]> git.sesse.net Git - vlc/blobdiff - src/network/io.c
httpd: cosmetics
[vlc] / src / network / io.c
index c38831c222f96ce102a1d42cb43a70cfb7cda51b..d8832e21f0b503a7bada50e75978c0a6d04899ef 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * io.c: network I/O functions
  *****************************************************************************
- * Copyright (C) 2004-2005, 2007 the VideoLAN team
+ * Copyright (C) 2004-2005, 2007 VLC authors and VideoLAN
  * Copyright © 2005-2006 Rémi Denis-Courmont
  * $Id$
  *
@@ -9,19 +9,19 @@
  *          Rémi Denis-Courmont <rem # videolan.org>
  *          Christophe Mutricy <xtophe at videolan dot org>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
@@ -32,7 +32,7 @@
 # include "config.h"
 #endif
 
-#include <vlc/vlc.h>
+#include <vlc_common.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
 #include <assert.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 <fcntl.h>
+#include <unistd.h>
 #ifdef HAVE_POLL
 #   include <poll.h>
 #endif
 #   define INADDR_NONE 0xFFFFFFFF
 #endif
 
-#if defined(WIN32) || defined(UNDER_CE)
+#if defined(_WIN32)
 # undef EAFNOSUPPORT
 # define EAFNOSUPPORT WSAEAFNOSUPPORT
+# undef EWOULDBLOCK
+# define EWOULDBLOCK WSAEWOULDBLOCK
+# undef EAGAIN
+# define EAGAIN WSAEWOULDBLOCK
 #endif
 
 #ifdef HAVE_LINUX_DCCP_H
 # define SOL_DCCP 269
 #endif
 
+#include "libvlc.h" /* vlc_object_waitpipe */
+
 extern int rootwrap_bind (int family, int socktype, int protocol,
                           const struct sockaddr *addr, size_t alen);
 
-int net_SetupSocket (int fd)
-{
-#if defined (WIN32) || defined (UNDER_CE)
-    ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
-#else
-    fcntl (fd, F_SETFD, FD_CLOEXEC);
-    fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) | O_NONBLOCK);
-#endif
-
-    setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
-    return 0;
-}
-
-
 int net_Socket (vlc_object_t *p_this, int family, int socktype,
                 int protocol)
 {
-    int fd = socket (family, socktype, protocol);
+    int fd = vlc_socket (family, socktype, protocol, true);
     if (fd == -1)
     {
         if (net_errno != EAFNOSUPPORT)
-            msg_Err (p_this, "cannot create socket: %m");
+            msg_Err (p_this, "cannot create socket: %s",
+                     vlc_strerror_c(net_errno));
         return -1;
     }
 
-    net_SetupSocket (fd);
+    setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
 
 #ifdef IPV6_V6ONLY
     /*
@@ -113,7 +99,7 @@ int net_Socket (vlc_object_t *p_this, int family, int socktype,
         setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int));
 #endif
 
-#if defined (WIN32) || defined (UNDER_CE)
+#if defined (_WIN32)
 # ifndef IPV6_PROTECTION_LEVEL
 #  warning Please update your C library headers.
 #  define IPV6_PROTECTION_LEVEL 23
@@ -127,7 +113,7 @@ int net_Socket (vlc_object_t *p_this, int family, int socktype,
 #ifdef DCCP_SOCKOPT_SERVICE
     if (socktype == SOL_DCCP)
     {
-        char *dccps = var_CreateGetNonEmptyString (p_this, "dccp-service");
+        char *dccps = var_InheritString (p_this, "dccp-service");
         if (dccps != NULL)
         {
             setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE, dccps,
@@ -142,39 +128,23 @@ int net_Socket (vlc_object_t *p_this, int family, int socktype,
 
 
 int *net_Listen (vlc_object_t *p_this, const char *psz_host,
-                 int i_port, int protocol)
+                 int i_port, int type, int protocol)
 {
-    struct addrinfo hints, *res;
-    int socktype = SOCK_DGRAM;
-
-    switch( protocol )
-    {
-        case IPPROTO_TCP:
-            socktype = SOCK_STREAM;
-            break;
-        case 33: /* DCCP */
-#ifdef __linux__
-# ifndef SOCK_DCCP
-#  define SOCK_DCCP 6
-# endif
-            socktype = SOCK_DCCP;
-#endif
-            break;
-    }
-
-    memset (&hints, 0, sizeof( hints ));
-    /* Since we use port numbers rather than service names, the socket type
-     * does not really matter. */
-    hints.ai_socktype = SOCK_DGRAM;
-    hints.ai_flags = AI_PASSIVE;
+    struct addrinfo hints = {
+        .ai_socktype = type,
+        .ai_protocol = protocol,
+        .ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_IDN,
+    }, *res;
 
-    msg_Dbg (p_this, "net: listening to %s port %d", psz_host, i_port);
+    msg_Dbg (p_this, "net: listening to %s port %d",
+             (psz_host != NULL) ? psz_host : "*", i_port);
 
-    int i_val = vlc_getaddrinfo (p_this, psz_host, i_port, &hints, &res);
+    int i_val = vlc_getaddrinfo (psz_host, i_port, &hints, &res);
     if (i_val)
     {
-        msg_Err (p_this, "Cannot resolve %s port %d : %s", psz_host, i_port,
-                 vlc_gai_strerror (i_val));
+        msg_Err (p_this, "Cannot resolve %s port %d : %s",
+                 (psz_host != NULL) ? psz_host : "", i_port,
+                 gai_strerror (i_val));
         return NULL;
     }
 
@@ -183,15 +153,16 @@ int *net_Listen (vlc_object_t *p_this, const char *psz_host,
 
     for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
     {
-        int fd = net_Socket (p_this, ptr->ai_family, socktype, protocol);
+        int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
+                             ptr->ai_protocol);
         if (fd == -1)
         {
-            msg_Dbg (p_this, "socket error: %m");
+            msg_Dbg (p_this, "socket error: %s", vlc_strerror_c(net_errno));
             continue;
         }
 
         /* Bind the socket */
-#if defined (WIN32) || defined (UNDER_CE)
+#if defined (_WIN32)
         /*
          * Under Win32 and for multicasting, we bind to INADDR_ANY.
          * This is of course a severe bug, since the socket would logically
@@ -215,10 +186,10 @@ int *net_Listen (vlc_object_t *p_this, const char *psz_host,
         if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
         {
             net_Close (fd);
-#if !defined(WIN32) && !defined(UNDER_CE)
+#if !defined(_WIN32)
             fd = rootwrap_bind (ptr->ai_family, ptr->ai_socktype,
-                                protocol ?: ptr->ai_protocol, ptr->ai_addr,
-                                ptr->ai_addrlen);
+                                ptr->ai_protocol,
+                                ptr->ai_addr, ptr->ai_addrlen);
             if (fd != -1)
             {
                 msg_Dbg (p_this, "got socket %d from rootwrap", fd);
@@ -226,7 +197,8 @@ int *net_Listen (vlc_object_t *p_this, const char *psz_host,
             else
 #endif
             {
-                msg_Err (p_this, "socket bind error (%m)");
+                msg_Err (p_this, "socket bind error: %s",
+                         vlc_strerror_c(net_errno));
                 continue;
             }
         }
@@ -241,7 +213,7 @@ int *net_Listen (vlc_object_t *p_this, const char *psz_host,
         }
 
         /* Listen */
-        switch (socktype)
+        switch (ptr->ai_socktype)
         {
             case SOCK_STREAM:
             case SOCK_RDM:
@@ -251,7 +223,8 @@ int *net_Listen (vlc_object_t *p_this, const char *psz_host,
 #endif
                 if (listen (fd, INT_MAX))
                 {
-                    msg_Err (p_this, "socket listen error (%m)");
+                    msg_Err (p_this, "socket listen error: %s",
+                             vlc_strerror_c(net_errno));
                     net_Close (fd);
                     continue;
                 }
@@ -267,7 +240,7 @@ int *net_Listen (vlc_object_t *p_this, const char *psz_host,
             net_Close (fd);
     }
 
-    vlc_freeaddrinfo (res);
+    freeaddrinfo (res);
 
     if (sockv != NULL)
         sockv[sockc] = -1;
@@ -275,142 +248,136 @@ int *net_Listen (vlc_object_t *p_this, const char *psz_host,
     return sockv;
 }
 
-
+#undef net_Read
 /*****************************************************************************
- * __net_Read:
+ * net_Read:
  *****************************************************************************
- * Reads from a network socket.
+ * Reads from a network socket. Cancellation point.
  * If waitall is true, then we repeat until we have read the right amount of
  * data; in that case, a short count means EOF has been reached or the VLC
  * object has been signaled.
  *****************************************************************************/
 ssize_t
-__net_Read (vlc_object_t *restrict p_this, int fd, const v_socket_t *vs,
-            uint8_t *restrict p_buf, size_t i_buflen, vlc_bool_t waitall)
+net_Read (vlc_object_t *restrict p_this, int fd, const v_socket_t *vs,
+          void *restrict p_buf, size_t i_buflen, bool waitall)
 {
-    size_t i_total = 0;
-    struct pollfd ufd[2] = {
-        { .fd = fd,                           .events = POLLIN },
-        { .fd = vlc_object_waitpipe (p_this), .events = POLLIN },
-    };
-
-    if (ufd[1].fd == -1)
-        return -1; /* vlc_object_waitpipe() sets errno */
+    struct pollfd ufd[2];
 
-    while (i_buflen > 0)
-    {
-        ufd[0].revents = ufd[1].revents = 0;
-
-        if (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), -1) < 0)
-        {
-            if (errno != EINTR)
-                goto error;
-            continue;
-        }
+    ufd[0].fd = fd;
+    ufd[0].events = POLLIN;
+    ufd[1].fd = vlc_object_waitpipe (p_this);
+    ufd[1].events = POLLIN;
 
-#ifndef POLLRDHUP /* This is nice but non-portable */
-# define POLLRDHUP 0
-#endif
-        if (i_total > 0)
-        {
-            /* Errors (-1) and EOF (0) will be returned on next call,
-             * otherwise we'd "hide" the error from the caller, which is a
-             * bad idea™. */
-            if (ufd[0].revents & (POLLERR|POLLNVAL|POLLRDHUP))
-                break;
-            if (ufd[1].revents)
-                break;
-        }
-        else
-        {
-            if (ufd[1].revents)
-            {
-                assert (p_this->b_die);
-                msg_Dbg (p_this, "socket %d polling interrupted", fd);
-#if defined(WIN32) || defined(UNDER_CE)
-                WSASetLastError (WSAEINTR);
-#else
-                errno = EINTR;
+    size_t i_total = 0;
+#if VLC_WINSTORE_APP
+    /* With winrtsock winsocks emulation library, the first call to read()
+     * before poll() starts an asynchronous transfer and returns 0.
+     * Always call poll() first.
+     *
+     * However if we have a virtual socket handler, try to read() first.
+     * See bug #8972 for details.
+     */
+    if (vs == NULL)
+        goto do_poll;
 #endif
-                goto silent;
-            }
-        }
-
-        assert (ufd[0].revents);
-
+    do
+    {
         ssize_t n;
         if (vs != NULL)
         {
+            int canc = vlc_savecancel ();
             n = vs->pf_recv (vs->p_sys, p_buf, i_buflen);
+            vlc_restorecancel (canc);
         }
         else
         {
-#ifdef WIN32
+#ifdef _WIN32
             n = recv (fd, p_buf, i_buflen, 0);
 #else
             n = read (fd, p_buf, i_buflen);
 #endif
         }
 
-        if (n == -1)
+        if (n < 0)
         {
-#if defined(WIN32) || defined(UNDER_CE)
-            switch (WSAGetLastError ())
+            switch (net_errno)
             {
-                case WSAEWOULDBLOCK:
-                /* only happens with vs != NULL (TLS) - not really an error */
+                case EAGAIN: /* no data */
+#if (EAGAIN != EWOULDBLOCK)
+                case EWOULDBLOCK:
+#endif
+                    break;
+#ifndef _WIN32
+                case EINTR:  /* asynchronous signal */
                     continue;
-
-                case WSAEMSGSIZE:
-                /* For UDP only */
-                /* On Win32, recv() fails if the datagram doesn't fit inside
-                 * the passed buffer, even though the buffer will be filled
-                 * with the first part of the datagram. */
-                    msg_Err (p_this, "Receive error: "
-                                     "Increase the mtu size (--mtu option)");
+#else
+                case WSAEMSGSIZE: /* datagram too big */
                     n = i_buflen;
                     break;
-
+#endif
                 default:
                     goto error;
             }
-#else
-            /* spurious wake-up or TLS did not yield any actual data */
-            if (errno == EAGAIN)
+        }
+        else
+        if (n > 0)
+        {
+            i_total += n;
+            p_buf = (char *)p_buf + n;
+            i_buflen -= n;
+
+            if (!waitall || i_buflen == 0)
+                break;
+        }
+        else /* n == 0 */
+            break;/* end of stream or empty packet */
+
+        if (ufd[1].fd == -1)
+        {
+            errno = EINTR;
+            return -1;
+        }
+#if VLC_WINSTORE_APP
+do_poll:
+#endif
+        /* Wait for more data */
+        if (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), -1) < 0)
+        {
+            if (errno == EINTR)
                 continue;
             goto error;
-#endif
         }
 
-        if (n == 0)
-            /* For streams, this means end of file, and there will not be any
-             * further data ever on the stream. For datagram sockets, this
-             * means empty datagram, and there could be more data coming.
-             * However, it makes no sense to set <waitall> with datagrams in the
-             * first place.
-             */
-            break; // EOF
-
-        i_total += n;
-        p_buf += n;
-        i_buflen -= n;
+        if (ufd[1].revents)
+        {
+            msg_Dbg (p_this, "socket %d polling interrupted", fd);
+            errno = EINTR;
+            return -1;
+        }
 
-        if (!waitall)
-            break;
+        assert (ufd[0].revents);
     }
+    while (i_buflen > 0);
 
     return i_total;
-
 error:
-    msg_Err (p_this, "Read error: %m");
-silent:
+    msg_Err (p_this, "read error: %s", vlc_strerror_c(errno));
     return -1;
 }
 
-
-/* Write exact amount requested */
-ssize_t __net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
-                     const uint8_t *p_data, size_t i_data )
+#undef net_Write
+/**
+ * Writes data to a file descriptor.
+ * This blocks until all data is written or an error occurs.
+ *
+ * This function is a cancellation point if p_vs is NULL.
+ * This function is not cancellation-safe if p_vs is not NULL.
+ *
+ * @return the total number of bytes written, or -1 if an error occurs
+ * before any data is written.
+ */
+ssize_t net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
+                   const void *restrict p_data, size_t i_data )
 {
     size_t i_total = 0;
     struct pollfd ufd[2] = {
@@ -418,8 +385,11 @@ ssize_t __net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
         { .fd = vlc_object_waitpipe (p_this), .events = POLLIN  },
     };
 
-    if (ufd[1].fd == -1)
+    if (unlikely(ufd[1].fd == -1))
+    {
+        vlc_testcancel ();
         return -1;
+    }
 
     while( i_data > 0 )
     {
@@ -427,29 +397,27 @@ ssize_t __net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
 
         ufd[0].revents = ufd[1].revents = 0;
 
-        if (poll (ufd, 1, -1) == -1)
+        if (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), -1) == -1)
         {
-            if (errno != EINTR)
-            {
-                msg_Err (p_this, "Write error: %m");
-                goto error;
-            }
-            continue;
+            if (errno == EINTR)
+                continue;
+            msg_Err (p_this, "Polling error: %s", vlc_strerror_c(errno));
+            return -1;
         }
 
         if (i_total > 0)
-        {
-            /* Errors will be dequeued separately, upon next call. */
-            if (ufd[0].revents & (POLLERR|POLLNVAL|POLLHUP))
+        {   /* If POLLHUP resp. POLLERR|POLLNVAL occurs while we have already
+             * read some data, it is important that we first return the number
+             * of bytes read, and then return 0 resp. -1 on the NEXT call. */
+            if (ufd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
                 break;
-            if (ufd[1].revents)
+            if (ufd[1].revents) /* VLC object signaled */
                 break;
         }
         else
         {
             if (ufd[1].revents)
             {
-                assert (p_this->b_die);
                 errno = EINTR;
                 goto error;
             }
@@ -458,7 +426,7 @@ ssize_t __net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
         if (p_vs != NULL)
             val = p_vs->pf_send (p_vs->p_sys, p_data, i_data);
         else
-#ifdef WIN32
+#ifdef _WIN32
             val = send (fd, p_data, i_data, 0);
 #else
             val = write (fd, p_data, i_data);
@@ -466,15 +434,20 @@ ssize_t __net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
 
         if (val == -1)
         {
-            msg_Err (p_this, "Write error: %m");
+            if (errno == EINTR)
+                continue;
+            msg_Err (p_this, "Write error: %s", vlc_strerror_c(errno));
             break;
         }
 
-        p_data += val;
+        p_data = (const char *)p_data + val;
         i_data -= val;
         i_total += val;
     }
 
+    if (unlikely(i_data == 0))
+        vlc_testcancel (); /* corner case */
+
     if ((i_total > 0) || (i_data == 0))
         return i_total;
 
@@ -482,46 +455,56 @@ error:
     return -1;
 }
 
-char *__net_Gets( vlc_object_t *p_this, int fd, const v_socket_t *p_vs )
+#undef net_Gets
+/**
+ * Reads a line from a file descriptor.
+ * This function is not thread-safe; the same file descriptor I/O cannot be
+ * read by another thread at the same time (although it can be written to).
+ *
+ * @note This only works with stream-oriented file descriptors, not with
+ * datagram or packet-oriented ones.
+ *
+ * @return nul-terminated heap-allocated string, or NULL on I/O error.
+ */
+char *net_Gets(vlc_object_t *obj, int fd, const v_socket_t *vs)
 {
-    char *psz_line = NULL, *ptr = NULL;
-    size_t  i_line = 0, i_max = 0;
-
+    char *buf = NULL;
+    size_t bufsize = 0, buflen = 0;
 
-    for( ;; )
+    for (;;)
     {
-        if( i_line == i_max )
+        if (buflen == bufsize)
         {
-            i_max += 1024;
-            psz_line = realloc( psz_line, i_max );
-            ptr = psz_line + i_line;
-        }
+            if (unlikely(bufsize >= (1 << 16)))
+                goto error; /* put sane buffer size limit */
 
-        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
-        {
-            if( i_line == 0 )
-            {
-                free( psz_line );
-                return NULL;
-            }
-            break;
+            char *newbuf = realloc(buf, bufsize + 1024);
+            if (unlikely(newbuf == NULL))
+                goto error;
+            buf = newbuf;
+            bufsize += 1024;
         }
 
-        if ( *ptr == '\n' )
+        ssize_t val = net_Read(obj, fd, vs, buf + buflen, 1, false);
+        if (val < 1)
+            goto error;
+
+        if (buf[buflen] == '\n')
             break;
 
-        i_line++;
-        ptr++;
+        buflen++;
     }
 
-    *ptr-- = '\0';
-
-    if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
-        *ptr = '\0';
-
-    return psz_line;
+    buf[buflen] = '\0';
+    if (buflen > 0 && buf[buflen - 1] == '\r')
+        buf[buflen - 1] = '\0';
+    return buf;
+error:
+    free(buf);
+    return NULL;
 }
 
+#undef net_Printf
 ssize_t net_Printf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
                     const char *psz_fmt, ... )
 {
@@ -534,134 +517,19 @@ ssize_t net_Printf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
     return i_ret;
 }
 
-ssize_t __net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
-                        const char *psz_fmt, va_list args )
+#undef net_vaPrintf
+ssize_t net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
+                      const char *psz_fmt, va_list args )
 {
     char    *psz;
-    int     i_size, i_ret;
+    int      i_ret;
 
-    i_size = vasprintf( &psz, psz_fmt, args );
-    i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
+    int i_size = vasprintf( &psz, psz_fmt, args );
+    if( i_size == -1 )
+        return -1;
+    i_ret = net_Write( p_this, fd, p_vs, psz, i_size ) < i_size
         ? -1 : i_size;
     free( psz );
 
     return i_ret;
 }
-
-
-/*****************************************************************************
- * inet_pton replacement for obsolete and/or crap operating systems
- *****************************************************************************/
-#ifndef HAVE_INET_PTON
-int inet_pton(int af, const char *src, void *dst)
-{
-# 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( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
-                             (LPSOCKADDR)&addr, &len ) )
-    {
-        free( workaround_for_ill_designed_api );
-        return -1;
-    }
-    free( workaround_for_ill_designed_api );
-
-    switch( af )
-    {
-        case AF_INET6:
-            memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
-            break;
-
-        case AF_INET:
-            memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
-            break;
-
-        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( af != AF_INET )
-    {
-        errno = EAFNOSUPPORT;
-        return -1;
-    }
-
-    ipv4 = inet_addr( src );
-    if( ipv4 == INADDR_NONE )
-        return -1;
-
-    memcpy( dst, &ipv4, 4 );
-# endif /* WIN32 */
-    return 0;
-}
-#endif /* HAVE_INET_PTON */
-
-#ifndef HAVE_INET_NTOP
-#ifdef WIN32
-const char *inet_ntop(int af, const void * src,
-                               char * dst, socklen_t cnt)
-{
-    switch( af )
-    {
-#ifdef AF_INET6
-        case AF_INET6:
-            {
-                struct sockaddr_in6 addr;
-                memset(&addr, 0, sizeof(addr));
-                addr.sin6_family = AF_INET6;
-                addr.sin6_addr = *((struct in6_addr*)src);
-                if( 0 == WSAAddressToStringA((LPSOCKADDR)&addr,
-                                             sizeof(struct sockaddr_in6),
-                                             NULL, dst, &cnt) )
-                {
-                    dst[cnt] = '\0';
-                    return dst;
-                }
-                errno = WSAGetLastError();
-                return NULL;
-
-            }
-
-#endif
-        case AF_INET:
-            {
-                struct sockaddr_in addr;
-                memset(&addr, 0, sizeof(addr));
-                addr.sin_family = AF_INET;
-                addr.sin_addr = *((struct in_addr*)src);
-                if( 0 == WSAAddressToStringA((LPSOCKADDR)&addr,
-                                             sizeof(struct sockaddr_in),
-                                             NULL, dst, &cnt) )
-                {
-                    dst[cnt] = '\0';
-                    return dst;
-                }
-                errno = WSAGetLastError();
-                return NULL;
-
-            }
-    }
-    errno = EAFNOSUPPORT;
-    return NULL;
-}
-#endif
-#endif