summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <abaumann@yahoo.com>2009-03-29 16:46:46 +0200
committerAndreas Baumann <abaumann@yahoo.com>2009-03-29 16:46:46 +0200
commit0b6f512e8e37935481de1d11b90c739070cb2565 (patch)
treea7499b355003f3f6d081fe6d7cc1132bc0fe96f7
parentcb1119666a3a4273fa53743837b2e13f6730bc10 (diff)
downloadwolfbones-0b6f512e8e37935481de1d11b90c739070cb2565.tar.gz
wolfbones-0b6f512e8e37935481de1d11b90c739070cb2565.tar.bz2
added stub implementation of getaddrinfo on Cygwin
-rw-r--r--docs/port/README.networking6
-rw-r--r--include/wolf/port/netdb.h9
-rw-r--r--include/wolf/port/sys.h7
-rwxr-xr-xsrc/port/getaddrinfo.c165
-rwxr-xr-xsrc/port/getaddrinfo.h247
-rw-r--r--src/port/netdb.c3
-rw-r--r--tests/port/test_getaddrinfo.c4
7 files changed, 433 insertions, 8 deletions
diff --git a/docs/port/README.networking b/docs/port/README.networking
new file mode 100644
index 0000000..6532a58
--- /dev/null
+++ b/docs/port/README.networking
@@ -0,0 +1,6 @@
+- use POSIX getaddrinfo/getnameinfo as they provide a good top-level interface which
+ is quite portable (even on Windows)
+
+Good code examples:
+- UNPV12e of W. Richard Stevens (Unix Network Programming), the must-read
+- postgresql has a good getaddrinfo replacement for Windows and Cygwin
diff --git a/include/wolf/port/netdb.h b/include/wolf/port/netdb.h
index 15ed25b..1751c2d 100644
--- a/include/wolf/port/netdb.h
+++ b/include/wolf/port/netdb.h
@@ -78,12 +78,9 @@
#include <netdb.h> /* for getaddrinfo, freeadrinfo,
struct getaddrinfo */
-#if !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO
-extern void wolf_port_getaddrinfo( void );
-#endif /* !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO */
-#if !defined HAVE_GETADDRINFO
-#define getaddrinfo( hostname, service, hints, result ) wolf_port_getaddrinfo( hostname, service, hints, result )
-#endif /* !defined HAVE_GETADDRINFO */
+#ifdef CYGWIN
+#include "port/getaddrinfo.h" /* stub implementation on Cygwin */
+#endif
/** @} */ /* @addtogroup wolf_port */
diff --git a/include/wolf/port/sys.h b/include/wolf/port/sys.h
index a6b42be..fcb82c3 100644
--- a/include/wolf/port/sys.h
+++ b/include/wolf/port/sys.h
@@ -47,6 +47,7 @@
#define HAVE_SYSLOG_H
#define HAVE_GETADDRINFO
#define HAVE_INET_NTOP
+#define HAVE_IPV6
#else
#error unknown platform
#endif /* defined OS_MINOR_VERSION == 6 */
@@ -74,6 +75,7 @@
#define MUST_DEFINE_STRLCAT_PROTOTYPE
#define HAVE_GETADDRINFO
#define HAVE_INET_NTOP
+#define HAVE_IPV6
#else
#error unknown platform
#endif /* defined OS_MINOR_VERSION == 0 */
@@ -96,6 +98,7 @@
#define MUST_DEFINE_STRLCAT_PROTOTYPE
#define HAVE_GETADDRINFO
#define HAVE_INET_NTOP
+#define HAVE_IPV6
#else
#error unknown platform
#endif /* defined OS_MINOR_VERSION == 2 */
@@ -124,6 +127,7 @@
#define MUST_DEFINE_STRLCAT_PROTOTYPE
#define HAVE_GETADDRINFO
#define HAVE_INET_NTOP
+#define HAVE_IPV6
#else
#error unknown platform
#endif /* defined OS_MINOR_VERSION >= 2 && OS_MINOR_VERSION <= 3 */
@@ -155,6 +159,7 @@
#define MUST_DEFINE_STRLCAT_PROTOTYPE
#define HAVE_GETADDRINFO
#define HAVE_INET_NTOP
+#define HAVE_IPV6
#else
#error unknown platform
#endif /* defined OS_MINOR_VERSION == 2 */
@@ -185,6 +190,7 @@
#define HAVE_STRLCAT
#define HAVE_GETADDRINFO
#define HAVE_INET_NTOP
+#define HAVE_IPV6
#else
#if OS_MINOR_VERSION == 10
#if !defined __cplusplus
@@ -205,6 +211,7 @@
#define HAVE_STRLCAT
#define HAVE_GETADDRINFO
#define HAVE_INET_NTOP
+#define HAVE_IPV6
#else
#error unknown platform
#endif /* OS_MINOR_VERSION == 10 */
diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c
new file mode 100755
index 0000000..558cb9e
--- /dev/null
+++ b/src/port/getaddrinfo.c
@@ -0,0 +1,165 @@
+/*
+ Copyright (C) 2008 Andreas Baumann <abaumann@yahoo.com>
+
+ 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "port/getaddrinfo.h"
+
+#if !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO
+
+#include "port/string.h" /* for memset, memcpy */
+#include "port/stdlib.h" /* for atoi, malloc, free, NULL */
+
+#include <netinet/in.h> /* for struct sockaddr_in */
+
+int wolf_port_getaddrinfo( const char *host_name,
+ const char *service_name,
+ const struct wolf_port_addrinfo *hintp,
+ struct wolf_port_addrinfo **result ) {
+ struct wolf_port_addrinfo *ai;
+ struct sockaddr_in sin,
+ *psin;
+ struct wolf_port_addrinfo hints;
+
+ if( hintp == NULL ) {
+ memset( &hints, 0, sizeof( struct wolf_port_addrinfo ) );
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ } else {
+ memcpy( &hints, hintp, sizeof( struct wolf_port_addrinfo ) );
+ }
+
+ if( hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC ) {
+ return EAI_FAMILY;
+ }
+
+ if( hints.ai_socktype == 0 ) {
+ hints.ai_socktype = SOCK_STREAM;
+ }
+
+ if( ( host_name == NULL ) && ( service_name == NULL ) ) {
+ return EAI_NONAME;
+ }
+
+ memset( &sin, 0, sizeof( struct sockaddr_in) );
+
+ sin.sin_family = AF_INET;
+
+ if( host_name != NULL ) {
+ if( host_name[0] == '\0' ) {
+ sin.sin_addr.s_addr = htonl( INADDR_ANY );
+ } else if( hints.ai_flags & AI_NUMERICHOST ) {
+ if( !inet_aton( host_name, &sin.sin_addr ) ) {
+ return EAI_FAIL;
+ }
+ } else {
+ struct hostent *hp;
+
+ hp = gethostbyname( host_name );
+
+ if( hp == NULL ) {
+ switch( h_errno ) {
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ return EAI_NONAME;
+
+ case TRY_AGAIN:
+ return EAI_AGAIN;
+
+ case NO_RECOVERY:
+ default:
+ return EAI_FAIL;
+ }
+ }
+
+ if( hp->h_addrtype != AF_INET ) {
+ return EAI_FAIL;
+ }
+
+ memcpy( &(sin.sin_addr), hp->h_addr, hp->h_length );
+ }
+ } else {
+ if( hints.ai_flags & AI_PASSIVE ) {
+ sin.sin_addr.s_addr = htonl( INADDR_ANY );
+ } else {
+ sin.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
+ }
+ }
+
+ if( service_name != NULL ) {
+ sin.sin_port = htons( (unsigned short)atoi( service_name ) );
+ }
+
+ ai = (struct wolf_port_addrinfo *)malloc( sizeof( struct wolf_port_addrinfo ) );
+ if( ai == NULL ) {
+ return EAI_MEMORY;
+ }
+
+ psin = (struct sockaddr_in *)malloc( sizeof( struct sockaddr_in ) );
+ if (!psin)
+ {
+ free(ai);
+ return EAI_MEMORY;
+ }
+
+ memcpy( psin, &sin, sizeof( struct sockaddr_in ) );
+
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET;
+ ai->ai_socktype = hints.ai_socktype;
+ ai->ai_protocol = hints.ai_protocol;
+ ai->ai_addrlen = sizeof(*psin);
+ ai->ai_addr = (struct sockaddr *) psin;
+ ai->ai_canonname = NULL;
+ ai->ai_next = NULL;
+
+ *result = ai;
+
+ return 0;
+}
+
+void wolf_port_freeaddrinfo( struct wolf_port_addrinfo *result ) {
+ /* stub doesn't have more than one element in list, adapt if you change that! */
+ if( result != NULL ) {
+ if( result->ai_addr != NULL ) {
+ free( result->ai_addr );
+ }
+ free( result );
+ }
+}
+
+const char *wolf_port_gai_strerror( int errcode ) {
+ switch( errcode ) {
+ case EAI_NONAME:
+ return "host nor service provided, or not known";
+
+ case EAI_AGAIN:
+ return "temporary failure in name resolution";
+
+ case EAI_FAIL:
+ return "non-recoverable failure in name resultion";
+
+ case EAI_FAMILY:
+ return "socket family not supported";
+
+ case EAI_MEMORY:
+ return "memory allocation failure";
+
+ default:
+ return "Unknown GAI error";
+ }
+}
+
+#endif /* !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO */
diff --git a/src/port/getaddrinfo.h b/src/port/getaddrinfo.h
new file mode 100755
index 0000000..2177afa
--- /dev/null
+++ b/src/port/getaddrinfo.h
@@ -0,0 +1,247 @@
+/*
+ Copyright (C) 2008 Andreas Baumann <abaumann@yahoo.com>
+
+ 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Bases on ideas found in:
+ *
+ * Postgres src/port/getaddrinfo.c, Copyright (c) 2003-2008, PostgreSQL Global Development Group
+ * Unix Stevens Network Programming, libgai implementation in unpv12e
+ *
+ * At least Windows 2000 and Cygwin don't know getaddrinfo..
+ */
+
+#ifndef __GETADDRINFO_H
+#define __GETADDRINFO_H
+
+#include "port/sys_internal.h"
+
+/* for errors returned by getaddrinfo */
+#if !defined EAI_NONAME
+#define EAI_NONAME -2 /**< NAME or SERVICE is unknown */
+#define EAI_AGAIN -3 /**< temporary failure in name resolution */
+#define EAI_FAIL -4 /**< non-recoverable failure in name resultion */
+#define EAI_FAMILY -6 /**< socket family not supported */
+#define EAI_MEMORY -10 /**< memory allocation failure */
+#endif
+
+/* for ai_flags */
+#if !defined AI_PASSIVE
+#define AI_PASSIVE 1 /**< socket is intended for bind() + listen() */
+#define AI_CANONNAME 2 /**< return canonical name */
+#define AI_NUMERICHOST 4 /**< don't use name resolution */
+#endif
+
+#if !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO
+struct wolf_port_addrinfo
+{
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct wolf_port_addrinfo *ai_next;
+};
+
+extern int wolf_port_getaddrinfo( const char *host_name,
+ const char *service_name,
+ const struct wolf_port_addrinfo *hints,
+ struct wolf_port_addrinfo **result );
+
+extern void wolf_port_freeaddrinfo( struct wolf_port_addrinfo *result );
+extern const char *wolf_port_gai_strerror( int errcode );
+
+#if !defined HAVE_GETADDRINFO
+#define addrinfo wolf_port_addrinfo
+#define getaddrinfo( host_name, service_name, hints, result ) wolf_port_getaddrinfo( host_name, service_name, hints, result )
+#define freeaddrinfo( result ) wolf_port_freeaddrinfo( result )
+#define gai_strerror( errcode ) wolf_port_gai_strerror( errcode )
+#endif
+
+#endif /* !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO */
+
+#endif /* ifndef __GETADDRINFO_H */
+
+#if 0
+
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.h
+ * Support getaddrinfo() on platforms that don't have it.
+ *
+ * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO,
+ * whether or not the library routine getaddrinfo() can be found. This
+ * policy is needed because on some platforms a manually installed libbind.a
+ * may provide getaddrinfo(), yet the system headers may not provide the
+ * struct definitions needed to call it. To avoid conflict with the libbind
+ * definition in such cases, we rename our routines to pg_xxx() via macros.
+ *
+ * This code will also work on platforms where struct addrinfo is defined
+ * in the system headers but no getaddrinfo() can be located.
+ *
+ * Copyright (c) 2003-2008, PostgreSQL Global Development Group
+ *
+ * $PostgreSQL: pgsql/src/include/getaddrinfo.h,v 1.25 2008/01/01 19:45:56 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef GETADDRINFO_H
+#define GETADDRINFO_H
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+
+/* Various macros that ought to be in <netdb.h>, but might not be */
+
+#ifndef EAI_FAIL
+#ifndef WIN32
+#define EAI_BADFLAGS (-1)
+#define EAI_NONAME (-2)
+#define EAI_AGAIN (-3)
+#define EAI_FAIL (-4)
+#define EAI_FAMILY (-6)
+#define EAI_SOCKTYPE (-7)
+#define EAI_SERVICE (-8)
+#define EAI_MEMORY (-10)
+#define EAI_SYSTEM (-11)
+#else /* WIN32 */
+#ifdef WIN32_ONLY_COMPILER
+#ifndef WSA_NOT_ENOUGH_MEMORY
+#define WSA_NOT_ENOUGH_MEMORY (WSAENOBUFS)
+#endif
+#ifndef __BORLANDC__
+#define WSATYPE_NOT_FOUND (WSABASEERR+109)
+#endif
+#endif
+#define EAI_AGAIN WSATRY_AGAIN
+#define EAI_BADFLAGS WSAEINVAL
+#define EAI_FAIL WSANO_RECOVERY
+#define EAI_FAMILY WSAEAFNOSUPPORT
+#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY
+#define EAI_NODATA WSANO_DATA
+#define EAI_NONAME WSAHOST_NOT_FOUND
+#define EAI_SERVICE WSATYPE_NOT_FOUND
+#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT
+#endif /* !WIN32 */
+#endif /* !EAI_FAIL */
+
+#ifndef AI_PASSIVE
+#define AI_PASSIVE 0x0001
+#endif
+
+#ifndef AI_NUMERICHOST
+/*
+ * some platforms don't support AI_NUMERICHOST; define as zero if using
+ * the system version of getaddrinfo...
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_NUMERICHOST 0
+#else
+#define AI_NUMERICHOST 0x0004
+#endif
+#endif
+
+#ifndef NI_NUMERICHOST
+#define NI_NUMERICHOST 1
+#endif
+#ifndef NI_NUMERICSERV
+#define NI_NUMERICSERV 2
+#endif
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 32
+#endif
+
+
+#ifndef HAVE_STRUCT_ADDRINFO
+
+#ifndef WIN32
+struct addrinfo
+{
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct addrinfo *ai_next;
+};
+#else
+/*
+ * The order of the structure elements on Win32 doesn't match the
+ * order specified in the standard, but we have to match it for
+ * IPv6 to work.
+ */
+struct addrinfo
+{
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfo *ai_next;
+};
+#endif
+#endif /* HAVE_STRUCT_ADDRINFO */
+
+
+#ifndef HAVE_GETADDRINFO
+
+#if 0
+/* Rename private copies per comments above */
+#ifdef getaddrinfo
+#undef getaddrinfo
+#endif
+#define getaddrinfo pg_getaddrinfo
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
+#define freeaddrinfo pg_freeaddrinfo
+
+#ifdef gai_strerror
+#undef gai_strerror
+#endif
+#define gai_strerror pg_gai_strerror
+
+#ifdef getnameinfo
+#undef getnameinfo
+#endif
+#define getnameinfo pg_getnameinfo
+#endif
+
+
+extern int getaddrinfo(const char *node, const char *service,
+ const struct addrinfo * hints, struct addrinfo ** res);
+extern void freeaddrinfo(struct addrinfo * res);
+extern const char *gai_strerror(int errcode);
+extern int getnameinfo(const struct sockaddr * sa, int salen,
+ char *node, int nodelen,
+ char *service, int servicelen, int flags);
+#endif /* HAVE_GETADDRINFO */
+
+#endif /* GETADDRINFO_H */
+
+#endif
diff --git a/src/port/netdb.c b/src/port/netdb.c
index 3995c5a..1e5b2eb 100644
--- a/src/port/netdb.c
+++ b/src/port/netdb.c
@@ -19,7 +19,6 @@
#if !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO
-void wolf_port_getaddrinfo( void ) {
-}
+#include "port/getaddrinfo.c"
#endif /* !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO */
diff --git a/tests/port/test_getaddrinfo.c b/tests/port/test_getaddrinfo.c
index df2be22..b18d49d 100644
--- a/tests/port/test_getaddrinfo.c
+++ b/tests/port/test_getaddrinfo.c
@@ -34,7 +34,9 @@ int main( void ) {
for( res = result; res != NULL; res = res->ai_next ) {
char s[100];
const struct sockaddr_in *addr_ipv4;
+#ifdef HAVE_IPV6
const struct sockaddr_in6 *addr_ipv6;
+#endif
memset( s, 0, 100 );
switch( res->ai_family ) {
@@ -43,10 +45,12 @@ int main( void ) {
inet_ntop( res->ai_family, &addr_ipv4->sin_addr, s, 100 );
break;
+#ifdef HAVE_IPV6
case AF_INET6:
addr_ipv6 = (const struct sockaddr_in6 *)((void *)res->ai_addr);
inet_ntop( res->ai_family, &addr_ipv6->sin6_addr, s, 100 );
break;
+#endif
}
printf( "%d %d %s\n", res->ai_family, res->ai_socktype, s );