X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fnetwork%2Fgetaddrinfo.c;h=70183d6b141cf80349c8018d354959dfcce9c3be;hb=b6bf43814fd1b6a170ade03ea06b21528b7be893;hp=db1cfc271eeb5e2cf86c4111bb25afc7c7752748;hpb=507cd4520d39166027f67e9cdb1fe75a25010b4a;p=vlc diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c index db1cfc271e..70183d6b14 100644 --- a/src/network/getaddrinfo.c +++ b/src/network/getaddrinfo.c @@ -2,7 +2,7 @@ * getaddrinfo.c: getaddrinfo/getnameinfo replacement functions ***************************************************************************** * Copyright (C) 2005 the VideoLAN team - * Copyright (C) 2002-2004 Rémi Denis-Courmont + * Copyright (C) 2002-2007 Rémi Denis-Courmont * $Id$ * * Author: Rémi Denis-Courmont @@ -42,7 +42,7 @@ # include #endif -#include "network.h" +#include #ifndef NO_ADDRESS # define NO_ADDRESS NO_DATA @@ -77,6 +77,7 @@ static struct { EAI_SERVICE, "Incompatible service for socket type" }, { EAI_ADDRFAMILY, "Unavailable address family for host name" }, { EAI_MEMORY, "Memory allocation failure" }, + { EAI_OVERFLOW, "Buffer overflow" }, { EAI_SYSTEM, "System error" }, { 0, NULL } }; @@ -86,53 +87,21 @@ static const char *__gai_unknownerr = "Unrecognized error number"; /**************************************************************************** * Converts an EAI_* error code into human readable english text. ****************************************************************************/ -const char *vlc_gai_strerror( int errnum ) +const char *vlc_gai_strerror (int errnum) { - int i; - - for (i = 0; __gai_errlist[i].msg != NULL; i++) + for (unsigned i = 0; __gai_errlist[i].msg != NULL; i++) if (errnum == __gai_errlist[i].code) return __gai_errlist[i].msg; return __gai_unknownerr; } -# undef _EAI_POSITIVE_MAX #else /* ifndef HAVE_GAI_STRERROR */ -const char *vlc_gai_strerror( int errnum ) +const char *vlc_gai_strerror (int errnum) { - return gai_strerror( errnum ); + return gai_strerror (errnum); } #endif -#if !(defined (HAVE_GETNAMEINFO) && defined (HAVE_GETADDRINFO)) -/* - * Converts the current herrno error value into an EAI_* error code. - * That error code is normally returned by getnameinfo() or getaddrinfo(). - */ -static int -gai_error_from_herrno( void ) -{ - switch(h_errno) - { - case HOST_NOT_FOUND: - return EAI_NONAME; - - case NO_ADDRESS: -# if (NO_ADDRESS != NO_DATA) - case NO_DATA: -# endif - return EAI_NODATA; - - case NO_RECOVERY: - return EAI_FAIL; - - case TRY_AGAIN: - return EAI_AGAIN; - } - return EAI_SYSTEM; -} -#endif /* if !(HAVE_GETNAMEINFO && HAVE_GETADDRINFO) */ - #ifndef HAVE_GETNAMEINFO /* * getnameinfo() non-thread-safe IPv4-only implementation, @@ -147,10 +116,10 @@ gai_error_from_herrno( void ) * getaddrinfo(). */ static int -__getnameinfo( const struct sockaddr *sa, socklen_t salen, - char *host, int hostlen, char *serv, int servlen, int flags ) +getnameinfo (const struct sockaddr *sa, socklen_t salen, + char *host, int hostlen, char *serv, int servlen, int flags) { - if (((unsigned)salen < sizeof (struct sockaddr_in)) + if (((size_t)salen < sizeof (struct sockaddr_in)) || (sa->sa_family != AF_INET)) return EAI_FAMILY; else if (flags & (~_NI_MASK)) @@ -163,72 +132,27 @@ __getnameinfo( const struct sockaddr *sa, socklen_t salen, if (host != NULL) { - int solved = 0; - /* host name resolution */ if (!(flags & NI_NUMERICHOST)) { - struct hostent *hent; - - hent = gethostbyaddr ((const void*)&addr->sin_addr, - 4, AF_INET); - - if (hent != NULL) - { - strlcpy (host, hent->h_name, hostlen); - - /* - * only keep first part of hostname - * if user don't want fully qualified - * domain name - */ - if (flags & NI_NOFQDN) - { - char *ptr; - - ptr = strchr (host, '.'); - if (ptr != NULL) - *ptr = 0; - } - - solved = 1; - } - else if (flags & NI_NAMEREQD) - return gai_error_from_herrno (); + if (flags & NI_NAMEREQD) + return EAI_NONAME; } - if (!solved) - /* inet_ntoa() can't fail */ - strlcpy (host, inet_ntoa (addr->sin_addr), hostlen); + /* inet_ntoa() is not thread-safe, do not use it */ + uint32_t ipv4 = ntohl (addr->sin_addr.s_addr); + + if (snprintf (host, hostlen, "%u.%u.%u.%u", ipv4 >> 24, + (ipv4 >> 16) & 0xff, (ipv4 >> 8) & 0xff, + ipv4 & 0xff) >= hostlen) + return EAI_OVERFLOW; } if (serv != NULL) { - struct servent *sent = NULL; - -#ifndef SYS_BEOS /* No getservbyport() */ - int solved = 0; - - /* service name resolution */ - if (!(flags & NI_NUMERICSERV)) - { - - sent = getservbyport(addr->sin_port, - (flags & NI_DGRAM) - ? "udp" : "tcp"); - if (sent != NULL) - { - strlcpy (serv, sent->s_name, servlen); - solved = 1; - } - } - if (sent == NULL) -#endif - { - snprintf (serv, servlen, "%u", - (unsigned int)ntohs (addr->sin_port)); - serv[servlen - 1] = '\0'; - } + if (snprintf (serv, servlen, "%u", + (unsigned int)ntohs (addr->sin_port)) >= servlen) + return EAI_OVERFLOW; } } return 0; @@ -236,13 +160,38 @@ __getnameinfo( const struct sockaddr *sa, socklen_t salen, #endif /* if !HAVE_GETNAMEINFO */ - #ifndef HAVE_GETADDRINFO +/* + * Converts the current herrno error value into an EAI_* error code. + * That error code is normally returned by getnameinfo() or getaddrinfo(). + */ +static int +gai_error_from_herrno (void) +{ + switch (h_errno) + { + case HOST_NOT_FOUND: + return EAI_NONAME; + + case NO_ADDRESS: +# if (NO_ADDRESS != NO_DATA) + case NO_DATA: +# endif + return EAI_NODATA; + + case NO_RECOVERY: + return EAI_FAIL; + + case TRY_AGAIN: + return EAI_AGAIN; + } + return EAI_SYSTEM; +} + /* * This functions must be used to free the memory allocated by getaddrinfo(). */ -static void -__freeaddrinfo (struct addrinfo *res) +static void freeaddrinfo (struct addrinfo *res) { if (res != NULL) { @@ -327,8 +276,8 @@ makeipv4info (int type, int proto, u_long ip, u_short port, const char *name) * Only UDP and TCP over IPv4 are supported here. */ static int -__getaddrinfo (const char *node, const char *service, - const struct addrinfo *hints, struct addrinfo **res) +getaddrinfo (const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo *info; u_long ip; @@ -382,7 +331,7 @@ __getaddrinfo (const char *node, const char *service, protocol = IPPROTO_UDP; break; -#ifndef SYS_BEOS +#ifndef SOCK_RAW case SOCK_RAW: #endif case 0: @@ -416,7 +365,7 @@ __getaddrinfo (const char *node, const char *service, entry = gethostbyname (node); if (entry == NULL) - return EAI_NONAME; + return gai_error_from_herrno (); if ((entry->h_length != 4) || (entry->h_addrtype != AF_INET)) return EAI_FAMILY; @@ -499,23 +448,105 @@ __getaddrinfo (const char *node, const char *service, } #endif /* if !HAVE_GETADDRINFO */ - -int vlc_getnameinfo( const struct sockaddr *sa, int salen, - char *host, int hostlen, int *portnum, int flags ) -{ - char psz_servbuf[6], *psz_serv; - int i_servlen, i_val; #if defined( WIN32 ) && !defined( UNDER_CE ) /* * Here is the kind of kludge you need to keep binary compatibility among * varying OS versions... */ - typedef int (CALLBACK * GETNAMEINFO) ( const struct sockaddr*, socklen_t, - char*, DWORD, char*, DWORD, int ); - HINSTANCE module; - GETNAMEINFO ws2_getnameinfo; +typedef int (WSAAPI * GETNAMEINFO) ( const struct sockaddr FAR *, socklen_t, + char FAR *, DWORD, char FAR *, DWORD, int ); +typedef int (WSAAPI * GETADDRINFO) (const char FAR *, const char FAR *, + const struct addrinfo FAR *, + struct addrinfo FAR * FAR *); + +typedef void (WSAAPI * FREEADDRINFO) ( struct addrinfo FAR * ); + +static int WSAAPI _ws2_getnameinfo_bind ( const struct sockaddr FAR *, socklen_t, + char FAR *, DWORD, char FAR *, DWORD, int ); +static int WSAAPI _ws2_getaddrinfo_bind (const char FAR *, const char FAR *, + const struct addrinfo FAR *, + struct addrinfo FAR * FAR *); + +static GETNAMEINFO ws2_getnameinfo = _ws2_getnameinfo_bind; +static GETADDRINFO ws2_getaddrinfo = _ws2_getaddrinfo_bind; +static FREEADDRINFO ws2_freeaddrinfo; + +static FARPROC ws2_find_api (LPCTSTR name) +{ + FARPROC f = NULL; + + HMODULE m = GetModuleHandle (TEXT("WS2_32")); + if (m != NULL) + f = GetProcAddress (m, name); + + if (f == NULL) + { + /* Windows 2K IPv6 preview */ + m = LoadLibrary (TEXT("WSHIP6")); + if (m != NULL) + f = GetProcAddress (m, name); + } + + return f; +} + +static WSAAPI int _ws2_getnameinfo_bind( const struct sockaddr FAR * sa, socklen_t salen, + char FAR *host, DWORD hostlen, char FAR *serv, DWORD servlen, int flags ) +{ + GETNAMEINFO entry = (GETNAMEINFO)ws2_find_api (TEXT("getnameinfo")); + if (entry != NULL) + { + /* call API before replacing function pointer to avoid crash */ + int result = entry (sa, salen, host, hostlen, serv, servlen, flags); + ws2_getnameinfo = entry; + return result; + } + return getnameinfo (sa, salen, host, hostlen, serv, servlen, flags); +} +#undef getnameinfo +#define getnameinfo ws2_getnameinfo + +/* So much for using different calling conventions */ +static WSAAPI void call_freeaddrinfo (struct addrinfo *infos) +{ + freeaddrinfo (infos); +} + +static WSAAPI int _ws2_getaddrinfo_bind(const char FAR *node, const char FAR *service, + const struct addrinfo FAR *hints, struct addrinfo FAR * FAR *res) +{ + GETADDRINFO entry; + FREEADDRINFO freentry; + + entry = (GETADDRINFO)ws2_find_api (TEXT("getaddrinfo")); + freentry = (FREEADDRINFO)ws2_find_api (TEXT("freeaddrinfo")); + + if ((entry != NULL) && (freentry != NULL)) + { + /* call API before replacing function pointer to avoid crash */ + int result = entry (node, service, hints, res); + ws2_freeaddrinfo = freentry; + ws2_getaddrinfo = entry; + return result; + } + ws2_freeaddrinfo = call_freeaddrinfo; + return getaddrinfo (node, service, hints, res); +} +#undef getaddrinfo +#undef freeaddrinfo +#define getaddrinfo ws2_getaddrinfo +#define freeaddrinfo ws2_freeaddrinfo +#define HAVE_GETADDRINFO #endif + + +int vlc_getnameinfo( const struct sockaddr *sa, int salen, + char *host, int hostlen, int *portnum, int flags ) +{ + char psz_servbuf[6], *psz_serv; + int i_servlen, i_val; + flags |= NI_NUMERICSERV; if( portnum != NULL ) { @@ -527,47 +558,8 @@ int vlc_getnameinfo( const struct sockaddr *sa, int salen, psz_serv = NULL; i_servlen = 0; } -#if defined( WIN32 ) && !defined( UNDER_CE ) - /* Production IPv6 stack releases are in WS2_32.DLL */ - module = LoadLibrary( "ws2_32.dll" ); - if( module != NULL ) - { - ws2_getnameinfo = (GETNAMEINFO)GetProcAddress( module, "getnameinfo" ); - if( ws2_getnameinfo != NULL ) - { - i_val = ws2_getnameinfo( sa, salen, host, hostlen, psz_serv, - i_servlen, flags ); - FreeLibrary( module ); - - if( portnum != NULL ) - *portnum = atoi( psz_serv ); - return i_val; - } - - FreeLibrary( module ); - } -#endif -#if defined( HAVE_GETNAMEINFO ) || defined( UNDER_CE ) i_val = getnameinfo(sa, salen, host, hostlen, psz_serv, i_servlen, flags); -#else - { -# ifdef HAVE_USABLE_MUTEX_THAT_DONT_NEED_LIBVLC_POINTER - static vlc_value_t lock; - - /* my getnameinfo implementation is not thread-safe as it uses - * gethostbyaddr and the likes */ - vlc_mutex_lock( lock.p_address ); -#else -//# warning FIXME : This is not thread-safe! -#endif - i_val = __getnameinfo( sa, salen, host, hostlen, psz_serv, i_servlen, - flags ); -# ifdef HAVE_USABLE_MUTEX_THAT_DONT_NEED_LIBVLC_POINTER - vlc_mutex_unlock( lock.p_address ); -# endif - } -#endif if( portnum != NULL ) *portnum = atoi( psz_serv ); @@ -576,7 +568,6 @@ int vlc_getnameinfo( const struct sockaddr *sa, int salen, } -/* TODO: support for setting sin6_scope_id */ int vlc_getaddrinfo( vlc_object_t *p_this, const char *node, int i_port, const struct addrinfo *p_hints, struct addrinfo **res ) @@ -620,7 +611,7 @@ int vlc_getaddrinfo( vlc_object_t *p_this, const char *node, #endif } - /* + /* * VLC extensions : * - accept "" as NULL * - ignore square brackets @@ -648,106 +639,57 @@ int vlc_getaddrinfo( vlc_object_t *p_this, const char *node, } } -#if defined( WIN32 ) && !defined( UNDER_CE ) +#ifdef WIN32 + /* + * Winsock tries to resolve numerical IPv4 addresses as AAAA + * and IPv6 addresses as A... There comes the bug-to-bug fix. + */ + if ((hints.ai_flags & AI_NUMERICHOST) == 0) { - typedef int (CALLBACK * GETADDRINFO) ( const char *, const char *, - const struct addrinfo *, - struct addrinfo ** ); - HINSTANCE module; - GETADDRINFO ws2_getaddrinfo; - - module = LoadLibrary( "ws2_32.dll" ); - if( module != NULL ) - { - ws2_getaddrinfo = (GETADDRINFO)GetProcAddress( module, "getaddrinfo" ); + hints.ai_flags |= AI_NUMERICHOST; - if( ws2_getaddrinfo != NULL ) - { - int i_ret; + if (getaddrinfo (psz_node, psz_service, &hints, res) == 0) + return 0; - i_ret = ws2_getaddrinfo( psz_node, psz_service, &hints, res ); - FreeLibrary( module ); /* is this wise ? */ - return i_ret; - } - - FreeLibrary( module ); - } + hints.ai_flags &= ~AI_NUMERICHOST; } #endif -#if defined( HAVE_GETADDRINFO ) || defined( UNDER_CE ) +#if defined (HAVE_GETADDRINFO) # ifdef AI_IDN /* Run-time I18n Domain Names support */ - { - static vlc_bool_t i_idn = VLC_TRUE; /* beware of thread-safety */ + static vlc_bool_t b_idn = VLC_TRUE; /* beware of thread-safety */ - if( i_idn ) - { - int i_ret; - - hints.ai_flags |= AI_IDN; - i_ret = getaddrinfo( psz_node, psz_service, &hints, res ); - - if( i_ret != EAI_BADFLAGS ) - return i_ret; + if (b_idn) + { + hints.ai_flags |= AI_IDN; + int ret = getaddrinfo (psz_node, psz_service, &hints, res); - /* libidn not available: disable and retry without it */ + if (ret != EAI_BADFLAGS) + return ret; - /* NOTE: Using i_idn here would not be thread-safe */ - hints.ai_flags &= ~AI_IDN; - i_idn = VLC_FALSE; - msg_Dbg( p_this, "localized Domain Names not supported - " \ - "disabled" ); - } + /* IDN not available: disable and retry without it */ + hints.ai_flags &= ~AI_IDN; + b_idn = VLC_FALSE; + msg_Info (p_this, "International Domain Names not supported"); } # endif - return getaddrinfo( psz_node, psz_service, &hints, res ); + return getaddrinfo (psz_node, psz_service, &hints, res); #else -{ - int i_ret; - + int ret; vlc_value_t lock; - var_Create( p_this->p_libvlc, "getaddrinfo_mutex", VLC_VAR_MUTEX ); - var_Get( p_this->p_libvlc, "getaddrinfo_mutex", &lock ); - vlc_mutex_lock( lock.p_address ); + var_Create (p_this->p_libvlc, "getaddrinfo_mutex", VLC_VAR_MUTEX); + var_Get (p_this->p_libvlc, "getaddrinfo_mutex", &lock); + vlc_mutex_lock (lock.p_address); - i_ret = __getaddrinfo( psz_node, psz_service, &hints, res ); - vlc_mutex_unlock( lock.p_address ); - return i_ret; -} + ret = getaddrinfo (psz_node, psz_service, &hints, res); + vlc_mutex_unlock (lock.p_address); + return ret; #endif } void vlc_freeaddrinfo( struct addrinfo *infos ) { -#if defined( WIN32 ) && !defined( UNDER_CE ) - typedef void (CALLBACK * FREEADDRINFO) ( struct addrinfo * ); - HINSTANCE module; - FREEADDRINFO ws2_freeaddrinfo; - - module = LoadLibrary( "ws2_32.dll" ); - if( module != NULL ) - { - ws2_freeaddrinfo = (FREEADDRINFO)GetProcAddress( module, "freeaddrinfo" ); - - /* - * NOTE: it is assumed that ws2_32.dll defines either both or neither - * getaddrinfo() and freeaddrinfo(). - */ - if( ws2_freeaddrinfo != NULL ) - { - ws2_freeaddrinfo( infos ); - FreeLibrary( module ); - return; - } - - FreeLibrary( module ); - } -#endif -#if defined( HAVE_GETADDRINFO ) || defined( UNDER_CE ) - freeaddrinfo( infos ); -#else - __freeaddrinfo( infos ); -#endif + freeaddrinfo (infos); }