/* Get address information (partial implementation).
- Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006, 2007, 2008 Free Software
+ Foundation, Inc.
Contributed by Simon Josefsson <simon@josefsson.org>.
This program is free software; you can redistribute it and/or modify
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
-#include "getaddrinfo.h"
+#include <netdb.h>
#if HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
+/* Get inet_ntop. */
+#include <arpa/inet.h>
+
/* Get calloc. */
#include <stdlib.h>
-/* Get memcpy. */
+/* Get memcpy, strdup. */
#include <string.h>
+/* Get snprintf. */
+#include <stdio.h>
+
#include <stdbool.h>
#include "gettext.h"
#define _(String) gettext (String)
#define N_(String) String
-#include "strdup.h"
+/* BeOS has AF_INET, but not PF_INET. */
+#ifndef PF_INET
+# define PF_INET AF_INET
+#endif
+/* BeOS also lacks PF_UNSPEC. */
+#ifndef PF_UNSPEC
+# define PF_UNSPEC 0
+#endif
+
+#if defined _WIN32 || defined __WIN32__
+# define WIN32_NATIVE
+#endif
-#ifdef _WIN32
-typedef void WSAAPI (*freeaddrinfo_func) (struct addrinfo*);
-typedef int WSAAPI (*getaddrinfo_func) (const char*, const char*,
+#ifdef WIN32_NATIVE
+typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*,
const struct addrinfo*,
struct addrinfo**);
-typedef int WSAAPI (*getnameinfo_func) (const struct sockaddr*,
+typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*);
+typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*,
socklen_t, char*, DWORD,
char*, DWORD, int);
static freeaddrinfo_func freeaddrinfo_ptr = NULL;
static getnameinfo_func getnameinfo_ptr = NULL;
-int use_win32_p (void)
+static int
+use_win32_p (void)
{
static int done = 0;
HMODULE h;
if (h)
{
- getaddrinfo_ptr = GetProcAddress (h, "getaddrinfo");
- freeaddrinfo_ptr = GetProcAddress (h, "freeaddrinfo");
- getnameinfo_ptr = GetProcAddress (h, "getnameinfo");
+ getaddrinfo_ptr = (getaddrinfo_func) GetProcAddress (h, "getaddrinfo");
+ freeaddrinfo_ptr = (freeaddrinfo_func) GetProcAddress (h, "freeaddrinfo");
+ getnameinfo_ptr = (getnameinfo_func) GetProcAddress (h, "getnameinfo");
}
/* If either is missing, something is odd. */
};
#endif
-#ifdef _WIN32
+#ifdef WIN32_NATIVE
if (use_win32_p ())
return getaddrinfo_ptr (nodename, servname, hints, res);
#endif
- if (hints && (hints->ai_flags & ~AI_CANONNAME))
+ if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE)))
/* FIXME: Support more flags. */
return EAI_BADFLAGS;
return EAI_SOCKTYPE; /* FIXME: Better return code? */
if (!nodename)
- /* FIXME: Support server bind mode. */
- return EAI_NONAME;
+ {
+ if (!(hints->ai_flags & AI_PASSIVE))
+ return EAI_NONAME;
+
+#ifdef HAVE_IPV6
+ nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0";
+#else
+ nodename = "0.0.0.0";
+#endif
+ }
if (servname)
{
const char *proto =
(hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
- if (!(hints->ai_flags & AI_NUMERICSERV))
+ if (hints == NULL || !(hints->ai_flags & AI_NUMERICSERV))
/* FIXME: Use getservbyname_r if available. */
se = getservbyname (servname, proto);
if (!se)
{
char *c;
+ if (!(*servname >= '0' && *servname <= '9'))
+ return EAI_NONAME;
port = strtoul (servname, &c, 10);
- if (*c)
+ if (*c || port > 0xffff)
return EAI_NONAME;
port = htons (port);
}
tmp->ai_addr->sa_family = he->h_addrtype;
tmp->ai_family = he->h_addrtype;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ switch (he->h_addrtype)
+ {
+#if HAVE_IPV4
+ case AF_INET:
+ tmp->ai_addr->sa_len = sizeof (struct sockaddr_in);
+ break;
+#endif
+#if HAVE_IPV6
+ case AF_INET6:
+ tmp->ai_addr->sa_len = sizeof (struct sockaddr_in6);
+ break;
+#endif
+ }
+#endif
+
/* FIXME: If more than one address, create linked list of addrinfo's. */
*res = tmp;
void
freeaddrinfo (struct addrinfo *ai)
{
-#ifdef _WIN32
+#ifdef WIN32_NATIVE
if (use_win32_p ())
- return freeaddrinfo_ptr (ai);
+ {
+ freeaddrinfo_ptr (ai);
+ return;
+ }
#endif
while (ai)
cur = ai;
ai = ai->ai_next;
- if (cur->ai_canonname) free (cur->ai_canonname);
+ free (cur->ai_canonname);
free (cur);
}
}
char *restrict service, socklen_t servicelen,
int flags)
{
-#if _WIN32
+#ifdef WIN32_NATIVE
if (use_win32_p ())
return getnameinfo_ptr (sa, salen, node, nodelen,
service, servicelen, flags);
#if HAVE_IPV4
case AF_INET:
if (!inet_ntop (AF_INET,
- (const void *)
&(((const struct sockaddr_in *) sa)->sin_addr),
node, nodelen))
return EAI_SYSTEM;
#if HAVE_IPV6
case AF_INET6:
if (!inet_ntop (AF_INET6,
- (const void *)
&(((const struct sockaddr_in6 *) sa)->sin6_addr),
node, nodelen))
return EAI_SYSTEM;
#if HAVE_IPV6
case AF_INET6:
#endif
- if (snprintf (service, servicelen, "%d",
- ntohs (((const struct sockaddr_in *) sa)->sin_port))
- + 1 > servicelen)
- return EAI_OVERFLOW;
+ {
+ unsigned short int port
+ = ntohs (((const struct sockaddr_in *) sa)->sin_port);
+ if (servicelen <= snprintf (service, servicelen, "%u", port))
+ return EAI_OVERFLOW;
+ }
break;
}