blob: ef7c9ae114019203a6ba4004edb5d1ffebf1e81e [file] [log] [blame]
/*
* 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;
}