summaryrefslogtreecommitdiff
path: root/src/port/netdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/port/netdb.c')
-rw-r--r--src/port/netdb.c247
1 files changed, 246 insertions, 1 deletions
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 */