From 697d52b88a6d8e03ec8c996d2161a4928d0e0fb6 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 18 Jan 2016 14:42:02 +0100 Subject: [PATCH] Add basic getaddrinfo(3) support for localhost ports. --- libc/netdb/freeaddrinfo.cpp | 16 ++++--- libc/netdb/getaddrinfo.cpp | 93 ++++++++++++++++++++++++++++++++++--- 2 files changed, 97 insertions(+), 12 deletions(-) diff --git a/libc/netdb/freeaddrinfo.cpp b/libc/netdb/freeaddrinfo.cpp index 02ef72cb..fca2ab3a 100644 --- a/libc/netdb/freeaddrinfo.cpp +++ b/libc/netdb/freeaddrinfo.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2013. + Copyright(C) Jonas 'Sortie' Termansen 2013, 2016. This file is part of the Sortix C Library. @@ -23,12 +23,16 @@ *******************************************************************************/ #include - -#include #include -extern "C" void freeaddrinfo(struct addrinfo*) +extern "C" void freeaddrinfo(struct addrinfo* ai) { - fprintf(stderr, "%s is not implemented, aborting.\n", __func__); - abort(); + while ( ai ) + { + struct addrinfo* todelete = ai; + ai = ai->ai_next; + free(todelete->ai_addr); + free(todelete->ai_canonname); + free(todelete); + } } diff --git a/libc/netdb/getaddrinfo.cpp b/libc/netdb/getaddrinfo.cpp index 94b699fa..7c0f373d 100644 --- a/libc/netdb/getaddrinfo.cpp +++ b/libc/netdb/getaddrinfo.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2013, 2015. + Copyright(C) Jonas 'Sortie' Termansen 2013, 2015, 2016. This file is part of the Sortix C Library. @@ -22,14 +22,95 @@ *******************************************************************************/ +#include + +#include #include - -#include +#include #include +#include -extern "C" int getaddrinfo(const char* restrict, const char* restrict, - const struct addrinfo* restrict, - struct addrinfo** restrict) +static bool linkaddrinfo(struct addrinfo** restrict* res_ptr, + const struct addrinfo* restrict templ) { + struct addrinfo* link = (struct addrinfo*) calloc(1, sizeof(struct addrinfo)); + if ( !link ) + return false; + link->ai_flags = templ->ai_flags; + link->ai_family = templ->ai_family; + link->ai_socktype = templ->ai_socktype; + link->ai_protocol = templ->ai_protocol; + link->ai_addrlen = templ->ai_addrlen; + link->ai_addr = (struct sockaddr*) malloc(templ->ai_addrlen); + if ( !link->ai_addr ) + return free(link), false; + memcpy(link->ai_addr, templ->ai_addr, templ->ai_addrlen); + link->ai_canonname = templ->ai_canonname ? strdup(templ->ai_canonname) : NULL; + if ( templ->ai_canonname && !link->ai_canonname ) + return free(link), free(link->ai_addr), false; + **res_ptr = link; + *res_ptr = &link->ai_next; + return true; +} + +extern "C" int getaddrinfo(const char* restrict node, + const char* restrict servname, + const struct addrinfo* restrict hints, + struct addrinfo** restrict res) +{ + struct addrinfo hints_def; + if ( !hints ) + { + memset(&hints_def, 0, sizeof(hints_def)); + hints_def.ai_family = AF_UNSPEC; + hints = &hints_def; + } + + int socktype = hints->ai_socktype; + if ( socktype == 0 ) + socktype = SOCK_STREAM; + + in_port_t port = 0; + if ( servname ) + { + if ( isspace((unsigned char) servname[0]) ) + return EAI_SERVICE; + const char* end; + long portl = strtol(servname, (char**) &end, 10); + if ( end[0] ) + return EAI_SERVICE; + if ( (in_port_t) portl != portl ) + return EAI_SERVICE; + port = portl; + } + + struct addrinfo** res_orig = res; + *res = NULL; + + if ( !node ) + { + bool any = false; + if ( hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET ) + { + any = true; + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + memcpy(&sin.sin_addr, "\x7F\x00\x00\x01", 4); + struct addrinfo templ; + memset(&templ, 0, sizeof(templ)); + templ.ai_family = sin.sin_family; + templ.ai_socktype = socktype; + templ.ai_protocol = hints->ai_protocol; + templ.ai_addrlen = sizeof(sin); + templ.ai_addr = (struct sockaddr*) &sin; + if ( !linkaddrinfo(&res, &templ) ) + return freeaddrinfo(*res_orig), EAI_MEMORY; + } + if ( any ) + return 0; + } + return EAI_NONAME; }