]> git.sesse.net Git - vlc/blobdiff - src/misc/net.c
implement net_ConnectUDP() (yet to be used) to create a connected UDP socket,
[vlc] / src / misc / net.c
index 481401f9fb76383a12f08f316de41ba82f610cce..7106c08dad23e4ca03eeb097e1f8e7e1cb8d1cb5 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * net.c:
  *****************************************************************************
- * Copyright (C) 2004-2005 VideoLAN
+ * Copyright (C) 2004-2005 the VideoLAN team
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@videolan.org>
 #ifdef HAVE_FCNTL_H
 #   include <fcntl.h>
 #endif
-
 #ifdef HAVE_SYS_TIME_H
 #    include <sys/time.h>
 #endif
-
-#if defined( WIN32 ) || defined( UNDER_CE )
-#   if defined(UNDER_CE) && defined(sockaddr_storage)
-#       undef sockaddr_storage
-#   endif
-#   include <winsock2.h>
-#   include <ws2tcpip.h>
-#else
-#   include <sys/socket.h>
-#   include <netinet/in.h>
-#   ifdef HAVE_ARPA_INET_H
-#       include <arpa/inet.h>
-#   endif
-#   include <netdb.h>
-#endif
-
 #ifdef HAVE_UNISTD_H
 #   include <unistd.h>
 #endif
@@ -82,11 +65,13 @@ static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
     if( fd == -1 )
     {
 #if defined(WIN32) || defined(UNDER_CE)
-        msg_Warn( p_this, "cannot create socket (%i)",
-                  WSAGetLastError() );
+        if( WSAGetLastError ( ) != WSAEAFNOSUPPORT )
+            msg_Warn( p_this, "cannot create socket (%i)",
+                      WSAGetLastError() );
 #else
-        msg_Warn( p_this, "cannot create socket (%s)",
-                  strerror( errno ) );
+        if( errno != EAFNOSUPPORT )
+            msg_Warn( p_this, "cannot create socket (%s)",
+                      strerror( errno ) );
 #endif
         return -1;
     }
@@ -124,31 +109,31 @@ static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
 #endif
 
 #if defined( WIN32 ) || defined( UNDER_CE )
-# ifdef IPV6_PROTECTION_LEVEL
+# ifndef IPV6_PROTECTION_LEVEL
+#  define IPV6_PROTECTION_LEVEL 23
+# endif
     if( i_family == AF_INET6 )
     {
-        i_val = PROTECTION_LEVEL_UNRESTRICTED;
-        setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
-                    sizeof( i_val ) );
+        i_val = 30 /*PROTECTION_LEVEL_UNRESTRICTED*/;
+        setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
+                   (const char*)&i_val, sizeof( i_val ) );
     }
-# else
-# warning You are using outdated headers for Winsock !
-# endif
 #endif
     return fd;
 }
 
 /*****************************************************************************
- * __net_OpenTCP:
+ * __net_ConnectTCP:
  *****************************************************************************
  * Open a TCP connection and return a handle
  *****************************************************************************/
-int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
+int __net_ConnectTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
 {
     struct addrinfo hints, *res, *ptr;
     const char      *psz_realhost;
     char            *psz_socks;
     int             i_realport, i_val, i_handle = -1;
+    vlc_bool_t      b_unreach = VLC_FALSE;
 
     if( i_port == 0 )
         i_port = 80; /* historical VLC thing */
@@ -167,7 +152,7 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
         psz_realhost = psz_socks;
         i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
 
-        msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'",
+        msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d",
                  psz_realhost, i_realport, psz_host, i_port );
     }
     else
@@ -175,14 +160,14 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
         psz_realhost = psz_host;
         i_realport = i_port;
 
-        msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_realhost,
+        msg_Dbg( p_this, "net: connecting to %s port %d", psz_realhost,
                  i_realport );
     }
 
     i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
     if( i_val )
     {
-        msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_realhost,
+        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
                  i_realport, vlc_gai_strerror( i_val ) );
         free( psz_socks );
         return -1;
@@ -199,23 +184,30 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
 
         if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
         {
-            int i_val_size = sizeof( i_val );
+            socklen_t i_val_size = sizeof( i_val );
             div_t d;
             struct timeval tv;
             vlc_value_t timeout;
+
 #if defined( WIN32 ) || defined( UNDER_CE )
             if( WSAGetLastError() != WSAEWOULDBLOCK )
             {
-                msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
-                          i_port, WSAGetLastError( ) );
+                if( WSAGetLastError () == WSAENETUNREACH )
+                    b_unreach = VLC_TRUE;
+                else
+                    msg_Warn( p_this, "connection to %s port %d failed (%d)",
+                              psz_host, i_port, WSAGetLastError( ) );
                 net_Close( fd );
                 continue;
             }
 #else
             if( errno != EINPROGRESS )
             {
-                msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
-                          i_port, strerror( errno ) );
+                if( errno == ENETUNREACH )
+                    b_unreach = VLC_TRUE;
+                else
+                    msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
+                              i_port, strerror( errno ) );
                 net_Close( fd );
                 continue;
             }
@@ -287,13 +279,18 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
             if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
                             &i_val_size ) == -1 || i_val != 0 )
             {
+                if( i_val == ENETUNREACH )
+                    b_unreach = VLC_TRUE;
+                else
+                {
 #ifdef WIN32
-                msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
-                          i_port, WSAGetLastError( ) );
+                    msg_Warn( p_this, "connection to %s port %d failed (%d)",
+                              psz_host, i_port, WSAGetLastError( ) );
 #else
-                msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
-                          i_port, strerror( i_val ) );
+                    msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
+                              i_port, strerror( i_val ) );
 #endif
+                }
                 net_Close( fd );
                 continue;
             }
@@ -301,9 +298,17 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
         }
         i_handle = fd; /* success! */
     }
-    
+
     vlc_freeaddrinfo( res );
 
+    if( i_handle == -1 )
+    {
+        if( b_unreach )
+            msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
+                     i_port );
+        return -1;
+    }
+
     if( *psz_socks && *psz_socks != ':' )
     {
         char *psz_user = var_CreateGetString( p_this, "socks-user" );
@@ -341,12 +346,12 @@ int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
     hints.ai_socktype = SOCK_STREAM;
     hints.ai_flags = AI_PASSIVE;
 
-    msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
+    msg_Dbg( p_this, "net: listening to %s port %d", psz_host, i_port );
 
     i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
     if( i_val )
     {
-        msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_host, i_port,
+        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
                  vlc_gai_strerror( i_val ) );
         return NULL;
     }
@@ -374,7 +379,7 @@ int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
             net_Close( fd );
             continue;
         }
+
         /* Listen */
         if( listen( fd, 100 ) == -1 )
         {
@@ -401,7 +406,7 @@ int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
             pi_handles = newpi;
         }
     }
-    
+
     vlc_freeaddrinfo( res );
 
     if( pi_handles != NULL )
@@ -496,38 +501,117 @@ int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
     return -1;
 }
 
+
 /*****************************************************************************
- * __net_OpenUDP:
+ * __net_ConnectUDP:
  *****************************************************************************
- * Open a UDP connection and return a handle
+ * Open a UDP socket to send data to a defined destination, with an optional
+ * hop limit.
  *****************************************************************************/
-int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
-                   char *psz_server, int i_server )
+int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port,
+                      int hlim )
 {
-    vlc_value_t      val;
-    void            *private;
+    struct addrinfo hints, *res, *ptr;
+    int             i_val, i_handle = -1;
+    vlc_bool_t      b_unreach = VLC_FALSE;
 
-    char            *psz_network = "";
-    network_socket_t sock;
-    module_t         *p_network;
+    if( i_port == 0 )
+        i_port = 1234; /* historical VLC thing */
+
+    memset( &hints, 0, sizeof( hints ) );
+    hints.ai_socktype = SOCK_DGRAM;
 
+    msg_Dbg( p_this, "net: connecting to %s port %d", psz_host, i_port );
 
-    /* Check if we have force ipv4 or ipv6 */
-    var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "ipv4", &val );
-    if( val.b_bool )
+    i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
+    if( i_val )
     {
-        psz_network = "ipv4";
+        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
+                 vlc_gai_strerror( i_val ) );
+        return -1;
     }
 
-    var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "ipv6", &val );
-    if( val.b_bool )
+    for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
     {
-        psz_network = "ipv6";
+        int fd;
+
+        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( i_handle, SOL_SOCKET, SO_RCVBUF, (void *)&i_val,
+                        sizeof( i_val ) );
+            i_val = 0x80000;
+            setsockopt( i_handle, SOL_SOCKET, SO_SNDBUF, (void *)&i_val,
+                        sizeof( i_val ) );
+        }
+#endif
+
+        if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
+        {
+            /* success */
+            i_handle = fd;
+            break;
+        }
+
+#if defined( WIN32 ) || defined( UNDER_CE )
+        if( WSAGetLastError () == WSAENETUNREACH )
+#else
+        if( errno == ENETUNREACH )
+#endif
+            b_unreach = VLC_TRUE;
+        else
+        {
+            msg_Warn( p_this, "%s port %d : %s", psz_host, i_port,
+                      strerror( errno ) );
+            net_Close( fd );
+            continue;
+        }
     }
+
+    vlc_freeaddrinfo( res );
+
+    if( i_handle == -1 )
+    {
+        if( b_unreach )
+            msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
+                     i_port );
+        return -1;
+    }
+
+    return i_handle;
+}
+
+/*****************************************************************************
+ * __net_OpenUDP:
+ *****************************************************************************
+ * Open a UDP connection and return a handle
+ *****************************************************************************/
+int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
+                   const char *psz_server, int i_server )
+{
+    vlc_value_t      v4, v6;
+    void            *private;
+    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_server == NULL ) psz_server = "";
-    if( psz_bind   == NULL ) psz_bind   = "";
+    if( psz_bind == NULL ) psz_bind = "";
 
     /* Prepare the network_socket_t structure */
     sock.psz_bind_addr   = psz_bind;
@@ -535,19 +619,73 @@ int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
     sock.psz_server_addr = psz_server;
     sock.i_server_port   = i_server;
     sock.i_ttl           = 0;
+    sock.v6only          = 0;
+    sock.i_handle        = -1;
 
-    msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'",
+    msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
              psz_server, i_server, psz_bind, i_bind );
-    private = p_this->p_private;
-    p_this->p_private = (void*)&sock;
-    if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
+
+    /* Check if we have force ipv4 or ipv6 */
+    var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+    var_Get( p_this, "ipv4", &v4 );
+    var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+    var_Get( p_this, "ipv6", &v6 );
+
+    if( !v4.b_bool )
     {
-        msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
-                 psz_server, i_server, psz_bind, i_bind );
-        return -1;
+        if( v6.b_bool )
+            sock.v6only = 1;
+
+        /* try IPv6 first (unless IPv4 forced) */
+        private = p_this->p_private;
+        p_this->p_private = (void*)&sock;
+        p_network = module_Need( p_this, "network", "ipv6", VLC_TRUE );
+
+        if( p_network != NULL )
+            module_Unneed( p_this, p_network );
+
+        p_this->p_private = private;
+
+        /*
+         * Check if the IP stack can receive IPv4 packets on IPv6 sockets.
+         * If yes, then it is better to use the IPv6 socket.
+         * Otherwise, if we also get an IPv4, we have to choose, so we use
+         * IPv4 only.
+         */
+        if( ( sock.i_handle != -1 ) && ( ( sock.v6only == 0 ) || v6.b_bool ) )
+            return sock.i_handle;
+    }
+
+    if( !v6.b_bool )
+    {
+        int fd6 = sock.i_handle;
+
+        /* also try IPv4 (unless IPv6 forced) */
+        private = p_this->p_private;
+        p_this->p_private = (void*)&sock;
+        p_network = module_Need( p_this, "network", "ipv4", VLC_TRUE );
+
+        if( p_network != NULL )
+            module_Unneed( p_this, p_network );
+
+        p_this->p_private = private;
+
+        if( fd6 != -1 )
+        {
+            if( sock.i_handle != -1 )
+            {
+                msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
+                                  "Using only IPv4." );
+                net_Close( fd6 );
+            }
+            else
+                sock.i_handle = fd6;
+        }
     }
-    module_Unneed( p_this, p_network );
-    p_this->p_private = private;
+
+    if( sock.i_handle == -1 )
+        msg_Dbg( p_this, "net: connection to '[%s]:%d@[%s]:%d' failed",
+                psz_server, i_server, psz_bind, i_bind );
 
     return sock.i_handle;
 }
@@ -584,7 +722,7 @@ void net_ListenClose( int *pi_fd )
  * __net_Read:
  *****************************************************************************
  * Read from a network socket
- * If b_rety is true, then we repeat until we have read the right amount of
+ * If b_retry is true, then we repeat until we have read the right amount of
  * data
  *****************************************************************************/
 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
@@ -622,7 +760,7 @@ int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
         if( i_ret < 0 )
         {
 #if defined(WIN32) || defined(UNDER_CE)
-            msg_Err( p_this, "network select error" );
+            msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
 #else
             msg_Err( p_this, "network select error (%s)", strerror(errno) );
 #endif
@@ -652,7 +790,7 @@ int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
             else if( WSAGetLastError() == WSAEINTR ) continue;
             else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
 #else
-            /* EAGAIN only happens with p_vs (SSL) and it's not an error */
+            /* EAGAIN only happens with p_vs (TLS) and it's not an error */
             if( errno != EAGAIN )
                 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
 #endif
@@ -706,7 +844,7 @@ int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
     else if( i_ret < 0 )
     {
 #if defined(WIN32) || defined(UNDER_CE)
-        msg_Err( p_this, "network select error" );
+        msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
 #else
         msg_Err( p_this, "network select error (%s)", strerror(errno) );
 #endif
@@ -723,7 +861,7 @@ int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
 #endif
         if( ( i_recv = (p_vs != NULL)
               ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
-              : recv( fd, p_data, i_data, 0 ) ) <= 0 )
+              : recv( fd, p_data, i_data, 0 ) ) < 0 )
         {
 #if defined(WIN32) || defined(UNDER_CE)
             /* For udp only */
@@ -803,7 +941,7 @@ int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
                 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
                          ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
                          : recv( pi_fd[i], p_data, i_data, 0 );
-                if( i_recv <= 0 )
+                if( i_recv < 0 )
                 {
 #ifdef WIN32
                     /* For udp only */
@@ -818,7 +956,7 @@ int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
                     else msg_Err( p_this, "recv failed (%i)",
                                   WSAGetLastError() );
 #else
-                     msg_Err( p_this, "recv failed (%s)", strerror(errno) );
+                    msg_Err( p_this, "recv failed (%s)", strerror(errno) );
 #endif
                     return VLC_EGENERIC;
                 }
@@ -835,7 +973,7 @@ int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
 
 /* Write exact amount requested */
 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
-                 uint8_t *p_data, int i_data )
+                 const uint8_t *p_data, int i_data )
 {
     struct timeval  timeout;
     fd_set          fds_w, fds_e;
@@ -870,7 +1008,7 @@ int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
         if( i_ret < 0 )
         {
 #if defined(WIN32) || defined(UNDER_CE)
-            msg_Err( p_this, "network select error" );
+            msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
 #else
             msg_Err( p_this, "network select error (%s)", strerror(errno) );
 #endif
@@ -909,7 +1047,7 @@ char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
             ptr = psz_line + i_line;
         }
 
-        if( net_Read( p_this, fd, p_vs, ptr, 1, VLC_TRUE ) != 1 )
+        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
         {
             if( i_line == 0 )
             {
@@ -952,9 +1090,9 @@ int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
     char    *psz;
     int     i_size, i_ret;
 
-    vasprintf( &psz, psz_fmt, args );
-    i_size = strlen( psz );
-    i_ret = __net_Write( p_this, fd, p_vs, psz, i_size ) < i_size ? -1 : i_size;
+    i_size = vasprintf( &psz, psz_fmt, args );
+    i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
+        ? -1 : i_size;
     free( psz );
 
     return i_ret;
@@ -999,7 +1137,7 @@ static int SocksNegociate( vlc_object_t *p_obj,
         buffer[2] = 0x00;               /* - No auth required */
         i_len = 3;
     }
-    
+
     if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
         return VLC_EGENERIC;
     if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
@@ -1156,57 +1294,67 @@ static int SocksHandshakeTCP( vlc_object_t *p_obj,
 }
 
 /*****************************************************************************
- * __net_CheckIP
- *****************************************************************************
- * Check that a given IP is within a set of IP/netmask.
+ * inet_pton replacement for obsolete and/or crap operating systems
  *****************************************************************************/
-int __net_CheckIP( vlc_object_t *p_this, char *psz_ip, char **ppsz_hosts,
-                   int i_hosts )
+#ifndef HAVE_INET_PTON
+int inet_pton(int af, const char *src, void *dst)
 {
-    struct in_addr ip;
-    int i;
+# ifdef WIN32
+    /* As we already know, Microsoft always go its own way, so even if they do
+     * provide IPv6, they don't provide the API. */
+    struct sockaddr_storage addr;
+    int len = sizeof( addr );
+
+    /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
+#ifdef UNICODE
+    wchar_t *workaround_for_ill_designed_api =
+        malloc( MAX_PATH * sizeof(wchar_t) );
+    mbstowcs( workaround_for_ill_designed_api, src, MAX_PATH );
+    workaround_for_ill_designed_api[MAX_PATH-1] = 0;
+#else
+    char *workaround_for_ill_designed_api = strdup( src );
+#endif
 
-    if( (ip.s_addr = inet_addr( psz_ip )) == INADDR_NONE )
+    if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
+                             (LPSOCKADDR)&addr, &len ) )
     {
-        return VLC_EGENERIC;
+        free( workaround_for_ill_designed_api );
+        return -1;
     }
+    free( workaround_for_ill_designed_api );
 
-    for( i = 0; i < i_hosts; i++ )
+    switch( af )
     {
-        struct in_addr base, mask;
-        char *psz_host = strdup( ppsz_hosts[i] );
-        char *p = strchr( psz_host, '/' );
+        case AF_INET6:
+            memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
+            break;
 
-        if( p != NULL )
-        {
-            int i_mask;
-            *p++ = '\0';
-            i_mask = atoi(p);
-            if( i_mask < 0 || i_mask > 32 )
-            {
-                msg_Err( p_this, "invalid netmask %s", p );
-                mask.s_addr = INADDR_NONE;
-            }
-            else if( i_mask == 0 )
-                mask.s_addr = INADDR_ANY;
-            else
-                mask.s_addr = htonl( ntohl(INADDR_NONE) << (32 - i_mask) );
-        }
-        else
-            mask.s_addr = INADDR_NONE;
+        case AF_INET:
+            memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
+            break;
 
-        if( (base.s_addr = inet_addr( psz_host )) == INADDR_NONE )
-        {
-            msg_Err( p_this, "invalid base address %s", psz_host );
-            free( psz_host );
-            continue;
-        }
-        free( psz_host );
+        default:
+            WSASetLastError( WSAEAFNOSUPPORT );
+            return -1;
+    }
+# else
+    /* Assume IPv6 is not supported. */
+    /* Would be safer and more simpler to use inet_aton() but it is most
+     * likely not provided either. */
+    uint32_t ipv4;
 
-        if( !((ip.s_addr ^ base.s_addr) & mask.s_addr) )
-            return VLC_TRUE;
+    if( af != AF_INET )
+    {
+        errno = EAFNOSUPPORT;
+        return -1;
     }
 
-    return VLC_FALSE;
-}
+    ipv4 = inet_addr( src );
+    if( ipv4 == INADDR_NONE )
+        return -1;
 
+    memcpy( dst, &ipv4, 4 );
+# endif /* WIN32 */
+    return 0;
+}
+#endif /* HAVE_INET_PTON */