/*
$NiH: getaddrinfo.c,v 1.11 2002/09/16 12:42:35 dillo Exp $
getaddrinfo.c -- name-to-address translation in protocol-independent manner
Copyright (C) 2000-2002 Dieter Baron
This file is a replacement for the following library functions:
getaddrinfo, freeaddrinfo, gai_strerror.
The author can be contacted at <dillo@giga.or.at>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include "config.h"
#include "sockets.h"
#ifndef HAVE_DECL_H_ERRNO
extern int h_errno;
#endif
int
getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
struct addrinfo *ai, *airet, *aiprev;
struct hostent *hp;
struct sockaddr_in sa;
struct servent *serv;
u_short port;
char addr[4], *s_addr_list[2], **addr_list;
int addr_len;
int i;
/* XXX: check arguments */
/* XXX: get proto */
if (hints && hints->ai_family != PF_UNSPEC
&& hints->ai_family != PF_INET)
return EAI_FAMILY;
if ((serv = getservbyname(servname, "tcp")) == NULL) {
if ((port=atoi(servname))==0
&& (servname[0]!='0' || servname[1]!='\0')) {
return EAI_SERVICE;
}
port = htons(port);
}
else
port = (u_short)serv->s_port;
sa.sin_family = AF_INET;
sa.sin_port = port;
memset(sa.sin_zero, 0, 8);
addr_list = s_addr_list;
addr_list[0] = addr;
addr_list[1] = NULL;
addr_len = 4;
if (hints->ai_flags & AI_PASSIVE && nodename == NULL) {
sa.sin_addr.s_addr = INADDR_ANY;
memcpy(addr_list[0], &sa.sin_addr.s_addr, addr_len);
}
else if (inet_aton(nodename, &sa.sin_addr) == 1) {
memcpy(addr_list[0], &sa.sin_addr.s_addr, addr_len);
}
else {
if ((hp = gethostbyname(nodename)) == NULL) {
switch (h_errno) {
case TRY_AGAIN:
return EAI_AGAIN;
case HOST_NOT_FOUND:
case NO_DATA:
return EAI_NODATA;
case NO_RECOVERY:
default:
return EAI_FAIL;
}
}
addr_list = hp->h_addr_list;
addr_len = hp->h_length;
}
airet = aiprev = NULL;
for (i=0; addr_list[i]; i++) {
if ((ai=malloc(sizeof(struct addrinfo))) == NULL) {
freeaddrinfo(airet);
return EAI_MEMORY;
}
if (airet == NULL)
airet = ai;
if (aiprev)
aiprev->ai_next = ai;
aiprev = ai;
ai->ai_next = NULL;
ai->ai_family = AF_INET;
ai->ai_socktype = SOCK_STREAM; /* XXX: from hints */
ai->ai_protocol = IPPROTO_TCP; /* XXX: from hints */
memcpy(&sa.sin_addr, addr_list[i], addr_len);
if ((ai->ai_addr=malloc(sizeof(struct sockaddr_in))) == NULL) {
freeaddrinfo(airet);
return EAI_MEMORY;
}
memcpy(ai->ai_addr, &sa, sizeof(struct sockaddr_in));
ai->ai_addrlen = sizeof(struct sockaddr_in);
}
*res = airet;
return 0;
}
void
freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *ai2;
while (ai) {
ai2 = ai->ai_next;
free(ai->ai_addr);
free(ai);
ai = ai2;
}
}
char *
gai_strerror(int ecode)
{
static char *estr[] = {
"Success",
"Address family for hostname not supported",
"Temporary failure in name resolution",
"Invalid value for ai_flags",
"Non-recoverable failure in name resolution",
"ai_family not supported",
"Memory allocation failure",
"No address associated with hostname",
"hostname nor servname provided, or not known",
"servname not supported for ai_socktype",
"ai_socktype not supported",
"System error returned in errno"
};
static const int nestr = sizeof(estr)/sizeof(estr[0]);
return (int)ecode < nestr ? estr[ecode] : "Unknown error";
}
syntax highlighted by Code2HTML, v. 0.9.1