diff options
author | Andreas Baumann <abaumann@yahoo.com> | 2009-04-01 15:48:39 +0200 |
---|---|---|
committer | Andreas Baumann <abaumann@yahoo.com> | 2009-04-01 15:48:39 +0200 |
commit | 8caf15e38c6c1a803c110028b0d8a10d6fece776 (patch) | |
tree | dcc3b99e2e716ce17172b94c2f7adc5ca3d522eb | |
parent | dde2d0138dd3d6d603b476f7e5f50aff2270251e (diff) | |
download | wolfbones-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-- | .gitignore | 1 | ||||
-rw-r--r-- | docs/port/README | 6 | ||||
-rw-r--r-- | include/wolf/port/gettext.h | 8 | ||||
-rw-r--r-- | include/wolf/port/netdb.h | 82 | ||||
-rw-r--r-- | include/wolf/port/stdio.h | 4 | ||||
-rw-r--r-- | include/wolf/port/stdlib.h | 2 | ||||
-rw-r--r-- | include/wolf/port/string.h | 16 | ||||
-rw-r--r-- | src/Makefile.W32 | 3 | ||||
-rwxr-xr-x | src/port/getaddrinfo.c | 225 | ||||
-rwxr-xr-x | src/port/getaddrinfo.h | 93 | ||||
-rw-r--r-- | src/port/netdb.c | 247 | ||||
-rw-r--r-- | tests/port/GNUmakefile | 5 | ||||
-rw-r--r-- | tests/port/Makefile.W32 | 6 | ||||
-rw-r--r-- | tests/port/test_gai_strerror_r.c | 28 |
14 files changed, 388 insertions, 338 deletions
@@ -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 ); +} |