X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fnetwork%2Fudp.c;h=4d8ac2ebdc659e302b06ebab0e434585070a56d1;hb=7e45ab1b284217f191c35c5c2916742b4fbe39ee;hp=0b723c7f214410c0a5494f20a662011bb07fb9dc;hpb=9a5e5236beae0b8c9ff08dcecc8922ac13d54799;p=vlc diff --git a/src/network/udp.c b/src/network/udp.c index 0b723c7f21..4d8ac2ebdc 100644 --- a/src/network/udp.c +++ b/src/network/udp.c @@ -35,10 +35,6 @@ #include -#ifdef HAVE_SYS_TIME_H -# include -#endif - #include #ifdef WIN32 @@ -97,6 +93,47 @@ extern int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype, int i_protocol ); +/* */ +static int net_SetupDgramSocket( vlc_object_t *p_obj, int fd, const struct addrinfo *ptr ) +{ +#ifdef SO_REUSEPORT + setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof (int)); +#endif + +#ifdef SO_RCVBUF + /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) + * to avoid packet loss caused in case of scheduling hiccups */ + setsockopt (fd, SOL_SOCKET, SO_RCVBUF, + (void *)&(int){ 0x80000 }, sizeof (int)); + setsockopt (fd, SOL_SOCKET, SO_SNDBUF, + (void *)&(int){ 0x80000 }, sizeof (int)); +#endif + +#if defined (WIN32) || defined (UNDER_CE) + if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) + && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen)) + { + // This works for IPv4 too - don't worry! + struct sockaddr_in6 dumb = + { + .sin6_family = ptr->ai_addr->sa_family, + .sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port + }; + + bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen); + } + else +#endif + if (bind (fd, ptr->ai_addr, ptr->ai_addrlen)) + { + msg_Err( p_obj, "socket bind error (%m)" ); + net_Close (fd); + return -1; + } + return fd; +} + +/* */ static int net_ListenSingle (vlc_object_t *obj, const char *host, int port, int family, int protocol) { @@ -105,12 +142,14 @@ static int net_ListenSingle (vlc_object_t *obj, const char *host, int port, memset (&hints, 0, sizeof( hints )); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = protocol; hints.ai_flags = AI_PASSIVE; if (host && !*host) host = NULL; - msg_Dbg (obj, "net: opening %s datagram port %d", host ?: "any", port); + msg_Dbg (obj, "net: opening %s datagram port %d", + host ? host : "any", port); int val = vlc_getaddrinfo (obj, host, port, &hints, &res); if (val) @@ -125,50 +164,45 @@ static int net_ListenSingle (vlc_object_t *obj, const char *host, int port, for (const struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next) { int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype, - protocol ?: ptr->ai_protocol); + ptr->ai_protocol); if (fd == -1) { msg_Dbg (obj, "socket error: %m"); continue; } - if (ptr->ai_next != NULL) - { #ifdef IPV6_V6ONLY - if ((ptr->ai_family != AF_INET6) - || setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, &(int){ 0 }, - sizeof (int))) -#endif - { - msg_Err (obj, "Multiple network protocols present"); - msg_Err (obj, "Please select network protocol manually"); - } + /* If IPv6 was forced, set IPv6-only mode. + * If IPv4 was forced, do nothing extraordinary. + * If nothing was forced, try dual-mode IPv6. */ + if (ptr->ai_family == AF_INET6) + { + int on = (family == AF_INET6); + setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, &on, sizeof (on)); } - - setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &(int){ 0x80000 }, sizeof (int)); - setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &(int){ 0x80000 }, sizeof (int)); - setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, sizeof (int)); - - /* Bind the socket */ -#if defined (WIN32) || defined (UNDER_CE) - if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) - && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen)) + else if (ptr->ai_family == AF_INET && family == AF_UNSPEC) { - struct sockaddr_in6 dumb = - { - .sin6_family = ptr->ai_addr->sa_family, - .sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port - }; - bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen); + for (const struct addrinfo *p = ptr; p != NULL; p = p->ai_next) + if (p->ai_family == AF_INET6) + { + net_Close (fd); + fd = -1; + break; + } + if (fd == -1) + continue; } - else -#endif - if (bind (fd, ptr->ai_addr, ptr->ai_addrlen)) +#else + if (family == AF_UNSPEC && ptr->ai_next != NULL) { - msg_Err (obj, "socket bind error (%m)"); - net_Close (fd); - continue; + msg_Warn (obj, "ambiguous network protocol specification"); + msg_Warn (obj, "please select IP version explicitly"); } +#endif + + fd = net_SetupDgramSocket( obj, fd, ptr ); + if( fd == -1 ) + continue; if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) && net_Subscribe (obj, fd, ptr->ai_addr, ptr->ai_addrlen)) @@ -608,25 +642,26 @@ static int net_SetDSCP( int fd, uint8_t dscp ) return setsockopt( fd, level, cmd, &(int){ dscp }, sizeof (int)); } - +#undef net_ConnectDgram /***************************************************************************** - * __net_ConnectDgram: + * net_ConnectDgram: ***************************************************************************** * Open a datagram socket to send data to a defined destination, with an * optional hop limit. *****************************************************************************/ -int __net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port, - int i_hlim, int proto ) +int net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port, + int i_hlim, int proto ) { struct addrinfo hints, *res, *ptr; int i_val, i_handle = -1; bool b_unreach = false; - if( i_hlim < 1 ) + if( i_hlim < 0 ) i_hlim = var_CreateGetInteger( p_this, "ttl" ); memset( &hints, 0, sizeof( hints ) ); hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = proto; msg_Dbg( p_this, "net: connecting to [%s]:%d", psz_host, i_port ); @@ -642,7 +677,7 @@ int __net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port, { char *str; int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype, - proto ?: ptr->ai_protocol); + ptr->ai_protocol); if (fd == -1) continue; @@ -656,7 +691,7 @@ int __net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port, setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, sizeof (int)); #endif - if( i_hlim > 0 ) + if( i_hlim >= 0 ) net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim ); str = var_CreateGetNonEmptyString (p_this, "miface"); @@ -709,15 +744,15 @@ int __net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port, return i_handle; } - +#undef net_OpenDgram /***************************************************************************** - * __net_OpenDgram: + * net_OpenDgram: ***************************************************************************** * OpenDgram a datagram socket and return a handle *****************************************************************************/ -int __net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind, - const char *psz_server, int i_server, - int family, int protocol ) +int net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind, + const char *psz_server, int i_server, + int family, int protocol ) { if ((psz_server == NULL) || (psz_server[0] == '\0')) return net_ListenSingle (obj, psz_bind, i_bind, family, protocol); @@ -731,6 +766,7 @@ int __net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind, memset (&hints, 0, sizeof (hints)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = protocol; val = vlc_getaddrinfo (obj, psz_server, i_server, &hints, &rem); if (val) @@ -753,43 +789,13 @@ int __net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind, for (struct addrinfo *ptr = loc; ptr != NULL; ptr = ptr->ai_next) { int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype, - protocol ?: ptr->ai_protocol); + ptr->ai_protocol); if (fd == -1) continue; // usually, address family not supported -#ifdef SO_REUSEPORT - setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof (int)); -#endif - -#ifdef SO_RCVBUF - /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) - * to avoid packet loss caused in case of scheduling hiccups */ - setsockopt (fd, SOL_SOCKET, SO_RCVBUF, - (void *)&(int){ 0x80000 }, sizeof (int)); - setsockopt (fd, SOL_SOCKET, SO_SNDBUF, - (void *)&(int){ 0x80000 }, sizeof (int)); -#endif - -#if defined (WIN32) || defined (UNDER_CE) - if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) - && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen)) - { - // This works for IPv4 too - don't worry! - struct sockaddr_in6 dumb = - { - .sin6_family = ptr->ai_addr->sa_family, - .sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port - }; - - bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen); - } - else -#endif - if (bind (fd, ptr->ai_addr, ptr->ai_addrlen)) - { - net_Close (fd); + fd = net_SetupDgramSocket( obj, fd, ptr ); + if( fd == -1 ) continue; - } val = -1; for (struct addrinfo *ptr2 = rem; ptr2 != NULL; ptr2 = ptr2->ai_next) @@ -816,7 +822,7 @@ int __net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind, if (val != -1) break; - close (fd); + net_Close (fd); } vlc_freeaddrinfo (rem);