summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <abaumann@yahoo.com>2009-04-01 15:48:39 +0200
committerAndreas Baumann <abaumann@yahoo.com>2009-04-01 15:48:39 +0200
commit8caf15e38c6c1a803c110028b0d8a10d6fece776 (patch)
treedcc3b99e2e716ce17172b94c2f7adc5ca3d522eb
parentdde2d0138dd3d6d603b476f7e5f50aff2270251e (diff)
downloadwolfbones-8caf15e38c6c1a803c110028b0d8a10d6fece776.tar.gz
wolfbones-8caf15e38c6c1a803c110028b0d8a10d6fece776.tar.bz2
removed extern in function prototypes; added gai_strerror_r and a test, cleanup in netdb.h and netdb.c
-rw-r--r--.gitignore1
-rw-r--r--docs/port/README6
-rw-r--r--include/wolf/port/gettext.h8
-rw-r--r--include/wolf/port/netdb.h82
-rw-r--r--include/wolf/port/stdio.h4
-rw-r--r--include/wolf/port/stdlib.h2
-rw-r--r--include/wolf/port/string.h16
-rw-r--r--src/Makefile.W323
-rwxr-xr-xsrc/port/getaddrinfo.c225
-rwxr-xr-xsrc/port/getaddrinfo.h93
-rw-r--r--src/port/netdb.c247
-rw-r--r--tests/port/GNUmakefile5
-rw-r--r--tests/port/Makefile.W326
-rw-r--r--tests/port/test_gai_strerror_r.c28
14 files changed, 388 insertions, 338 deletions
diff --git a/.gitignore b/.gitignore
index d94d9fc..3c06b44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@ tests/port/test_strlcat
tests/port/test_strlcpy
tests/gettext/test_gettext
tests/port/test_getaddrinfo
+tests/port/test_gai_strerror_r
tests/threads/test_create_join
tests/threads/test_counter_mutex
*.exe
diff --git a/docs/port/README b/docs/port/README
index aa96234..324cfe5 100644
--- a/docs/port/README
+++ b/docs/port/README
@@ -49,6 +49,10 @@ Currently there are the following definitions which must be set:
stub
- HAVE_ITOA: handy function, we define it as on Windows (as the char*
return value is more handy than void)
+- HAVE_GETADDRINFO: if we have the GAI library functions getaddrinfo,
+ freeaddrinfo and the counterpart getnameinfo, as well as the error
+ message function gai_strerror
+- HAVE_GAI_STRERROR_R: if we have a thread-safe version of gai_strerror
Defines in 'port/sys_internal.h'
--------------------------------
@@ -73,7 +77,7 @@ How to use the porting layer in your code
-----------------------------------------
Don't include system header files if there is a similar file in the
-'ports' subdir:
+'port' subdir:
#include "port/limits.h"
#include "port/stdbool.h"
diff --git a/include/wolf/port/gettext.h b/include/wolf/port/gettext.h
index 3d45d7e..3d4a4f9 100644
--- a/include/wolf/port/gettext.h
+++ b/include/wolf/port/gettext.h
@@ -48,10 +48,10 @@
*/
#if defined __GNUC__
#if defined GETTEXT_NEEDS_FORMAT_ARG
-extern char *gettext( const char *__msgid ) __attribute__ ( ( format_arg ( 1 ) ) );
-extern char *libintl_gettext( const char *__msgid ) __attribute__ ( ( format_arg ( 1 ) ) );
-extern char *dgettext( const char *__domainname, const char *__msgid ) __attribute__ ( ( format_arg ( 2 ) ) );
-extern char *libintl_dgettext( const char *__domainname, const char *__msgid ) __attribute__ ( ( format_arg ( 2 ) ) );
+char *gettext( const char *__msgid ) __attribute__ ( ( format_arg ( 1 ) ) );
+char *libintl_gettext( const char *__msgid ) __attribute__ ( ( format_arg ( 1 ) ) );
+char *dgettext( const char *__domainname, const char *__msgid ) __attribute__ ( ( format_arg ( 2 ) ) );
+char *libintl_dgettext( const char *__domainname, const char *__msgid ) __attribute__ ( ( format_arg ( 2 ) ) );
#endif
#endif
diff --git a/include/wolf/port/netdb.h b/include/wolf/port/netdb.h
index 99abf73..28aa679 100644
--- a/include/wolf/port/netdb.h
+++ b/include/wolf/port/netdb.h
@@ -29,6 +29,14 @@
* @author Andreas Baumann <abaumann@yahoo.com>
*/
+/*
+ * Based 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
+ */
+
#include "port/sys.h"
#ifdef FREEBSD
@@ -84,6 +92,80 @@
#define NI_MAXSERV 32
#endif
+#if !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO
+
+#include <sys/types.h> /* for size_t */
+#include <sys/socket.h> /* for AF_UNSPEC */
+#include <arpa/inet.h> /* for TCPPROTO and others */
+
+/* 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
+
+/* for flags in getnameinfo */
+#if !defined NI_NUMERICHOST
+#define NI_NUMERICHOST 1 /**< don't try to look up hostname. */
+#define NI_NUMERICSERV 2 /**< don't convert port number to name. */
+#endif
+
+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;
+};
+
+int wolf_port_getaddrinfo( const char *host_name,
+ const char *service_name,
+ const struct wolf_port_addrinfo *hints,
+ struct wolf_port_addrinfo **result );
+void wolf_port_freeaddrinfo( struct wolf_port_addrinfo *result );
+
+int wolf_port_getnameinfo( const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags );
+
+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 getnameinfo( sa, salen, host, hostlen, serv, servlen, flags ) wolf_port_getnameinfo( sa, salen, host, hostlen, serv, servlen, flags )
+#define gai_strerror( errcode ) wolf_port_gai_strerror( errcode )
+#endif
+
+#endif /* !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO */
+
+/* gai_strerror is not thread-safe. Some platforms (like AIX 6.1) started to
+ * introduce a thread-safe version gai_strerror_r
+ */
+#if !defined HAVE_GAI_STRERROR_R || defined TEST_GAI_STRERROR_R
+int wolf_port_gai_strerror_r( int errcode, char *buf, size_t buflen );
+#if !defined HAVE_GAI_STRERROR_R
+#define gai_strerror_r( errcode, buf, buflen ) wolf_port_gai_strerror_r( errcode, buf, buflen )
+#endif /* !defined HAVE_GAI_STRERROR_R */
+
+#endif /* !defined HAVE_GAI_STRERROR_R || defined TEST_GAI_STRERROR_R */
+
/** @} */ /* @addtogroup wolf_port */
#endif /* ifndef WOLF_NETDB_H */
diff --git a/include/wolf/port/stdio.h b/include/wolf/port/stdio.h
index d195f6d..1a2fc75 100644
--- a/include/wolf/port/stdio.h
+++ b/include/wolf/port/stdio.h
@@ -62,7 +62,7 @@
#include <sys/types.h> /* for size_t */
#if !defined HAVE_SNPRINTF || defined WOLF_TEST_SNPRINTF
-extern int rpl_snprintf( char *str, size_t size, const char *format, ... );
+int rpl_snprintf( char *str, size_t size, const char *format, ... );
#endif /* !defined HAVE_SNPRINTF || defined TEST_SNPRINTF */
#if !defined HAVE_SNPRINTF
/* TODO: with variadic macros, we can define a much better macro here! */
@@ -70,7 +70,7 @@ extern int rpl_snprintf( char *str, size_t size, const char *format, ... );
#endif /* !defined HAVE_SNPRINTF */
#if !defined HAVE_VSNPRINTF || defined WOLF_TEST_VSNPRINTF
-extern int rpl_vsnprintf( char *str, size_t size, const char *format, va_list args );
+int rpl_vsnprintf( char *str, size_t size, const char *format, va_list args );
#endif /* !defined HAVE_VSNPRINTF || defined TEST_VSNPRINTF */
#if !defined HAVE_VSNPRINTF
#define vsnprintf( str, size, format, ap ) rpl_vsnprintf( str, size, format, ap )
diff --git a/include/wolf/port/stdlib.h b/include/wolf/port/stdlib.h
index 37e1931..c8afeb8 100644
--- a/include/wolf/port/stdlib.h
+++ b/include/wolf/port/stdlib.h
@@ -34,7 +34,7 @@
#include <stdlib.h>
#if !defined HAVE_ITOA || defined TEST_ITOA
-extern char *wolf_port_itoa( int value, char *string, int radix );
+char *wolf_port_itoa( int value, char *string, int radix );
#endif /* !defined HAVE_ITOA || defined TEST_ITOA */
#if !defined HAVE_ITOA
#define itoa( value, string, radix ) wolf_port_itoa( value, string, radix )
diff --git a/include/wolf/port/string.h b/include/wolf/port/string.h
index 7875701..0f17083 100644
--- a/include/wolf/port/string.h
+++ b/include/wolf/port/string.h
@@ -46,52 +46,52 @@
#endif
#if !defined HAVE_STRDUP || defined TEST_STRDUP
-extern char *wolf_port_strdup( const char *s );
+char *wolf_port_strdup( const char *s );
#endif
#if !defined HAVE_STRDUP
#define strdup wolf_port_strdup
#endif
#if !defined HAVE_STRERROR_R || defined TEST_STRERROR_R
-extern int wolf_port_strerror_r( int num, char *buf, size_t buflen );
+int wolf_port_strerror_r( int num, char *buf, size_t buflen );
#endif
#if !defined HAVE_STRERROR_R
#define strerror_r( errnum, buf, buflen ) wolf_port_strerror_r( errnum, buf, buflen )
#endif
#if !defined HAVE_STRCASECMP || defined TEST_STRCASECMP
-extern int wolf_port_strcasecmp( const char *s1, const char *s2 );
+int wolf_port_strcasecmp( const char *s1, const char *s2 );
#endif
#if !defined HAVE_STRCASECMP
#define strcasecmp( s1, s2 ) wolf_port_strcasecmp( s1, s2 )
#endif
#if !defined HAVE_STRNCASECMP || defined TEST_STRNCASECMP
-extern int wolf_port_strncasecmp( const char *s1, const char *s2, size_t n );
+int wolf_port_strncasecmp( const char *s1, const char *s2, size_t n );
#endif
#if !defined HAVE_STRNCASECMP
#define strncasecmp( s1, s2, n ) wolf_port_strncasecmp( s1, s2, n )
#endif
#if !defined HAVE_STRLCPY || defined TEST_STRLCPY
-extern size_t wolf_port_strlcpy( char *d, const char *s, size_t bufsize );
+size_t wolf_port_strlcpy( char *d, const char *s, size_t bufsize );
#endif
#if !defined HAVE_STRLCPY
#define strlcpy( d, s, bufsize ) wolf_port_strlcpy( d, s, bufsize )
#else
#if defined MUST_DEFINE_STRLCPY_PROTOTYPE
-extern size_t strlcpy( char *d, const char *s, size_t bufsize );
+size_t strlcpy( char *d, const char *s, size_t bufsize );
#endif
#endif
#if !defined HAVE_STRLCAT || defined TEST_STRLCAT
-extern size_t wolf_port_strlcat( char *d, const char *s, size_t bufsize );
+size_t wolf_port_strlcat( char *d, const char *s, size_t bufsize );
#endif
#if !defined HAVE_STRLCAT
#define strlcat( d, s, bufsize ) wolf_port_strlcat( d, s, bufsize )
#else
#if defined MUST_DEFINE_STRLCAT_PROTOTYPE
-extern size_t strlcat( char *d, const char *s, size_t bufsize );
+size_t strlcat( char *d, const char *s, size_t bufsize );
#endif
#endif
diff --git a/src/Makefile.W32 b/src/Makefile.W32
index b321eeb..d0f7a99 100644
--- a/src/Makefile.W32
+++ b/src/Makefile.W32
@@ -20,7 +20,8 @@ PORT_OBJS = \
port\string.obj \
port\stdio.obj \
port\stdlib.obj \
- port\time.obj
+ port\time.obj \
+ port\netdb.obj
LOG_OBJS = \
log\log.obj
diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c
deleted file mode 100755
index 8f9db2a..0000000
--- a/src/port/getaddrinfo.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- 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, itoa, malloc, free, NULL */
-#include "port/unused.h"
-
-#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 );
- }
-}
-
-/*
- * Convert an ipv4 address to a hostname.
- *
- * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
- * It will never resolv a hostname.
- * - No IPv6 support.
- */
-extern int getnameinfo( const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen,
- int flags ) {
- WOLF_UNUSED( salen );
-
- /* Invalid arguments. */
- if( sa == NULL || ( host == NULL && serv == NULL ) ) {
- return EAI_FAIL;
- }
-
- /* We don't support those. */
- if( ( host && !( flags & NI_NUMERICHOST ) )
- || ( serv && !( flags & NI_NUMERICSERV ) ) ) {
- return EAI_FAIL;
- }
-
-#ifdef HAVE_IPV6
- /* no IPV6 here */
- if( sa->sa_family == AF_INET6 ) {
- return EAI_FAMILY;
- }
-#endif
-
- if( host != NULL ) {
- if( sa->sa_family == AF_INET ) {
- char *p;
-
- /* maximal size of an IP4 addres 255.255.255.255.255 */
- if( hostlen < 16 ) {
- return EAI_MEMORY;
- }
-
- p = inet_ntoa( ( (const struct sockaddr_in * ) sa)->sin_addr );
-
- strlcpy( host, p, hostlen );
- }
- }
-
- if( serv != NULL ) {
- if (sa->sa_family == AF_INET ) {
- /* maximal number of digits in an unsigned short */
- if( servlen < 10 ) {
- return EAI_MEMORY;
- }
- (void)itoa( ntohs( ( (const struct sockaddr_in * )sa)->sin_port ), serv, servlen );
- }
- }
-
- return 0;
-}
-
-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
deleted file mode 100755
index 746ac47..0000000
--- a/src/port/getaddrinfo.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- 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
- */
-
-#ifndef __GETADDRINFO_H
-#define __GETADDRINFO_H
-
-#include "port/sys_internal.h"
-
-#if !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO
-
-#include <sys/types.h> /* for size_t */
-#include <sys/socket.h> /* for AF_UNSPEC */
-#include <arpa/inet.h> /* for TCPPROTO and others */
-
-/* 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
-
-/* for flags in getnameinfo */
-#if !defined NI_NUMERICHOST
-#define NI_NUMERICHOST 1 /**< don't try to look up hostname. */
-#define NI_NUMERICSERV 2 /**< don't convert port number to name. */
-#endif
-
-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 int wolf_port_getnameinfo( const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen,
- int flags );
-
-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 getnameinfo( sa, salen, host, hostlen, serv, servlen, flags ) wolf_port_getnameinfo( sa, salen, host, hostlen, serv, servlen, flags )
-#define gai_strerror( errcode ) wolf_port_gai_strerror( errcode )
-#endif
-
-#endif /* !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO */
-
-#endif /* ifndef __GETADDRINFO_H */
diff --git a/src/port/netdb.c b/src/port/netdb.c
index 916b908..a61acd2 100644
--- a/src/port/netdb.c
+++ b/src/port/netdb.c
@@ -18,5 +18,250 @@
#include "port/netdb.h"
#if !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO
-#include "port/getaddrinfo.c"
+
+#include "port/string.h" /* for memset, memcpy */
+#include "port/stdlib.h" /* for atoi, itoa, malloc, free, NULL */
+#include "port/stdio.h" /* for snprintf */
+#include "port/unused.h"
+
+#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 );
+ }
+}
+
+/*
+ * Convert an ipv4 address to a hostname.
+ *
+ * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
+ * It will never resolv a hostname.
+ * - No IPv6 support.
+ */
+extern int getnameinfo( const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags ) {
+ WOLF_UNUSED( salen );
+
+ /* Invalid arguments. */
+ if( sa == NULL || ( host == NULL && serv == NULL ) ) {
+ return EAI_FAIL;
+ }
+
+ /* We don't support those. */
+ if( ( host && !( flags & NI_NUMERICHOST ) )
+ || ( serv && !( flags & NI_NUMERICSERV ) ) ) {
+ return EAI_FAIL;
+ }
+
+#ifdef HAVE_IPV6
+ /* no IPV6 here */
+ if( sa->sa_family == AF_INET6 ) {
+ return EAI_FAMILY;
+ }
+#endif
+
+ if( host != NULL ) {
+ if( sa->sa_family == AF_INET ) {
+ char *p;
+
+ /* maximal size of an IP4 addres 255.255.255.255.255 */
+ if( hostlen < 16 ) {
+ return EAI_MEMORY;
+ }
+
+ p = inet_ntoa( ( (const struct sockaddr_in * ) sa)->sin_addr );
+
+ strlcpy( host, p, hostlen );
+ }
+ }
+
+ if( serv != NULL ) {
+ if (sa->sa_family == AF_INET ) {
+ /* maximal number of digits in an unsigned short */
+ if( servlen < 10 ) {
+ return EAI_MEMORY;
+ }
+ (void)itoa( ntohs( ( (const struct sockaddr_in * )sa)->sin_port ), serv, servlen );
+ }
+ }
+
+ return 0;
+}
+
+const char *wolf_port_gai_strerror( int errcode ) {
+ static char buf[256];
+
+ 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:
+ snprintf( buf, 256, "Unknown GAI error %d", errcode );
+ return buf;
+ }
+}
+
#endif /* !defined HAVE_GETADDRINFO || defined TEST_GETADDRINFO */
+
+#if !defined HAVE_GAI_STRERROR_R || defined TEST_GAI_STRERROR_R
+
+#include "threads/mutex.h" /* for mutexes */
+#include "port/stdio.h" /* for snprintf */
+#include "port/stdbool.h" /* for bool */
+#include "port/string.h" /* for strncmp */
+#include <errno.h> /* for errno */
+
+static bool mutex_initialized = false;
+static wolf_mutex_t mutex;
+
+int wolf_port_gai_strerror_r( int errcode, char *buf, size_t buflen ) {
+ int safe_errno = errno;
+ const char *msg;
+
+ /* critical section as gai_strerror is not thread-safe */
+ if( !mutex_initialized ) {
+ wolf_mutex_init( &mutex );
+ mutex_initialized = true;
+ }
+ wolf_mutex_lock( &mutex );
+
+ msg = gai_strerror( errcode );
+ if( strncmp( msg, "Unknown GAI errror", strlen( "Unknown GAI error" ) ) == 0 /* our own stub implementation */ ) {
+ (void)snprintf( buf, buflen, "Unknown GAI error %d", errcode );
+ errno = EINVAL;
+ wolf_mutex_unlock( &mutex );
+ return -1;
+ }
+
+ strncpy( buf, msg, buflen-1 );
+ errno = safe_errno;
+ wolf_mutex_unlock( &mutex );
+ return 0;
+}
+
+#endif /* !defined HAVE_GAI_STRERROR_R || defined TEST_GAI_STRERROR_R */
diff --git a/tests/port/GNUmakefile b/tests/port/GNUmakefile
index ea6794c..64e3fe6 100644
--- a/tests/port/GNUmakefile
+++ b/tests/port/GNUmakefile
@@ -16,7 +16,8 @@ TEST_BINS = \
test_strlcpy$(EXE) \
test_strlcat$(EXE) \
test_itoa$(EXE) \
- test_getaddrinfo$(EXE)
+ test_getaddrinfo$(EXE) \
+ test_gai_strerror_r$(EXE)
-include $(TOPDIR)/makefiles/gmake/sub.mk
@@ -54,3 +55,5 @@ local_test:
@./test_itoa > /dev/null
@echo "Testing getaddrinfo.."
@./test_getaddrinfo > /dev/null
+ @echo "Testing gai_strerror_r.."
+ @./test_gai_strerror_r > /dev/null
diff --git a/tests/port/Makefile.W32 b/tests/port/Makefile.W32
index 5cf4e7a..22203ad 100644
--- a/tests/port/Makefile.W32
+++ b/tests/port/Makefile.W32
@@ -21,7 +21,8 @@ TEST_BINS = \
test_strlcpy.exe \
test_strlcat.exe \
test_itoa.exe \
- test_getaddrinfo.exe
+ test_getaddrinfo.exe \
+ test_gai_strerror_r.exe
!INCLUDE $(TOPDIR)\makefiles\nmake\sub.mk
@@ -36,6 +37,7 @@ test_strlcpy.exe: test_strlcpy.obj
test_strlcat.exe: test_strlcat.obj
test_itoa.exe: test_itoa.obj
test_getaddrinfo.exe: test_getaddrinfo.obj
+test_gai_strerror_r.exe: test_gai_strerror_r.obj
local_all:
@@ -64,3 +66,5 @@ local_test:
@test_itoa >NUL 2>NUL
@echo Testing getaddrinfo..
@test_getaddrinfo >NUL 2>NUL
+ @echo Testing gai_strerror_r..
+ @test_gai_strerror_r >NUL 2>NUL
diff --git a/tests/port/test_gai_strerror_r.c b/tests/port/test_gai_strerror_r.c
new file mode 100644
index 0000000..eb4c249
--- /dev/null
+++ b/tests/port/test_gai_strerror_r.c
@@ -0,0 +1,28 @@
+#include "port/sys.h"
+
+#define TEST_GAI_STRERROR_R
+#include "port/netdb.c" /* for gai_strerror_r */
+
+#include <stdlib.h> /* for exit, EXIT_SUCCESS, free */
+#include <stdio.h> /* for printf */
+
+int main( void ) {
+ signed int i;
+ int res;
+ char buf[1024];
+
+ /* go through gai errors (TODO: find out how many of them there are!) */
+ for( i = -1; i >= -255; i-- ) {
+ *buf = '\0';
+ res = gai_strerror_r( i, buf, 1024 );
+ printf( "%d: %d \"%s\"\n", i, res, buf );
+ }
+
+ /* go through gai errors (TODO: find out how many of them there are!) */
+ for( i = -1; i >= -255; i-- ) {
+ *buf = '\0';
+ res = wolf_port_gai_strerror_r( i, buf, 1024 );
+ printf( "%d: %d \"%s\"\n", i, res, buf );
+ }
+ exit( EXIT_SUCCESS );
+}