X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fnetwork%2Fgetaddrinfo.c;h=7d56c2dccf386ce23e3f4a820d6e971453ee9ded;hb=5eedc2aec432ba05d7e33920a035b85b1af5c0b0;hp=4294bce83f8c45dcd3a0c13b3cf9ad028499295f;hpb=d666030b2349e8a710fcba4d2cabb912cc700580;p=vlc diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c index 4294bce83f..7d56c2dccf 100644 --- a/src/network/getaddrinfo.c +++ b/src/network/getaddrinfo.c @@ -27,15 +27,15 @@ #endif #include +#include #include /* size_t */ #include /* strlen(), memcpy(), memset(), strchr() */ #include /* malloc(), free(), strtoul() */ #include +#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif +#include #ifdef HAVE_ARPA_INET_H # include #endif @@ -119,11 +119,11 @@ const char *vlc_gai_strerror (int errnum) */ #ifdef WIN32 static int WSAAPI -getnameinfo (const struct sockaddr *sa, socklen_t salen, +stub_getnameinfo (const struct sockaddr *sa, socklen_t salen, char *host, DWORD hostlen, char *serv, DWORD servlen, int flags) #else static int -getnameinfo (const struct sockaddr *sa, socklen_t salen, +stub_getnameinfo (const struct sockaddr *sa, socklen_t salen, char *host, int hostlen, char *serv, int servlen, int flags) #endif { @@ -165,7 +165,8 @@ getnameinfo (const struct sockaddr *sa, socklen_t salen, } return 0; } - +#undef getnameinfo +#define getnameifo stub_getnameinfo #endif /* if !HAVE_GETNAMEINFO */ #ifndef HAVE_GETADDRINFO @@ -201,21 +202,17 @@ gai_error_from_herrno (void) * This functions must be used to free the memory allocated by getaddrinfo(). */ #ifdef WIN32 -static void WSAAPI freeaddrinfo (struct addrinfo *res) +static void WSAAPI stub_freeaddrinfo (struct addrinfo *res) #else -static void freeaddrinfo (struct addrinfo *res) +static void stub_freeaddrinfo (struct addrinfo *res) #endif { - if (res != NULL) - { - if (res->ai_canonname != NULL) - free (res->ai_canonname); - if (res->ai_addr != NULL) - free (res->ai_addr); - if (res->ai_next != NULL) - free (res->ai_next); - free (res); - } + if (res == NULL) + return; + free (res->ai_canonname); + free (res->ai_addr); + free (res->ai_next); + free (res); } @@ -290,11 +287,11 @@ makeipv4info (int type, int proto, u_long ip, u_short port, const char *name) */ #ifdef WIN32 static int WSAAPI -getaddrinfo (const char *node, const char *service, +stub_getaddrinfo (const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) #else static int -getaddrinfo (const char *node, const char *service, +stub_getaddrinfo (const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) #endif { @@ -441,6 +438,10 @@ getaddrinfo (const char *node, const char *service, return 0; } +#undef getaddrinfo +#define getaddrifo stub_getaddrinfo +#undef freeaddrinfo +#define freeaddrifo stub_freeaddrinfo #endif /* if !HAVE_GETADDRINFO */ #if defined( WIN32 ) && !defined( UNDER_CE ) @@ -494,8 +495,7 @@ static WSAAPI int _ws2_getnameinfo_bind( const struct sockaddr FAR * sa, socklen if (entry == NULL) { /* not found, use replacement API instead */ - entry = getnameinfo; - + entry = stub_getnameinfo; } /* call API before replacing function pointer to avoid crash */ result = entry (sa, salen, host, hostlen, serv, servlen, flags); @@ -518,8 +518,8 @@ static WSAAPI int _ws2_getaddrinfo_bind(const char FAR *node, const char FAR *se if ((entry == NULL) || (freentry == NULL)) { /* not found, use replacement API instead */ - entry = getaddrinfo; - freentry = freeaddrinfo; + entry = stub_getaddrinfo; + freentry = stub_freeaddrinfo; } /* call API before replacing function pointer to avoid crash */ result = entry (node, service, hints, res); @@ -535,7 +535,6 @@ static WSAAPI int _ws2_getaddrinfo_bind(const char FAR *node, const char FAR *se #endif - int vlc_getnameinfo( const struct sockaddr *sa, int salen, char *host, int hostlen, int *portnum, int flags ) { @@ -563,12 +562,24 @@ int vlc_getnameinfo( const struct sockaddr *sa, int salen, } +/** + * Resolves a host name to a list of socket addresses (like getaddrinfo()). + * + * @param p_this a VLC object + * @param node host name to resolve (encoded as UTF-8), or NULL + * @param i_port port number for the socket addresses + * @param p_hints parameters (see getaddrinfo() manual page) + * @param res pointer set to the resulting chained list. + * @return 0 on success, a getaddrinfo() error otherwise. + * On failure, *res is undefined. On success, it must be freed with + * vlc_freeaddrinfo(). + */ int vlc_getaddrinfo( vlc_object_t *p_this, const char *node, int i_port, const struct addrinfo *p_hints, struct addrinfo **res ) { struct addrinfo hints; - char psz_buf[NI_MAXHOST], *psz_node, psz_service[6]; + char psz_buf[NI_MAXHOST], psz_service[6]; /* * In VLC, we always use port number as integer rather than strings @@ -591,9 +602,7 @@ int vlc_getaddrinfo( vlc_object_t *p_this, const char *node, AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | -#ifdef AI_NUMERICSERV AI_NUMERICSERV | -#endif #ifdef AI_ALL AI_ALL | #endif @@ -615,10 +624,8 @@ int vlc_getaddrinfo( vlc_object_t *p_this, const char *node, hints.ai_flags = p_hints->ai_flags & safe_flags; } -#ifdef AI_NUMERICSERV /* We only ever use port *numbers* */ hints.ai_flags |= AI_NUMERICSERV; -#endif if( hints.ai_family == AF_UNSPEC ) { @@ -636,29 +643,25 @@ int vlc_getaddrinfo( vlc_object_t *p_this, const char *node, * - accept "" as NULL * - ignore square brackets */ - if( ( node == NULL ) || (node[0] == '\0' ) ) - { - psz_node = NULL; - } - else + if (node != NULL) { - strlcpy( psz_buf, node, NI_MAXHOST ); - - psz_node = psz_buf; - - if( psz_buf[0] == '[' ) + if (node[0] == '[') { - char *ptr; - - ptr = strrchr( psz_buf, ']' ); - if( ( ptr != NULL ) && (ptr[1] == '\0' ) ) + size_t len = strlen (node + 1); + if ((len <= sizeof (psz_buf)) && (node[len] == ']')) { - *ptr = '\0'; - psz_node++; + assert (len > 0); + memcpy (psz_buf, node + 1, len - 1); + psz_buf[len - 1] = '\0'; + node = psz_buf; } } + if (node[0] == '\0') + node = NULL; } + int ret; + node = ToLocale (node); #ifdef WIN32 /* * Winsock tries to resolve numerical IPv4 addresses as AAAA @@ -667,24 +670,28 @@ int vlc_getaddrinfo( vlc_object_t *p_this, const char *node, if ((hints.ai_flags & AI_NUMERICHOST) == 0) { hints.ai_flags |= AI_NUMERICHOST; - - if (getaddrinfo (psz_node, psz_service, &hints, res) == 0) - return 0; - + ret = getaddrinfo (node, psz_service, &hints, res); + if (ret == 0) + goto out; hints.ai_flags &= ~AI_NUMERICHOST; } #endif #ifdef AI_IDN /* Run-time I18n Domain Names support */ hints.ai_flags |= AI_IDN; - int ret = getaddrinfo (psz_node, psz_service, &hints, res); + ret = getaddrinfo (node, psz_service, &hints, res); if (ret != EAI_BADFLAGS) - return ret; - + goto out; /* IDN not available: disable and retry without it */ hints.ai_flags &= ~AI_IDN; #endif - return getaddrinfo (psz_node, psz_service, &hints, res); + ret = getaddrinfo (node, psz_service, &hints, res); + +#if defined(AI_IDN) || defined(WIN32) +out: +#endif + LocaleFree (node); + return ret; } @@ -692,3 +699,87 @@ void vlc_freeaddrinfo( struct addrinfo *infos ) { freeaddrinfo (infos); } + +/** + * inet_pton() replacement + */ +int vlc_inet_pton (int af, const char *src, void *dst) +{ +#ifndef HAVE_INET_PTON + /* Windows Vista has inet_pton(), but not XP. */ + /* We have a pretty good example of abstraction inversion here... */ + struct addrinfo hints = { + .ai_family = af, + .ai_socktype = SOCK_DGRAM, /* make sure we have... */ + .ai_protocol = IPPROTO_UDP, /* ...only one response */ + .ai_flags = AI_NUMERICHOST, + }, *res; + + if (getaddrinfo (src, NULL, &hints, &res)) + return 0; + + const void *data; + size_t len; + + switch (af) + { + case AF_INET: + data = &((const struct sockaddr_in *)res->ai_addr)->sin_addr; + len = sizeof (struct in_addr); + break; +#ifdef AF_INET6 + case AF_INET6: + data = &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + len = sizeof (struct in6_addr); + break; +#endif + default: + freeaddrinfo (res); + return -1; + } + memcpy (dst, data, len); + freeaddrinfo (res); + return 1; +#else /* HAVE_INET_PTON */ + return inet_pton( af, src, dst ); +#endif /* HAVE_INET_PTON */ +} + +/** + * inet_ntop() replacement + */ +const char *vlc_inet_ntop (int af, const void *src, char *dst, socklen_t cnt) +{ +#ifndef HAVE_INET_NTOP + int ret = EAI_FAMILY; + + switch (af) + { +#ifdef AF_INET6 + case AF_INET6: + { + struct sockaddr_in6 addr; + memset (&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = *(struct in6_addr *)src; + ret = getnameinfo ((struct sockaddr *)&addr, sizeof (addr), + dst, cnt, NULL, 0, NI_NUMERICHOST); + } + +#endif + case AF_INET: + { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *(struct in_addr *)src; + ret = getnameinfo ((struct sockaddr *)&addr, sizeof (addr), + dst, cnt, NULL, 0, NI_NUMERICHOST); + } + } + return (ret == 0) ? dst : NULL; +#else /* HAVE_INET_NTOP */ + return inet_ntop( af, src, dst, cnt ); +#endif /* HAVE_INET_NTOP */ +} +