]> git.sesse.net Git - vlc/blob - src/network/getaddrinfo.c
ac2d67b819ffea93b9bba7da4394ca35f7562fd7
[vlc] / src / network / getaddrinfo.c
1 /*****************************************************************************
2  * getaddrinfo.c: getaddrinfo/getnameinfo replacement functions
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * Copyright (C) 2002-2007 Rémi Denis-Courmont
6  * $Id$
7  *
8  * Author: Rémi Denis-Courmont <rem # videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc_common.h>
30 #include <vlc_charset.h>
31
32 #include <stddef.h> /* size_t */
33 #include <string.h> /* strlen(), memcpy(), memset(), strchr() */
34 #include <stdlib.h> /* malloc(), free(), strtoul() */
35 #include <errno.h>
36
37 #ifdef HAVE_SYS_TYPES_H
38 #   include <sys/types.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 #   include <arpa/inet.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_H
44 #   include <netinet/in.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #   include <unistd.h>
48 #endif
49
50 #include <vlc_network.h>
51
52 #ifndef NO_ADDRESS
53 #   define NO_ADDRESS  NO_DATA
54 #endif
55 #ifndef INADDR_NONE
56 #   define INADDR_NONE 0xFFFFFFFF
57 #endif
58 #ifndef AF_UNSPEC
59 #   define AF_UNSPEC   0
60 #endif
61
62
63 #ifndef HAVE_GAI_STRERROR
64 static const struct
65 {
66     int        code;
67     const char msg[41];
68 } gai_errlist[] =
69 {
70     { 0,              "Error 0" },
71     { EAI_BADFLAGS,   "Invalid flag used" },
72     { EAI_NONAME,     "Host or service not found" },
73     { EAI_AGAIN,      "Temporary name service failure" },
74     { EAI_FAIL,       "Non-recoverable name service failure" },
75     { EAI_NODATA,     "No data for host name" },
76     { EAI_FAMILY,     "Unsupported address family" },
77     { EAI_SOCKTYPE,   "Unsupported socket type" },
78     { EAI_SERVICE,    "Incompatible service for socket type" },
79     { EAI_ADDRFAMILY, "Unavailable address family for host name" },
80     { EAI_MEMORY,     "Memory allocation failure" },
81     { EAI_OVERFLOW,   "Buffer overflow" },
82     { EAI_SYSTEM,     "System error" },
83     { 0,              "" },
84 };
85
86 static const char gai_unknownerr[] = "Unrecognized error number";
87
88 /****************************************************************************
89  * Converts an EAI_* error code into human readable english text.
90  ****************************************************************************/
91 const char *vlc_gai_strerror (int errnum)
92 {
93     for (unsigned i = 0; *gai_errlist[i].msg; i++)
94         if (errnum == gai_errlist[i].code)
95             return gai_errlist[i].msg;
96
97     return gai_unknownerr;
98 }
99 #else /* ifndef HAVE_GAI_STRERROR */
100 const char *vlc_gai_strerror (int errnum)
101 {
102     return gai_strerror (errnum);
103 }
104 #endif
105
106 #ifndef HAVE_GETNAMEINFO
107 #define _NI_MASK (NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|\
108                   NI_DGRAM)
109 /*
110  * getnameinfo() non-thread-safe IPv4-only implementation,
111  * Address-family-independent address to hostname translation
112  * (reverse DNS lookup in case of IPv4).
113  *
114  * This is meant for use on old IP-enabled systems that are not IPv6-aware,
115  * and probably do not have getnameinfo(), but have the old gethostbyaddr()
116  * function.
117  *
118  * GNU C library 2.0.x is known to lack this function, even though it defines
119  * getaddrinfo().
120  */
121 #ifdef WIN32
122 static int WSAAPI
123 stub_getnameinfo (const struct sockaddr *sa, socklen_t salen,
124              char *host, DWORD hostlen, char *serv, DWORD servlen, int flags)
125 #else
126 static int
127 stub_getnameinfo (const struct sockaddr *sa, socklen_t salen,
128              char *host, int hostlen, char *serv, int servlen, int flags)
129 #endif
130 {
131     if (((size_t)salen < sizeof (struct sockaddr_in))
132      || (sa->sa_family != AF_INET))
133         return EAI_FAMILY;
134     else if (flags & (~_NI_MASK))
135         return EAI_BADFLAGS;
136     else
137     {
138         const struct sockaddr_in *addr;
139
140         addr = (const struct sockaddr_in *)sa;
141
142         if (host != NULL)
143         {
144             /* host name resolution */
145             if (!(flags & NI_NUMERICHOST))
146             {
147                 if (flags & NI_NAMEREQD)
148                     return EAI_NONAME;
149             }
150
151             /* inet_ntoa() is not thread-safe, do not use it */
152             uint32_t ipv4 = ntohl (addr->sin_addr.s_addr);
153
154             if (snprintf (host, hostlen, "%u.%u.%u.%u", ipv4 >> 24,
155                           (ipv4 >> 16) & 0xff, (ipv4 >> 8) & 0xff,
156                           ipv4 & 0xff) >= (int)hostlen)
157                 return EAI_OVERFLOW;
158         }
159
160         if (serv != NULL)
161         {
162             if (snprintf (serv, servlen, "%u",
163                           (unsigned int)ntohs (addr->sin_port)) >= (int)servlen)
164                 return EAI_OVERFLOW;
165         }
166     }
167     return 0;
168 }
169 #undef getnameinfo
170 #define getnameifo stub_getnameinfo
171 #endif /* if !HAVE_GETNAMEINFO */
172
173 #ifndef HAVE_GETADDRINFO
174 #define _AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
175 /*
176  * Converts the current herrno error value into an EAI_* error code.
177  * That error code is normally returned by getnameinfo() or getaddrinfo().
178  */
179 static int
180 gai_error_from_herrno (void)
181 {
182     switch (h_errno)
183     {
184         case HOST_NOT_FOUND:
185             return EAI_NONAME;
186
187         case NO_ADDRESS:
188 # if (NO_ADDRESS != NO_DATA)
189         case NO_DATA:
190 # endif
191             return EAI_NODATA;
192
193         case NO_RECOVERY:
194             return EAI_FAIL;
195
196         case TRY_AGAIN:
197             return EAI_AGAIN;
198     }
199     return EAI_SYSTEM;
200 }
201
202 /*
203  * This functions must be used to free the memory allocated by getaddrinfo().
204  */
205 #ifdef WIN32
206 static void WSAAPI stub_freeaddrinfo (struct addrinfo *res)
207 #else
208 static void stub_freeaddrinfo (struct addrinfo *res)
209 #endif
210 {
211     if (res == NULL)
212         return;
213     free (res->ai_canonname);
214     free (res->ai_addr);
215     free (res->ai_next);
216     free (res);
217 }
218
219
220 /*
221  * Internal function that builds an addrinfo struct.
222  */
223 static struct addrinfo *
224 makeaddrinfo (int af, int type, int proto,
225               const struct sockaddr *addr, size_t addrlen,
226               const char *canonname)
227 {
228     struct addrinfo *res;
229
230     res = (struct addrinfo *)malloc (sizeof (struct addrinfo));
231     if (res != NULL)
232     {
233         res->ai_flags = 0;
234         res->ai_family = af;
235         res->ai_socktype = type;
236         res->ai_protocol = proto;
237         res->ai_addrlen = addrlen;
238         res->ai_addr = malloc (addrlen);
239         res->ai_canonname = NULL;
240         res->ai_next = NULL;
241
242         if (res->ai_addr != NULL)
243         {
244             memcpy (res->ai_addr, addr, addrlen);
245
246             if (canonname != NULL)
247             {
248                 res->ai_canonname = strdup (canonname);
249                 if (res->ai_canonname != NULL)
250                     return res; /* success ! */
251             }
252             else
253                 return res;
254         }
255     }
256     /* failsafe */
257     vlc_freeaddrinfo (res);
258     return NULL;
259 }
260
261
262 static struct addrinfo *
263 makeipv4info (int type, int proto, u_long ip, u_short port, const char *name)
264 {
265     struct sockaddr_in addr;
266
267     memset (&addr, 0, sizeof (addr));
268     addr.sin_family = AF_INET;
269 # ifdef HAVE_SA_LEN
270     addr.sin_len = sizeof (addr);
271 # endif
272     addr.sin_port = port;
273     addr.sin_addr.s_addr = ip;
274
275     return makeaddrinfo (AF_INET, type, proto,
276                          (struct sockaddr*)&addr, sizeof (addr), name);
277 }
278
279
280 /*
281  * getaddrinfo() non-thread-safe IPv4-only implementation
282  * Address-family-independent hostname to address resolution.
283  *
284  * This is meant for IPv6-unaware systems that do probably not provide
285  * getaddrinfo(), but still have old function gethostbyname().
286  *
287  * Only UDP and TCP over IPv4 are supported here.
288  */
289 #ifdef WIN32
290 static int WSAAPI
291 stub_getaddrinfo (const char *node, const char *service,
292              const struct addrinfo *hints, struct addrinfo **res)
293 #else
294 static int
295 stub_getaddrinfo (const char *node, const char *service,
296              const struct addrinfo *hints, struct addrinfo **res)
297 #endif
298 {
299     struct addrinfo *info;
300     u_long ip;
301     u_short port;
302     int protocol = 0, flags = 0;
303     const char *name = NULL;
304
305 #ifdef WIN32
306     /*
307      * Maybe you knew already that Winsock does not handle TCP/RST packets
308      * properly, so that when a TCP connection fails, it will wait until it
309      * times out even if the remote host did return a TCP/RST. However, it
310      * still sees the TCP/RST as the error code is 10061 instead of 10060.
311      * Basically, we have the stupid brainfucked behavior with DNS queries...
312      * When the recursive DNS server returns an error, Winsock waits about
313      * 2 seconds before it returns to the callers, even though it should know
314      * that is pointless. I'd like to know how come this hasn't been fixed
315      * for the past decade, or maybe not.
316      *
317      * Anyway, this is causing a severe delay when the SAP listener tries
318      * to resolve more than ten IPv6 numeric addresses. Modern systems will
319      * eventually realize that it is an IPv6 address, and won't try to resolve
320      * it as a IPv4 address via the Domain Name Service. Old systems
321      * (including Windows XP without the IPv6 stack) will not. It is normally
322      * not an issue as the DNS server usually returns an error very quickly.
323      * But it IS a severe issue on Windows, given the bug explained above.
324      * So here comes one more bug-to-bug Windows compatibility fix.
325      */
326     if ((node != NULL) && (strchr (node, ':') != NULL))
327        return EAI_NONAME;
328 #endif
329
330     if (hints != NULL)
331     {
332         flags = hints->ai_flags;
333
334         if (flags & ~_AI_MASK)
335             return EAI_BADFLAGS;
336         /* only accept AF_INET and AF_UNSPEC */
337         if (hints->ai_family && (hints->ai_family != AF_INET))
338             return EAI_FAMILY;
339
340         /* protocol sanity check */
341         switch (hints->ai_socktype)
342         {
343             case SOCK_STREAM:
344                 protocol = IPPROTO_TCP;
345                 break;
346
347             case SOCK_DGRAM:
348                 protocol = IPPROTO_UDP;
349                 break;
350
351 #ifndef SOCK_RAW
352             case SOCK_RAW:
353 #endif
354             case 0:
355                 break;
356
357             default:
358                 return EAI_SOCKTYPE;
359         }
360         if (hints->ai_protocol && protocol
361          && (protocol != hints->ai_protocol))
362             return EAI_SERVICE;
363     }
364
365     *res = NULL;
366
367     /* default values */
368     if (node == NULL)
369     {
370         if (flags & AI_PASSIVE)
371             ip = htonl (INADDR_ANY);
372         else
373             ip = htonl (INADDR_LOOPBACK);
374     }
375     else
376     if ((ip = inet_addr (node)) == INADDR_NONE)
377     {
378         struct hostent *entry = NULL;
379
380         /* hostname resolution */
381         if (!(flags & AI_NUMERICHOST))
382             entry = gethostbyname (node);
383
384         if (entry == NULL)
385             return gai_error_from_herrno ();
386
387         if ((entry->h_length != 4) || (entry->h_addrtype != AF_INET))
388             return EAI_FAMILY;
389
390         ip = *((u_long *) entry->h_addr);
391         if (flags & AI_CANONNAME)
392             name = entry->h_name;
393     }
394
395     if ((flags & AI_CANONNAME) && (name == NULL))
396         name = node;
397
398     /* service resolution */
399     if (service == NULL)
400         port = 0;
401     else
402     {
403         unsigned long d;
404         char *end;
405
406         d = strtoul (service, &end, 0);
407         if (end[0] || (d > 65535u))
408             return EAI_SERVICE;
409
410         port = htons ((u_short)d);
411     }
412
413     /* building results... */
414     if ((!protocol) || (protocol == IPPROTO_UDP))
415     {
416         info = makeipv4info (SOCK_DGRAM, IPPROTO_UDP, ip, port, name);
417         if (info == NULL)
418         {
419             errno = ENOMEM;
420             return EAI_SYSTEM;
421         }
422         if (flags & AI_PASSIVE)
423             info->ai_flags |= AI_PASSIVE;
424         *res = info;
425     }
426     if ((!protocol) || (protocol == IPPROTO_TCP))
427     {
428         info = makeipv4info (SOCK_STREAM, IPPROTO_TCP, ip, port, name);
429         if (info == NULL)
430         {
431             errno = ENOMEM;
432             return EAI_SYSTEM;
433         }
434         info->ai_next = *res;
435         if (flags & AI_PASSIVE)
436             info->ai_flags |= AI_PASSIVE;
437         *res = info;
438     }
439
440     return 0;
441 }
442 #undef getaddrinfo
443 #define getaddrifo stub_getaddrinfo
444 #undef freeaddrinfo
445 #define freeaddrifo stub_freeaddrinfo
446 #endif /* if !HAVE_GETADDRINFO */
447
448 #if defined( WIN32 ) && !defined( UNDER_CE )
449     /*
450      * Here is the kind of kludge you need to keep binary compatibility among
451      * varying OS versions...
452      */
453 typedef int (WSAAPI * GETNAMEINFO) ( const struct sockaddr FAR *, socklen_t,
454                                            char FAR *, DWORD, char FAR *, DWORD, int );
455 typedef int (WSAAPI * GETADDRINFO) (const char FAR *, const char FAR *,
456                                           const struct addrinfo FAR *,
457                                           struct addrinfo FAR * FAR *);
458
459 typedef void (WSAAPI * FREEADDRINFO) ( struct addrinfo FAR * );
460
461 static int WSAAPI _ws2_getnameinfo_bind ( const struct sockaddr FAR *, socklen_t,
462                                            char FAR *, DWORD, char FAR *, DWORD, int );
463 static int WSAAPI _ws2_getaddrinfo_bind (const char FAR *, const char FAR *,
464                                           const struct addrinfo FAR *,
465                                           struct addrinfo FAR * FAR *);
466
467 static GETNAMEINFO ws2_getnameinfo = _ws2_getnameinfo_bind;
468 static GETADDRINFO ws2_getaddrinfo = _ws2_getaddrinfo_bind;
469 static FREEADDRINFO ws2_freeaddrinfo;
470
471 static FARPROC ws2_find_api (LPCTSTR name)
472 {
473     FARPROC f = NULL;
474
475     HMODULE m = GetModuleHandle (TEXT("WS2_32"));
476     if (m != NULL)
477         f = GetProcAddress (m, name);
478
479     if (f == NULL)
480     {
481         /* Windows 2K IPv6 preview */
482         m = LoadLibrary (TEXT("WSHIP6"));
483         if (m != NULL)
484             f = GetProcAddress (m, name);
485     }
486
487     return f;
488 }
489
490 static WSAAPI int _ws2_getnameinfo_bind( const struct sockaddr FAR * sa, socklen_t salen,
491                char FAR *host, DWORD hostlen, char FAR *serv, DWORD servlen, int flags )
492 {
493     GETNAMEINFO entry = (GETNAMEINFO)ws2_find_api (TEXT("getnameinfo"));
494     int result;
495
496     if (entry == NULL)
497     {
498         /* not found, use replacement API instead */
499         entry = stub_getnameinfo;
500     }
501     /* call API before replacing function pointer to avoid crash */
502     result = entry (sa, salen, host, hostlen, serv, servlen, flags);
503     ws2_getnameinfo = entry;
504     return result;
505 }
506 #undef getnameinfo
507 #define getnameinfo ws2_getnameinfo
508
509 static WSAAPI int _ws2_getaddrinfo_bind(const char FAR *node, const char FAR *service,
510                const struct addrinfo FAR *hints, struct addrinfo FAR * FAR *res)
511 {
512     GETADDRINFO entry;
513     FREEADDRINFO freentry;
514     int result;
515
516     entry = (GETADDRINFO)ws2_find_api (TEXT("getaddrinfo"));
517     freentry = (FREEADDRINFO)ws2_find_api (TEXT("freeaddrinfo"));
518
519     if ((entry == NULL) ||  (freentry == NULL))
520     {
521         /* not found, use replacement API instead */
522         entry = stub_getaddrinfo;
523         freentry = stub_freeaddrinfo;
524     }
525     /* call API before replacing function pointer to avoid crash */
526     result = entry (node, service, hints, res);
527     ws2_freeaddrinfo = freentry;
528     ws2_getaddrinfo = entry;
529     return result;
530 }
531 #undef getaddrinfo
532 #undef freeaddrinfo
533 #define getaddrinfo ws2_getaddrinfo
534 #define freeaddrinfo ws2_freeaddrinfo
535 #define HAVE_GETADDRINFO
536 #endif
537
538
539 int vlc_getnameinfo( const struct sockaddr *sa, int salen,
540                      char *host, int hostlen, int *portnum, int flags )
541 {
542     char psz_servbuf[6], *psz_serv;
543     int i_servlen, i_val;
544
545     flags |= NI_NUMERICSERV;
546     if( portnum != NULL )
547     {
548         psz_serv = psz_servbuf;
549         i_servlen = sizeof( psz_servbuf );
550     }
551     else
552     {
553         psz_serv = NULL;
554         i_servlen = 0;
555     }
556
557     i_val = getnameinfo(sa, salen, host, hostlen, psz_serv, i_servlen, flags);
558
559     if( portnum != NULL )
560         *portnum = atoi( psz_serv );
561
562     return i_val;
563 }
564
565
566 int vlc_getaddrinfo( vlc_object_t *p_this, const char *node,
567                      int i_port, const struct addrinfo *p_hints,
568                      struct addrinfo **res )
569 {
570     struct addrinfo hints;
571     char psz_buf[NI_MAXHOST], psz_service[6];
572
573     /*
574      * In VLC, we always use port number as integer rather than strings
575      * for historical reasons (and portability).
576      */
577     if( ( i_port > 65535 ) || ( i_port < 0 ) )
578     {
579         msg_Err( p_this, "invalid port number %d specified", i_port );
580         return EAI_SERVICE;
581     }
582
583     /* cannot overflow */
584     snprintf( psz_service, 6, "%d", i_port );
585
586     /* Check if we have to force ipv4 or ipv6 */
587     memset (&hints, 0, sizeof (hints));
588     if (p_hints != NULL)
589     {
590         const int safe_flags =
591             AI_PASSIVE |
592             AI_CANONNAME |
593             AI_NUMERICHOST |
594             AI_NUMERICSERV |
595 #ifdef AI_ALL
596             AI_ALL |
597 #endif
598 #ifdef AI_ADDRCONFIG
599             AI_ADDRCONFIG |
600 #endif
601 #ifdef AI_V4MAPPED
602             AI_V4MAPPED |
603 #endif
604             0;
605
606         hints.ai_family = p_hints->ai_family;
607         hints.ai_socktype = p_hints->ai_socktype;
608         hints.ai_protocol = p_hints->ai_protocol;
609         /* Unfortunately, some flags chang the layout of struct addrinfo, so
610          * they cannot be copied blindly from p_hints to &hints. Therefore, we
611          * only copy flags that we know for sure are "safe".
612          */
613         hints.ai_flags = p_hints->ai_flags & safe_flags;
614     }
615
616     /* We only ever use port *numbers* */
617     hints.ai_flags |= AI_NUMERICSERV;
618
619     if( hints.ai_family == AF_UNSPEC )
620     {
621 #ifdef AF_INET6
622         if (var_CreateGetBool (p_this, "ipv6"))
623             hints.ai_family = AF_INET6;
624         else
625 #endif
626         if (var_CreateGetBool (p_this, "ipv4"))
627             hints.ai_family = AF_INET;
628     }
629
630     /*
631      * VLC extensions :
632      * - accept "" as NULL
633      * - ignore square brackets
634      */
635     if (node != NULL)
636     {
637         if (node[0] == '[')
638         {
639             size_t len = strlen (node + 1);
640             if ((len <= sizeof (psz_buf)) && (node[len] == ']'))
641             {
642                 assert (len > 0);
643                 memcpy (psz_buf, node + 1, len - 1);
644                 psz_buf[len - 1] = '\0';
645                 node = psz_buf;
646             }
647         }
648         if (node[0] == '\0')
649             node = NULL;
650     }
651
652     int ret;
653     node = ToLocale (node);
654 #ifdef WIN32
655     /*
656      * Winsock tries to resolve numerical IPv4 addresses as AAAA
657      * and IPv6 addresses as A... There comes the bug-to-bug fix.
658      */
659     if ((hints.ai_flags & AI_NUMERICHOST) == 0)
660     {
661         hints.ai_flags |= AI_NUMERICHOST;
662         ret = getaddrinfo (node, psz_service, &hints, res);
663         if (ret == 0)
664             goto out;
665         hints.ai_flags &= ~AI_NUMERICHOST;
666     }
667 #endif
668 #ifdef AI_IDN
669     /* Run-time I18n Domain Names support */
670     hints.ai_flags |= AI_IDN;
671     ret = getaddrinfo (node, psz_service, &hints, res);
672     if (ret != EAI_BADFLAGS)
673         goto out;
674     /* IDN not available: disable and retry without it */
675     hints.ai_flags &= ~AI_IDN;
676 #endif
677     ret = getaddrinfo (node, psz_service, &hints, res);
678
679 out:
680     LocaleFree (node);
681     return ret;
682 }
683
684
685 void vlc_freeaddrinfo( struct addrinfo *infos )
686 {
687     freeaddrinfo (infos);
688 }
689
690 /**
691  * inet_pton() replacement
692  */
693 int vlc_inet_pton (int af, const char *src, void *dst)
694 {
695 #ifndef HAVE_INET_PTON
696     /* Windows Vista has inet_pton(), but not XP. */
697     /* We have a pretty good example of abstraction inversion here... */
698     struct addrinfo hints = {
699         .ai_family = af,
700         .ai_socktype = SOCK_DGRAM, /* make sure we have... */
701         .ai_protocol = IPPROTO_UDP, /* ...only one response */
702         .ai_flags = AI_NUMERICHOST,
703     }, *res;
704
705     if (getaddrinfo (src, NULL, &hints, &res))
706         return 0;
707
708     const void *data;
709     size_t len;
710
711     switch (af)
712     {
713         case AF_INET:
714             data = &((const struct sockaddr_in *)res->ai_addr)->sin_addr;
715             len = sizeof (struct in_addr);
716             break;
717 #ifdef AF_INET6
718         case AF_INET6:
719             data = &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
720             len = sizeof (struct in6_addr);
721             break;
722 #endif
723         default:
724             freeaddrinfo (res);
725             return -1;
726     }
727     memcpy (dst, data, len);
728     freeaddrinfo (res);
729     return 1;
730 #else /* HAVE_INET_PTON */
731     return inet_pton( af, src, dst );
732 #endif /* HAVE_INET_PTON */
733 }
734
735 /**
736  * inet_ntop() replacement
737  */
738 const char *vlc_inet_ntop (int af, const void *src, char *dst, socklen_t cnt)
739 {
740 #ifndef HAVE_INET_NTOP
741     int ret = EAI_FAMILY;
742
743     switch (af)
744     {
745 #ifdef AF_INET6
746         case AF_INET6:
747             {
748                 struct sockaddr_in6 addr;
749                 memset (&addr, 0, sizeof(addr));
750                 addr.sin6_family = AF_INET6;
751                 addr.sin6_addr = *(struct in6_addr *)src;
752                 ret = getnameinfo ((struct sockaddr *)&addr, sizeof (addr),
753                                    dst, cnt, NULL, 0, NI_NUMERICHOST);
754             }
755
756 #endif
757         case AF_INET:
758             {
759                 struct sockaddr_in addr;
760                 memset(&addr, 0, sizeof(addr));
761                 addr.sin_family = AF_INET;
762                 addr.sin_addr = *(struct in_addr *)src;
763                 ret = getnameinfo ((struct sockaddr *)&addr, sizeof (addr),
764                                    dst, cnt, NULL, 0, NI_NUMERICHOST);
765             }
766     }
767     return (ret == 0) ? dst : NULL;
768 #else /* HAVE_INET_NTOP */
769     return inet_ntop( af, src, dst, cnt );
770 #endif /* HAVE_INET_NTOP */
771 }
772