]> git.sesse.net Git - vlc/blob - src/network/getaddrinfo.c
efdb4e12674a226541682e49cb5011529d5a5aef
[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 /**
567  * Resolves a host name to a list of socket addresses (like getaddrinfo()).
568  *
569  * @param p_this a VLC object
570  * @param node host name to resolve (encoded as UTF-8), or NULL
571  * @param i_port port number for the socket addresses
572  * @param p_hints parameters (see getaddrinfo() manual page)
573  * @param res pointer set to the resulting chained list.
574  * @return 0 on success, a getaddrinfo() error otherwise.
575  * On failure, *res is undefined. On success, it must be freed with
576  * vlc_freeaddrinfo().
577  */
578 int vlc_getaddrinfo( vlc_object_t *p_this, const char *node,
579                      int i_port, const struct addrinfo *p_hints,
580                      struct addrinfo **res )
581 {
582     struct addrinfo hints;
583     char psz_buf[NI_MAXHOST], psz_service[6];
584
585     /*
586      * In VLC, we always use port number as integer rather than strings
587      * for historical reasons (and portability).
588      */
589     if( ( i_port > 65535 ) || ( i_port < 0 ) )
590     {
591         msg_Err( p_this, "invalid port number %d specified", i_port );
592         return EAI_SERVICE;
593     }
594
595     /* cannot overflow */
596     snprintf( psz_service, 6, "%d", i_port );
597
598     /* Check if we have to force ipv4 or ipv6 */
599     memset (&hints, 0, sizeof (hints));
600     if (p_hints != NULL)
601     {
602         const int safe_flags =
603             AI_PASSIVE |
604             AI_CANONNAME |
605             AI_NUMERICHOST |
606             AI_NUMERICSERV |
607 #ifdef AI_ALL
608             AI_ALL |
609 #endif
610 #ifdef AI_ADDRCONFIG
611             AI_ADDRCONFIG |
612 #endif
613 #ifdef AI_V4MAPPED
614             AI_V4MAPPED |
615 #endif
616             0;
617
618         hints.ai_family = p_hints->ai_family;
619         hints.ai_socktype = p_hints->ai_socktype;
620         hints.ai_protocol = p_hints->ai_protocol;
621         /* Unfortunately, some flags chang the layout of struct addrinfo, so
622          * they cannot be copied blindly from p_hints to &hints. Therefore, we
623          * only copy flags that we know for sure are "safe".
624          */
625         hints.ai_flags = p_hints->ai_flags & safe_flags;
626     }
627
628     /* We only ever use port *numbers* */
629     hints.ai_flags |= AI_NUMERICSERV;
630
631     if( hints.ai_family == AF_UNSPEC )
632     {
633 #ifdef AF_INET6
634         if (var_CreateGetBool (p_this, "ipv6"))
635             hints.ai_family = AF_INET6;
636         else
637 #endif
638         if (var_CreateGetBool (p_this, "ipv4"))
639             hints.ai_family = AF_INET;
640     }
641
642     /*
643      * VLC extensions :
644      * - accept "" as NULL
645      * - ignore square brackets
646      */
647     if (node != NULL)
648     {
649         if (node[0] == '[')
650         {
651             size_t len = strlen (node + 1);
652             if ((len <= sizeof (psz_buf)) && (node[len] == ']'))
653             {
654                 assert (len > 0);
655                 memcpy (psz_buf, node + 1, len - 1);
656                 psz_buf[len - 1] = '\0';
657                 node = psz_buf;
658             }
659         }
660         if (node[0] == '\0')
661             node = NULL;
662     }
663
664     int ret;
665     node = ToLocale (node);
666 #ifdef WIN32
667     /*
668      * Winsock tries to resolve numerical IPv4 addresses as AAAA
669      * and IPv6 addresses as A... There comes the bug-to-bug fix.
670      */
671     if ((hints.ai_flags & AI_NUMERICHOST) == 0)
672     {
673         hints.ai_flags |= AI_NUMERICHOST;
674         ret = getaddrinfo (node, psz_service, &hints, res);
675         if (ret == 0)
676             goto out;
677         hints.ai_flags &= ~AI_NUMERICHOST;
678     }
679 #endif
680 #ifdef AI_IDN
681     /* Run-time I18n Domain Names support */
682     hints.ai_flags |= AI_IDN;
683     ret = getaddrinfo (node, psz_service, &hints, res);
684     if (ret != EAI_BADFLAGS)
685         goto out;
686     /* IDN not available: disable and retry without it */
687     hints.ai_flags &= ~AI_IDN;
688 #endif
689     ret = getaddrinfo (node, psz_service, &hints, res);
690
691 out:
692     LocaleFree (node);
693     return ret;
694 }
695
696
697 void vlc_freeaddrinfo( struct addrinfo *infos )
698 {
699     freeaddrinfo (infos);
700 }
701
702 /**
703  * inet_pton() replacement
704  */
705 int vlc_inet_pton (int af, const char *src, void *dst)
706 {
707 #ifndef HAVE_INET_PTON
708     /* Windows Vista has inet_pton(), but not XP. */
709     /* We have a pretty good example of abstraction inversion here... */
710     struct addrinfo hints = {
711         .ai_family = af,
712         .ai_socktype = SOCK_DGRAM, /* make sure we have... */
713         .ai_protocol = IPPROTO_UDP, /* ...only one response */
714         .ai_flags = AI_NUMERICHOST,
715     }, *res;
716
717     if (getaddrinfo (src, NULL, &hints, &res))
718         return 0;
719
720     const void *data;
721     size_t len;
722
723     switch (af)
724     {
725         case AF_INET:
726             data = &((const struct sockaddr_in *)res->ai_addr)->sin_addr;
727             len = sizeof (struct in_addr);
728             break;
729 #ifdef AF_INET6
730         case AF_INET6:
731             data = &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
732             len = sizeof (struct in6_addr);
733             break;
734 #endif
735         default:
736             freeaddrinfo (res);
737             return -1;
738     }
739     memcpy (dst, data, len);
740     freeaddrinfo (res);
741     return 1;
742 #else /* HAVE_INET_PTON */
743     return inet_pton( af, src, dst );
744 #endif /* HAVE_INET_PTON */
745 }
746
747 /**
748  * inet_ntop() replacement
749  */
750 const char *vlc_inet_ntop (int af, const void *src, char *dst, socklen_t cnt)
751 {
752 #ifndef HAVE_INET_NTOP
753     int ret = EAI_FAMILY;
754
755     switch (af)
756     {
757 #ifdef AF_INET6
758         case AF_INET6:
759             {
760                 struct sockaddr_in6 addr;
761                 memset (&addr, 0, sizeof(addr));
762                 addr.sin6_family = AF_INET6;
763                 addr.sin6_addr = *(struct in6_addr *)src;
764                 ret = getnameinfo ((struct sockaddr *)&addr, sizeof (addr),
765                                    dst, cnt, NULL, 0, NI_NUMERICHOST);
766             }
767
768 #endif
769         case AF_INET:
770             {
771                 struct sockaddr_in addr;
772                 memset(&addr, 0, sizeof(addr));
773                 addr.sin_family = AF_INET;
774                 addr.sin_addr = *(struct in_addr *)src;
775                 ret = getnameinfo ((struct sockaddr *)&addr, sizeof (addr),
776                                    dst, cnt, NULL, 0, NI_NUMERICHOST);
777             }
778     }
779     return (ret == 0) ? dst : NULL;
780 #else /* HAVE_INET_NTOP */
781     return inet_ntop( af, src, dst, cnt );
782 #endif /* HAVE_INET_NTOP */
783 }
784