]> git.sesse.net Git - vlc/blobdiff - src/network/udp.c
Fix and revive the net_OpenUDP warning
[vlc] / src / network / udp.c
index 2dc30fafa2c73f70b48a8ecf3e0dcffac8aa8535..61eb2722f2e08c48679fd586ace930c3aa99e3e6 100644 (file)
@@ -1,7 +1,9 @@
 /*****************************************************************************
  * udp.c:
  *****************************************************************************
- * Copyright (C) 2004-2005 the VideoLAN team
+ * Copyright (C) 2004-2006 the VideoLAN team
+ * Copyright © 2006 Rémi Denis-Courmont
+ *
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@videolan.org>
@@ -19,7 +21,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
 
 #include <errno.h>
 
-#ifdef HAVE_FCNTL_H
-#   include <fcntl.h>
-#endif
 #ifdef HAVE_SYS_TIME_H
 #    include <sys/time.h>
 #endif
-#ifdef HAVE_UNISTD_H
-#   include <unistd.h>
-#endif
 
 #include "network.h"
 
 #       define IP_ADD_MEMBERSHIP 5
 #   endif
 #   define EAFNOSUPPORT WSAEAFNOSUPPORT
+#   define if_nametoindex( str ) atoi( str )
+#else
+#   include <unistd.h>
+#   ifdef HAVE_NET_IF_H
+#       include <net/if.h>
+#   endif
 #endif
 
 #ifndef SOL_IP
@@ -109,45 +111,117 @@ static int net_SetMcastHopLimit( vlc_object_t *p_this,
 }
 
 
-static int net_SetMcastSource( vlc_object_t *p_this,
-                                int fd, int family, const char *str )
+static int net_SetMcastOutIface (int fd, int family, int scope)
 {
-#ifndef SYS_BEOS
-    switch( family )
+    switch (family)
     {
+#ifdef IPV6_MULTICAST_IF
+        case AF_INET6:
+            return setsockopt (fd, SOL_IPV6, IPV6_MULTICAST_IF,
+                               &scope, sizeof (scope));
+#endif
+
+#ifdef __linux__
         case AF_INET:
         {
-            struct in_addr addr;
+            struct ip_mreqn req = { .imr_ifindex = scope };
+
+            return setsockopt (fd, SOL_IP, IP_MULTICAST_IF, &req,
+                               sizeof (req));
+        }
+#endif
+    }
+
+    errno = EAFNOSUPPORT;
+    return -1;
+}
+
+
+static inline int net_SetMcastOutIPv4 (int fd, struct in_addr ipv4)
+{
+#ifdef IP_MULTICAST_IF
+    return setsockopt( fd, SOL_IP, IP_MULTICAST_IF, &ipv4, sizeof (ipv4));
+#else
+    errno = EAFNOSUPPORT;
+    return -1;
+#endif
+}
 
-            if( inet_pton( AF_INET, str, &addr) <= 0 )
-            {
-                msg_Err( p_this, "Invalid multicast interface %s",
-                         str );
-                return VLC_EGENERIC;
-            }
 
-            if( setsockopt( fd, IPPROTO_IP, IP_MULTICAST_IF, &addr,
-                            sizeof( addr ) ) < 0 )
+static int net_SetMcastOut (vlc_object_t *p_this, int fd, int family,
+                            const char *iface, const char *addr)
+{
+    if (iface != NULL)
+    {
+        int scope = if_nametoindex (iface);
+        if (scope == 0)
+        {
+            msg_Err (p_this, "%s: invalid interface for multicast", iface);
+            return -1;
+        }
+
+        if (net_SetMcastOutIface (fd, family, scope) == 0)
+            return 0;
+
+        msg_Err (p_this, "%s: %s", iface, net_strerror (net_errno));
+    }
+
+    if (addr != NULL)
+    {
+        if (family == AF_INET)
+        {
+            struct in_addr ipv4;
+            if (inet_pton (AF_INET, addr, &ipv4) <= 0)
             {
-                msg_Dbg( p_this, "Cannot set multicast interface (%s)",
-                         strerror(errno) );
-                return VLC_EGENERIC;
+                msg_Err (p_this, "%s: invalid IPv4 address for multicast",
+                         addr);
+                return -1;
             }
-            break;
+
+            if (net_SetMcastOutIPv4 (fd, ipv4) == 0)
+                return 0;
+
+            msg_Err (p_this, "%s: %s", addr, net_strerror (net_errno));
         }
+    }
 
-#ifdef IPV6_MULTICAST_IF
-/* FIXME: TODO */
+    return -1;
+}
+
+
+int net_SetDSCP( int fd, uint8_t dscp )
+{
+    struct sockaddr_storage addr;
+    if( getsockname( fd, (struct sockaddr *)&addr, &(socklen_t){ sizeof (addr) }) )
+        return -1;
+
+    int level, cmd;
+
+    switch( addr.ss_family )
+    {
+#ifdef IPV6_TCLASS
+        case AF_INET6:
+            level = SOL_IPV6;
+            cmd = IPV6_TCLASS;
+            break;
 #endif
+
+        case AF_INET:
+            level = SOL_IP;
+            cmd = IP_TOS;
+            break;
+
         default:
-            msg_Warn( p_this, "%s", strerror( EAFNOSUPPORT ) );
-            return VLC_EGENERIC;
+#ifdef ENOPROTOOPT
+            errno = ENOPROTOOPT;
+#endif
+            return -1;
     }
 
-#endif
-    return VLC_SUCCESS;
+    return setsockopt( fd, level, cmd, &(int){ dscp }, sizeof (int));
 }
 
+
 /*****************************************************************************
  * __net_ConnectUDP:
  *****************************************************************************
@@ -182,43 +256,41 @@ int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port,
 
     for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
     {
-        int fd;
-        char *psz_mif_addr;
-
-        fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
-                         ptr->ai_protocol );
-        if( fd == -1 )
+        char *str;
+        int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
+                             ptr->ai_protocol);
+        if (fd == -1)
             continue;
+
 #if !defined( SYS_BEOS )
-        else
-        {
-            int i_val;
-
-            /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s)
-             * to avoid packet loss caused by scheduling problems */
-            i_val = 0x80000;
-            setsockopt( fd, SOL_SOCKET, SO_RCVBUF, (void *)&i_val,
-                        sizeof( i_val ) );
-            i_val = 0x80000;
-            setsockopt( fd, SOL_SOCKET, SO_SNDBUF, (void *)&i_val,
-                        sizeof( i_val ) );
-
-            /* Allow broadcast sending */
-            i_val = 1;
-            setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST, (void*)&i_val,
-                        sizeof( i_val ) );
-        }
+        /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s)
+        * to avoid packet loss caused by scheduling problems */
+        setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &(int){ 0x80000 }, sizeof (int));
+        setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &(int){ 0x80000 }, sizeof (int));
+
+        /* Allow broadcast sending */
+        setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, sizeof (int));
 #endif
 
-        if( hlim > 0 )
+        if( i_hlim > 0 )
             net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim );
-        psz_mif_addr = config_GetPsz( p_this, "miface-addr" );
-        if( psz_mif_addr != NULL )
+
+        str = var_CreateGetString (p_this, "miface");
+        if (str != NULL)
         {
-            net_SetMcastSource( p_this, fd, ptr->ai_family, psz_mif_addr );
-            free( psz_mif_addr );
+            net_SetMcastOut (p_this, fd, ptr->ai_family, str, NULL);
+            free (str);
         }
 
+        str = var_CreateGetString (p_this, "miface-addr");
+        if (str != NULL)
+        {
+            net_SetMcastOut (p_this, fd, ptr->ai_family, NULL, str);
+            free (str);
+        }
+
+        net_SetDSCP (fd, var_CreateGetInteger (p_this, "dscp"));
+
         if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
         {
             /* success */
@@ -267,12 +339,17 @@ int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
     network_socket_t sock;
     module_t         *p_network = NULL;
 
-    if( ( psz_server != NULL ) && ( psz_server[0] == '\0' ) )
-        msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
-                  "is obsolete - use net_ConnectUDP instead" );
-    if( i_server != 0 )
-        msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
-                  "port is obsolete - use __net_ConnectUDP instead" );
+    if (((psz_bind == NULL) || (psz_bind[0] == '\0')) && (i_bind == 0))
+        msg_Warn (p_this,
+                  "Obsolete net_OpenUDP with no local endpoint; "
+                  "Use net_ConnectUDP instead");
+
+#if 0
+    if (((psz_server == NULL) || (psz_server[0] == '\0')) && (i_server == 0))
+        msg_Warn (p_this,
+                  "Obsolete net_OpenUDP with no remote endpoint; "
+                  "Use net_ListenUDP instead");
+#endif
 
     if( psz_server == NULL ) psz_server = "";
     if( psz_bind == NULL ) psz_bind = "";
@@ -338,8 +415,8 @@ int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
         {
             if( sock.i_handle != -1 )
             {
-                msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
-                                  "Using only IPv4." );
+                msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present, "
+                                  "using only IPv4." );
                 net_Close( fd6 );
             }
             else