00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <vlc/vlc.h>
00026
00027 #include <stddef.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <errno.h>
00031
00032 #ifdef HAVE_SYS_TYPES_H
00033 # include <sys/types.h>
00034 #endif
00035 #ifdef HAVE_ARPA_INET_H
00036 # include <arpa/inet.h>
00037 #endif
00038 #ifdef HAVE_NETINET_IN_H
00039 # include <netinet/in.h>
00040 #endif
00041 #ifdef HAVE_UNISTD_H
00042 # include <unistd.h>
00043 #endif
00044
00045 #include "network.h"
00046
00047 #ifndef NO_ADDRESS
00048 # define NO_ADDRESS NO_DATA
00049 #endif
00050 #ifndef INADDR_NONE
00051 # define INADDR_NONE 0xFFFFFFFF
00052 #endif
00053 #ifndef AF_UNSPEC
00054 # define AF_UNSPEC 0
00055 #endif
00056
00057 #define _NI_MASK (NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|\
00058 NI_DGRAM)
00059 #define _AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
00060
00061
00062 #ifndef HAVE_GAI_STRERROR
00063 static struct
00064 {
00065 int code;
00066 const char *msg;
00067 } const __gai_errlist[] =
00068 {
00069 { 0, "Error 0" },
00070 { EAI_BADFLAGS, "Invalid flag used" },
00071 { EAI_NONAME, "Host or service not found" },
00072 { EAI_AGAIN, "Temporary name service failure" },
00073 { EAI_FAIL, "Non-recoverable name service failure" },
00074 { EAI_NODATA, "No data for host name" },
00075 { EAI_FAMILY, "Unsupported address family" },
00076 { EAI_SOCKTYPE, "Unsupported socket type" },
00077 { EAI_SERVICE, "Incompatible service for socket type" },
00078 { EAI_ADDRFAMILY, "Unavailable address family for host name" },
00079 { EAI_MEMORY, "Memory allocation failure" },
00080 { EAI_SYSTEM, "System error" },
00081 { 0, NULL }
00082 };
00083
00084 static const char *__gai_unknownerr = "Unrecognized error number";
00085
00086
00087
00088
00089 const char *vlc_gai_strerror( int errnum )
00090 {
00091 int i;
00092
00093 for (i = 0; __gai_errlist[i].msg != NULL; i++)
00094 if (errnum == __gai_errlist[i].code)
00095 return __gai_errlist[i].msg;
00096
00097 return __gai_unknownerr;
00098 }
00099 # undef _EAI_POSITIVE_MAX
00100 #else
00101 const char *vlc_gai_strerror( int errnum )
00102 {
00103 return gai_strerror( errnum );
00104 }
00105 #endif
00106
00107 #if !(defined (HAVE_GETNAMEINFO) && defined (HAVE_GETADDRINFO))
00108
00109
00110
00111
00112 static int
00113 gai_error_from_herrno( void )
00114 {
00115 switch(h_errno)
00116 {
00117 case HOST_NOT_FOUND:
00118 return EAI_NONAME;
00119
00120 case NO_ADDRESS:
00121 # if (NO_ADDRESS != NO_DATA)
00122 case NO_DATA:
00123 # endif
00124 return EAI_NODATA;
00125
00126 case NO_RECOVERY:
00127 return EAI_FAIL;
00128
00129 case TRY_AGAIN:
00130 return EAI_AGAIN;
00131 }
00132 return EAI_SYSTEM;
00133 }
00134 #endif
00135
00136 #ifndef HAVE_GETNAMEINFO
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 static int
00150 __getnameinfo( const struct sockaddr *sa, socklen_t salen,
00151 char *host, int hostlen, char *serv, int servlen, int flags )
00152 {
00153 if (((unsigned)salen < sizeof (struct sockaddr_in))
00154 || (sa->sa_family != AF_INET))
00155 return EAI_FAMILY;
00156 else if (flags & (~_NI_MASK))
00157 return EAI_BADFLAGS;
00158 else
00159 {
00160 const struct sockaddr_in *addr;
00161
00162 addr = (const struct sockaddr_in *)sa;
00163
00164 if (host != NULL)
00165 {
00166 int solved = 0;
00167
00168
00169 if (!(flags & NI_NUMERICHOST))
00170 {
00171 struct hostent *hent;
00172
00173 hent = gethostbyaddr ((const void*)&addr->sin_addr,
00174 4, AF_INET);
00175
00176 if (hent != NULL)
00177 {
00178 strncpy (host, hent->h_name, hostlen);
00179 host[hostlen - 1] = '\0';
00180
00181
00182
00183
00184
00185
00186 if (flags & NI_NOFQDN)
00187 {
00188 char *ptr;
00189
00190 ptr = strchr (host, '.');
00191 if (ptr != NULL)
00192 *ptr = 0;
00193 }
00194
00195 solved = 1;
00196 }
00197 else if (flags & NI_NAMEREQD)
00198 return gai_error_from_herrno ();
00199 }
00200
00201 if (!solved)
00202 {
00203
00204 strncpy (host, inet_ntoa (addr->sin_addr), hostlen);
00205 host[hostlen - 1] = '\0';
00206 }
00207 }
00208
00209 if (serv != NULL)
00210 {
00211 struct servent *sent = NULL;
00212
00213 #ifndef SYS_BEOS
00214 int solved = 0;
00215
00216
00217 if (!(flags & NI_NUMERICSERV))
00218 {
00219
00220 sent = getservbyport(addr->sin_port,
00221 (flags & NI_DGRAM)
00222 ? "udp" : "tcp");
00223 if (sent != NULL)
00224 {
00225 strncpy (serv, sent->s_name, servlen);
00226 serv[servlen - 1] = 0;
00227 solved = 1;
00228 }
00229 }
00230 #else
00231 sent = NULL;
00232 #endif
00233 if (sent == NULL)
00234 {
00235 snprintf (serv, servlen, "%u",
00236 (unsigned int)ntohs (addr->sin_port));
00237 serv[servlen - 1] = '\0';
00238 }
00239 }
00240 }
00241 return 0;
00242 }
00243
00244 #endif
00245
00246
00247 #ifndef HAVE_GETADDRINFO
00248
00249
00250
00251 static void
00252 __freeaddrinfo (struct addrinfo *res)
00253 {
00254 if (res != NULL)
00255 {
00256 if (res->ai_canonname != NULL)
00257 free (res->ai_canonname);
00258 if (res->ai_addr != NULL)
00259 free (res->ai_addr);
00260 if (res->ai_next != NULL)
00261 free (res->ai_next);
00262 free (res);
00263 }
00264 }
00265
00266
00267
00268
00269
00270 static struct addrinfo *
00271 makeaddrinfo (int af, int type, int proto,
00272 const struct sockaddr *addr, size_t addrlen,
00273 const char *canonname)
00274 {
00275 struct addrinfo *res;
00276
00277 res = (struct addrinfo *)malloc (sizeof (struct addrinfo));
00278 if (res != NULL)
00279 {
00280 res->ai_flags = 0;
00281 res->ai_family = af;
00282 res->ai_socktype = type;
00283 res->ai_protocol = proto;
00284 res->ai_addrlen = addrlen;
00285 res->ai_addr = malloc (addrlen);
00286 res->ai_canonname = NULL;
00287 res->ai_next = NULL;
00288
00289 if (res->ai_addr != NULL)
00290 {
00291 memcpy (res->ai_addr, addr, addrlen);
00292
00293 if (canonname != NULL)
00294 {
00295 res->ai_canonname = strdup (canonname);
00296 if (res->ai_canonname != NULL)
00297 return res;
00298 }
00299 else
00300 return res;
00301 }
00302 }
00303
00304 vlc_freeaddrinfo (res);
00305 return NULL;
00306 }
00307
00308
00309 static struct addrinfo *
00310 makeipv4info (int type, int proto, u_long ip, u_short port, const char *name)
00311 {
00312 struct sockaddr_in addr;
00313
00314 memset (&addr, 0, sizeof (addr));
00315 addr.sin_family = AF_INET;
00316 # ifdef HAVE_SA_LEN
00317 addr.sin_len = sizeof (addr);
00318 # endif
00319 addr.sin_port = port;
00320 addr.sin_addr.s_addr = ip;
00321
00322 return makeaddrinfo (AF_INET, type, proto,
00323 (struct sockaddr*)&addr, sizeof (addr), name);
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 static int
00337 __getaddrinfo (const char *node, const char *service,
00338 const struct addrinfo *hints, struct addrinfo **res)
00339 {
00340 struct addrinfo *info;
00341 u_long ip;
00342 u_short port;
00343 int protocol = 0, flags = 0;
00344 const char *name = NULL;
00345
00346 if (hints != NULL)
00347 {
00348 flags = hints->ai_flags;
00349
00350 if (flags & ~_AI_MASK)
00351 return EAI_BADFLAGS;
00352
00353 if (hints->ai_family && (hints->ai_family != AF_INET))
00354 return EAI_FAMILY;
00355
00356
00357 switch (hints->ai_socktype)
00358 {
00359 case SOCK_STREAM:
00360 protocol = IPPROTO_TCP;
00361 break;
00362
00363 case SOCK_DGRAM:
00364 protocol = IPPROTO_UDP;
00365 break;
00366
00367 #ifndef SYS_BEOS
00368 case SOCK_RAW:
00369 #endif
00370 case 0:
00371 break;
00372
00373 default:
00374 return EAI_SOCKTYPE;
00375 }
00376 if (hints->ai_protocol && protocol
00377 && (protocol != hints->ai_protocol))
00378 return EAI_SERVICE;
00379 }
00380
00381 *res = NULL;
00382
00383
00384 if (node == NULL)
00385 {
00386 if (flags & AI_PASSIVE)
00387 ip = htonl (INADDR_ANY);
00388 else
00389 ip = htonl (INADDR_LOOPBACK);
00390 }
00391 else
00392 if ((ip = inet_addr (node)) == INADDR_NONE)
00393 {
00394 struct hostent *entry = NULL;
00395
00396
00397 if (!(flags & AI_NUMERICHOST))
00398 entry = gethostbyname (node);
00399
00400 if (entry == NULL)
00401 return EAI_NONAME;
00402
00403 if ((entry->h_length != 4) || (entry->h_addrtype != AF_INET))
00404 return EAI_FAMILY;
00405
00406 ip = *((u_long *) entry->h_addr);
00407 if (flags & AI_CANONNAME)
00408 name = entry->h_name;
00409 }
00410
00411 if ((flags & AI_CANONNAME) && (name == NULL))
00412 name = node;
00413
00414
00415 if (service == NULL)
00416 port = 0;
00417 else
00418 {
00419 long d;
00420 char *end;
00421
00422 d = strtoul (service, &end, 0);
00423 if (end[0]
00424 || (d > 65535))
00425 {
00426 struct servent *entry;
00427 const char *protoname;
00428
00429 switch (protocol)
00430 {
00431 case IPPROTO_TCP:
00432 protoname = "tcp";
00433 break;
00434
00435 case IPPROTO_UDP:
00436 protoname = "udp";
00437 break;
00438
00439 default:
00440 protoname = NULL;
00441 }
00442
00443 entry = getservbyname (service, protoname);
00444 if (entry == NULL)
00445 return EAI_SERVICE;
00446
00447 port = entry->s_port;
00448 }
00449 else
00450 port = htons ((u_short)d);
00451 }
00452
00453
00454 if ((!protocol) || (protocol == IPPROTO_UDP))
00455 {
00456 info = makeipv4info (SOCK_DGRAM, IPPROTO_UDP, ip, port, name);
00457 if (info == NULL)
00458 {
00459 errno = ENOMEM;
00460 return EAI_SYSTEM;
00461 }
00462 if (flags & AI_PASSIVE)
00463 info->ai_flags |= AI_PASSIVE;
00464 *res = info;
00465 }
00466 if ((!protocol) || (protocol == IPPROTO_TCP))
00467 {
00468 info = makeipv4info (SOCK_STREAM, IPPROTO_TCP, ip, port, name);
00469 if (info == NULL)
00470 {
00471 errno = ENOMEM;
00472 return EAI_SYSTEM;
00473 }
00474 info->ai_next = *res;
00475 if (flags & AI_PASSIVE)
00476 info->ai_flags |= AI_PASSIVE;
00477 *res = info;
00478 }
00479
00480 return 0;
00481 }
00482 #endif
00483
00484
00485 int vlc_getnameinfo( const struct sockaddr *sa, int salen,
00486 char *host, int hostlen, int *portnum, int flags )
00487 {
00488 char psz_servbuf[6], *psz_serv;
00489 int i_servlen, i_val;
00490 #if defined( WIN32 ) && !defined( UNDER_CE )
00491
00492
00493
00494
00495 typedef int (CALLBACK * GETNAMEINFO) ( const struct sockaddr*, socklen_t,
00496 char*, DWORD, char*, DWORD, int );
00497 HINSTANCE wship6_module;
00498 GETNAMEINFO ws2_getnameinfo;
00499 #endif
00500
00501 flags |= NI_NUMERICSERV;
00502 if( portnum != NULL )
00503 {
00504 psz_serv = psz_servbuf;
00505 i_servlen = sizeof( psz_servbuf );
00506 }
00507 else
00508 {
00509 psz_serv = NULL;
00510 i_servlen = 0;
00511 }
00512 #if defined( WIN32 ) && !defined( UNDER_CE )
00513 wship6_module = LoadLibrary( "wship6.dll" );
00514 if( wship6_module != NULL )
00515 {
00516 ws2_getnameinfo = (GETNAMEINFO)GetProcAddress( wship6_module,
00517 "getnameinfo" );
00518
00519 if( ws2_getnameinfo != NULL )
00520 {
00521 i_val = ws2_getnameinfo( sa, salen, host, hostlen, psz_serv,
00522 i_servlen, flags );
00523 FreeLibrary( wship6_module );
00524
00525 if( portnum != NULL )
00526 *portnum = atoi( psz_serv );
00527 return i_val;
00528 }
00529
00530 FreeLibrary( wship6_module );
00531 }
00532 #endif
00533 #if defined( HAVE_GETNAMEINFO ) || defined( UNDER_CE )
00534 i_val = getnameinfo(sa, salen, host, hostlen, psz_serv, i_servlen, flags);
00535 #else
00536 {
00537 # ifdef HAVE_USABLE_MUTEX_THAT_DONT_NEED_LIBVLC_POINTER
00538 static vlc_value_t lock;
00539
00540
00541
00542 vlc_mutex_lock( lock.p_address );
00543 #else
00544
00545 #endif
00546 i_val = __getnameinfo( sa, salen, host, hostlen, psz_serv, i_servlen,
00547 flags );
00548 # ifdef HAVE_USABLE_MUTEX_THAT_DONT_NEED_LIBVLC_POINTER
00549 vlc_mutex_unlock( lock.p_address );
00550 # endif
00551 }
00552 #endif
00553
00554 if( portnum != NULL )
00555 *portnum = atoi( psz_serv );
00556
00557 return i_val;
00558 }
00559
00560
00561
00562 int vlc_getaddrinfo( vlc_object_t *p_this, const char *node,
00563 int i_port, const struct addrinfo *p_hints,
00564 struct addrinfo **res )
00565 {
00566 struct addrinfo hints;
00567 char psz_buf[NI_MAXHOST], *psz_node, psz_service[6];
00568
00569
00570
00571
00572
00573 if( ( i_port > 65535 ) || ( i_port < 0 ) )
00574 {
00575 msg_Err( p_this, "invalid port number %d specified", i_port );
00576 return EAI_SERVICE;
00577 }
00578
00579
00580 snprintf( psz_service, 6, "%d", i_port );
00581
00582
00583 if( p_hints == NULL )
00584 memset( &hints, 0, sizeof( hints ) );
00585 else
00586 memcpy( &hints, p_hints, sizeof( hints ) );
00587
00588 if( hints.ai_family == AF_UNSPEC )
00589 {
00590 vlc_value_t val;
00591
00592 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00593 var_Get( p_this, "ipv4", &val );
00594 if( val.b_bool )
00595 hints.ai_family = AF_INET;
00596
00597 #ifdef AF_INET6
00598 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00599 var_Get( p_this, "ipv6", &val );
00600 if( val.b_bool )
00601 hints.ai_family = AF_INET6;
00602 #endif
00603 }
00604
00605
00606
00607
00608
00609
00610 if( ( node == NULL ) || (node[0] == '\0' ) )
00611 {
00612 psz_node = NULL;
00613 }
00614 else
00615 {
00616 strncpy( psz_buf, node, NI_MAXHOST );
00617 psz_buf[NI_MAXHOST - 1] = '\0';
00618
00619 psz_node = psz_buf;
00620
00621 if( psz_buf[0] == '[' )
00622 {
00623 char *ptr;
00624
00625 ptr = strrchr( psz_buf, ']' );
00626 if( ( ptr != NULL ) && (ptr[1] == '\0' ) )
00627 {
00628 *ptr = '\0';
00629 psz_node++;
00630 }
00631 }
00632 }
00633
00634 #if defined( WIN32 ) && !defined( UNDER_CE )
00635 {
00636 typedef int (CALLBACK * GETADDRINFO) ( const char *, const char *,
00637 const struct addrinfo *,
00638 struct addrinfo ** );
00639 HINSTANCE wship6_module;
00640 GETADDRINFO ws2_getaddrinfo;
00641
00642 wship6_module = LoadLibrary( "wship6.dll" );
00643 if( wship6_module != NULL )
00644 {
00645 ws2_getaddrinfo = (GETADDRINFO)GetProcAddress( wship6_module,
00646 "getaddrinfo" );
00647
00648 if( ws2_getaddrinfo != NULL )
00649 {
00650 int i_ret;
00651
00652 i_ret = ws2_getaddrinfo( psz_node, psz_service, &hints, res );
00653 FreeLibrary( wship6_module );
00654 return i_ret;
00655 }
00656
00657 FreeLibrary( wship6_module );
00658 }
00659 }
00660 #endif
00661 #if defined( HAVE_GETADDRINFO ) || defined( UNDER_CE )
00662 # ifdef AI_IDN
00663
00664 {
00665 static vlc_bool_t i_idn = VLC_TRUE;
00666
00667 if( i_idn )
00668 {
00669 int i_ret;
00670
00671 hints.ai_flags |= AI_IDN;
00672 i_ret = getaddrinfo( psz_node, psz_service, &hints, res );
00673
00674 if( i_ret != EAI_BADFLAGS )
00675 return i_ret;
00676
00677
00678
00679
00680 hints.ai_flags &= ~AI_IDN;
00681 i_idn = VLC_FALSE;
00682 msg_Dbg( p_this, "I18n Domain Names not supported - disabled" );
00683 }
00684 }
00685 # endif
00686 return getaddrinfo( psz_node, psz_service, &hints, res );
00687 #else
00688 {
00689 int i_ret;
00690
00691 vlc_value_t lock;
00692
00693 var_Create( p_this->p_libvlc, "getaddrinfo_mutex", VLC_VAR_MUTEX );
00694 var_Get( p_this->p_libvlc, "getaddrinfo_mutex", &lock );
00695 vlc_mutex_lock( lock.p_address );
00696
00697 i_ret = __getaddrinfo( psz_node, psz_service, &hints, res );
00698 vlc_mutex_unlock( lock.p_address );
00699 return i_ret;
00700 }
00701 #endif
00702 }
00703
00704
00705 void vlc_freeaddrinfo( struct addrinfo *infos )
00706 {
00707 #if defined( WIN32 ) && !defined( UNDER_CE )
00708 typedef void (CALLBACK * FREEADDRINFO) ( struct addrinfo * );
00709 HINSTANCE wship6_module;
00710 FREEADDRINFO ws2_freeaddrinfo;
00711
00712 wship6_module = LoadLibrary( "wship6.dll" );
00713 if( wship6_module != NULL )
00714 {
00715 ws2_freeaddrinfo = (FREEADDRINFO)GetProcAddress( wship6_module,
00716 "freeaddrinfo" );
00717
00718
00719
00720
00721
00722 if( ws2_freeaddrinfo != NULL )
00723 {
00724 ws2_freeaddrinfo( infos );
00725 FreeLibrary( wship6_module );
00726 return;
00727 }
00728
00729 FreeLibrary( wship6_module );
00730 }
00731 #endif
00732 #if defined( HAVE_GETADDRINFO ) || defined( UNDER_CE )
00733 freeaddrinfo( infos );
00734 #else
00735 __freeaddrinfo( infos );
00736 #endif
00737 }