/* * getaddrinfo.c * * Simple version of getaddrinfo() * */ #include "config.h" extern int errno; extern int h_errno; void freeaddrinfo(struct addrinfo *res) { if (!res) return; if (res->ai_next) freeaddrinfo(res->ai_next); if (res->ai_addr) free(res->ai_addr); if (res->ai_canonname) free(res->ai_canonname); free(res); } int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct hostent *host; struct sockaddr *sa; int err, size = 0; if ((!node) || (!res)) { errno = EINVAL; return EAI_SYSTEM; } *res = NULL; /* we do not support service in this version */ if (service) { errno = EINVAL; return EAI_SYSTEM; } host = gethostbyname(node); if (!host) return EAI_NONAME; if (hints) { if (hints->ai_family != AF_UNSPEC) { if (hints->ai_family != host->h_addrtype) return EAI_ADDRFAMILY; } } *res = malloc(sizeof(struct addrinfo)); if (!*res) { return EAI_MEMORY; } memset(*res, 0, sizeof(struct addrinfo)); (*res)->ai_family = host->h_addrtype; if (host->h_length) { if (host->h_addrtype == AF_INET) size = sizeof(struct sockaddr_in); #ifdef HAVE_IPV6 else if (host->h_addrtype == AF_INET6) size = sizeof(struct sockaddr_in6); #endif else { free(*res); *res = NULL; return EAI_ADDRFAMILY; } sa = malloc(size); if (!sa) { free(*res); *res = NULL; return EAI_MEMORY; } memset(sa, 0, size); (*res)->ai_addr = sa; (*res)->ai_addrlen = size; sa->sa_family = host->h_addrtype; if (host->h_addrtype == AF_INET) memcpy(&((struct sockaddr_in *)sa)->sin_addr, host->h_addr, host->h_length); #ifdef HAVE_IPV6 else memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, host->h_addr, host->h_length); #endif } if (host->h_name) (*res)->ai_canonname = strdup(host->h_name); /* we only handle the first address entry and do not build a list now */ return 0; } const char *gai_strerror(int errcode) { const char *s = NULL; switch(errcode) { case 0: s = "no error"; break; case EAI_MEMORY: s = "no memory"; break; case EAI_SYSTEM: s = strerror(errno); break; case EAI_NONAME: s = hstrerror(h_errno); break; case EAI_ADDRFAMILY: s = "address does not match address family"; break; default: s = "unknown error code"; break; } return s; }