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