Merged IPv6 support in the NET module
diff --git a/ChangeLog b/ChangeLog
index 2ff3694..3eadbcc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,7 @@
      (POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
    * Support for Curve25519
    * Support for ECDH-RSA and ECDH-ECDSA key exchanges and ciphersuites
+   * Support for IPv6 in the NET module
 
 Changes
    * gen_prime() speedup
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index 970212f..7bbef55 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -101,6 +101,16 @@
  * Comment if your system does not support time functions
  */
 #define POLARSSL_HAVE_TIME
+
+/**
+ * \def POLARSSL_HAVE_IPV6
+ *
+ * System supports the basic socket interface for IPv6 (RFC 3493),
+ * specifically getaddrinfo(), freeaddrinfo() and struct sockaddr_storage.
+ *
+ * Comment if your system does not support the IPv6 socket interface
+ */
+#define POLARSSL_HAVE_IPV6
 /* \} name SECTION: System support */
 
 /**
diff --git a/include/polarssl/net.h b/include/polarssl/net.h
index 88302ac..22698b4 100644
--- a/include/polarssl/net.h
+++ b/include/polarssl/net.h
@@ -82,9 +82,10 @@
  * \param bind_fd   Relevant socket
  * \param client_fd Will contain the connected client socket
  * \param client_ip Will contain the client IP address
+ *                  Must be at least 4 bytes, or 16 if IPv6 is supported
  *
  * \return          0 if successful, POLARSSL_ERR_NET_ACCEPT_FAILED, or
- *                  POLARSSL_ERR_NET_WOULD_BLOCK is bind_fd was set to
+ *                  POLARSSL_ERR_NET_WANT_READ is bind_fd was set to
  *                  non-blocking and accept() is blocking.
  */
 int net_accept( int bind_fd, int *client_fd, void *client_ip );
diff --git a/library/net.c b/library/net.c
index be2785d..19f699d 100644
--- a/library/net.c
+++ b/library/net.c
@@ -81,6 +81,11 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#if defined(_MSC_VER) && !defined  snprintf && !defined(EFIX64) && \
+    !defined(EFI32)
+#define  snprintf  _snprintf
+#endif
+
 #if defined(POLARSSL_HAVE_TIME)
 #include <time.h>
 #endif
@@ -115,16 +120,12 @@
 #define net_htonl(n) POLARSSL_HTONL(n)
 
 /*
- * Initiate a TCP connection with host:port
+ * Prepare for using the sockets interface
  */
-int net_connect( int *fd, const char *host, int port )
+static void net_prepare( void )
 {
-    struct sockaddr_in server_addr;
-    struct hostent *server_host;
-
 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
     !defined(EFI32)
-
     WSADATA wsaData;
 
     if( wsa_init_done == 0 )
@@ -139,6 +140,64 @@
     signal( SIGPIPE, SIG_IGN );
 #endif
 #endif
+}
+
+/*
+ * Initiate a TCP connection with host:port
+ */
+int net_connect( int *fd, const char *host, int port )
+{
+#if defined(POLARSSL_HAVE_IPV6)
+    int ret = POLARSSL_ERR_NET_UNKNOWN_HOST;
+    struct addrinfo hints, *addr_list, *cur;
+    char port_str[6];
+
+    net_prepare();
+
+    /* getaddrinfo expects port as a string */
+    memset( port_str, 0, sizeof( port_str ) );
+    snprintf( port_str, sizeof( port_str ), "%d", port );
+
+    /* Do name resolution with both IPv6 and IPv4, but only TCP */
+    memset( &hints, 0, sizeof( hints ) );
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = IPPROTO_TCP;
+
+    if( getaddrinfo( host, port_str, &hints, &addr_list ) != 0 )
+        return( POLARSSL_ERR_NET_UNKNOWN_HOST );
+
+    /* Try the sockaddrs until a connection succeeds */
+    for( cur = addr_list; cur != NULL; cur = cur->ai_next )
+    {
+        *fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
+        if( *fd < 0 )
+        {
+            ret = POLARSSL_ERR_NET_SOCKET_FAILED;
+            continue;
+        }
+
+        if( connect( *fd, cur->ai_addr, cur->ai_addrlen ) == 0 )
+        {
+            ret = 0;
+            break;
+        }
+
+        close( *fd );
+        ret = POLARSSL_ERR_NET_CONNECT_FAILED;
+    }
+
+    freeaddrinfo( addr_list );
+
+    return( ret );
+
+#else
+    /* Legacy IPv4-only version */
+
+    struct sockaddr_in server_addr;
+    struct hostent *server_host;
+
+    net_prepare();
 
     if( ( server_host = gethostbyname( host ) ) == NULL )
         return( POLARSSL_ERR_NET_UNKNOWN_HOST );
@@ -161,6 +220,7 @@
     }
 
     return( 0 );
+#endif /* POLARSSL_HAVE_IPV6 */
 }
 
 /*
@@ -168,25 +228,72 @@
  */
 int net_bind( int *fd, const char *bind_ip, int port )
 {
+#if defined(POLARSSL_HAVE_IPV6)
+    int n, ret = POLARSSL_ERR_NET_UNKNOWN_HOST;
+    struct addrinfo hints, *addr_list, *cur;
+    char port_str[6];
+
+    net_prepare();
+
+    /* getaddrinfo expects port as a string */
+    memset( port_str, 0, sizeof( port_str ) );
+    snprintf( port_str, sizeof( port_str ), "%d", port );
+
+    /* Bind to IPv6 and/or IPv4, but only in TCP */
+    memset( &hints, 0, sizeof( hints ) );
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = IPPROTO_TCP;
+    if( bind_ip == NULL )
+        hints.ai_flags = AI_PASSIVE;
+
+    if( getaddrinfo( bind_ip, port_str, &hints, &addr_list ) != 0 )
+        return( POLARSSL_ERR_NET_UNKNOWN_HOST );
+
+    /* Try the sockaddrs until a binding succeeds */
+    for( cur = addr_list; cur != NULL; cur = cur->ai_next )
+    {
+        *fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
+        if( *fd < 0 )
+        {
+            ret = POLARSSL_ERR_NET_SOCKET_FAILED;
+            continue;
+        }
+
+        n = 1;
+        setsockopt( *fd, SOL_SOCKET, SO_REUSEADDR,
+                    (const char *) &n, sizeof( n ) );
+
+        if( bind( *fd, cur->ai_addr, cur->ai_addrlen ) != 0 )
+        {
+            close( *fd );
+            ret = POLARSSL_ERR_NET_BIND_FAILED;
+            continue;
+        }
+
+        if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 )
+        {
+            close( *fd );
+            ret = POLARSSL_ERR_NET_LISTEN_FAILED;
+            continue;
+        }
+
+        /* I we ever get there, it's a success */
+        ret = 0;
+        break;
+    }
+
+    freeaddrinfo( addr_list );
+
+    return( ret );
+
+#else
+    /* Legacy IPv4-only version */
+
     int n, c[4];
     struct sockaddr_in server_addr;
 
-#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
-    !defined(EFI32)
-    WSADATA wsaData;
-
-    if( wsa_init_done == 0 )
-    {
-        if( WSAStartup( MAKEWORD(2,0), &wsaData ) == SOCKET_ERROR )
-            return( POLARSSL_ERR_NET_SOCKET_FAILED );
-
-        wsa_init_done = 1;
-    }
-#else
-#if !defined(EFIX64) && !defined(EFI32)
-    signal( SIGPIPE, SIG_IGN );
-#endif
-#endif
+    net_prepare();
 
     if( ( *fd = (int) socket( AF_INET, SOCK_STREAM, IPPROTO_IP ) ) < 0 )
         return( POLARSSL_ERR_NET_SOCKET_FAILED );
@@ -230,6 +337,7 @@
     }
 
     return( 0 );
+#endif /* POLARSSL_HAVE_IPV6 */
 }
 
 /*
@@ -260,7 +368,11 @@
  */
 int net_accept( int bind_fd, int *client_fd, void *client_ip )
 {
+#if defined(POLARSSL_HAVE_IPV6)
+    struct sockaddr_storage client_addr;
+#else
     struct sockaddr_in client_addr;
+#endif
 
 #if defined(__socklen_t_defined) || defined(_SOCKLEN_T) ||  \
     defined(_SOCKLEN_T_DECLARED)
@@ -281,8 +393,25 @@
     }
 
     if( client_ip != NULL )
+    {
+#if defined(POLARSSL_HAVE_IPV6)
+        if( client_addr.ss_family == AF_INET )
+        {
+            struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr;
+            memcpy( client_ip, &addr4->sin_addr.s_addr,
+                        sizeof( addr4->sin_addr.s_addr ) );
+        }
+        else
+        {
+            struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr;
+            memcpy( client_ip, &addr6->sin6_addr.s6_addr,
+                        sizeof( addr6->sin6_addr.s6_addr ) );
+        }
+#else
         memcpy( client_ip, &client_addr.sin_addr.s_addr,
                     sizeof( client_addr.sin_addr.s_addr ) );
+#endif /* POLARSSL_HAVE_IPV6 */
+    }
 
     return( 0 );
 }
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 96cbb49..7233dff 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -49,6 +49,7 @@
 #include "polarssl/memory.h"
 #endif
 
+#define DFL_SERVER_ADDR         NULL
 #define DFL_SERVER_PORT         4433
 #define DFL_DEBUG_LEVEL         0
 #define DFL_CA_FILE             ""
@@ -91,6 +92,7 @@
  */
 struct options
 {
+    const char *server_addr;    /* address on which the ssl service runs    */
     int server_port;            /* port on which the ssl service runs       */
     int debug_level;            /* level of debugging                       */
     const char *ca_file;        /* the file with the CA certificate(s)      */
@@ -172,6 +174,7 @@
 #define USAGE \
     "\n usage: ssl_server2 param=<>...\n"                   \
     "\n acceptable parameters:\n"                           \
+    "    server_addr=%%d      default: (all interfaces)\n"  \
     "    server_port=%%d      default: 4433\n"              \
     "    debug_level=%%d      default: 0 (disabled)\n"      \
     USAGE_IO                                                \
@@ -281,6 +284,7 @@
         goto exit;
     }
 
+    opt.server_addr         = DFL_SERVER_ADDR;
     opt.server_port         = DFL_SERVER_PORT;
     opt.debug_level         = DFL_DEBUG_LEVEL;
     opt.ca_file             = DFL_CA_FILE;
@@ -313,6 +317,8 @@
             if( opt.server_port < 1 || opt.server_port > 65535 )
                 goto usage;
         }
+        else if( strcmp( p, "server_addr" ) == 0 )
+            opt.server_addr = q;
         else if( strcmp( p, "debug_level" ) == 0 )
         {
             opt.debug_level = atoi( q );
@@ -678,7 +684,8 @@
     printf( "  . Bind on tcp://localhost:%-4d/ ...", opt.server_port );
     fflush( stdout );
 
-    if( ( ret = net_bind( &listen_fd, NULL, opt.server_port ) ) != 0 )
+    if( ( ret = net_bind( &listen_fd, opt.server_addr,
+                                      opt.server_port ) ) != 0 )
     {
         printf( " failed\n  ! net_bind returned -0x%x\n\n", -ret );
         goto exit;
diff --git a/tests/compat.sh b/tests/compat.sh
index 36f241b..ecc2e58 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -354,8 +354,8 @@
 kill $PROCESS_ID
 wait $PROCESS_ID 2>/dev/null
 
-log "../programs/ssl/ssl_server2 $P_SERVER_ARGS force_version=$MODE > /dev/null"
-../programs/ssl/ssl_server2 $P_SERVER_ARGS force_version=$MODE > /dev/null &
+log "../programs/ssl/ssl_server2 server_addr=0.0.0.0 $P_SERVER_ARGS force_version=$MODE > /dev/null"
+../programs/ssl/ssl_server2 server_addr=0.0.0.0 $P_SERVER_ARGS force_version=$MODE > /dev/null &
 PROCESS_ID=$!
 
 sleep 1
@@ -390,8 +390,8 @@
 kill $PROCESS_ID
 wait $PROCESS_ID 2>/dev/null
 
-log "../programs/ssl/ssl_server2 $P_SERVER_ARGS force_version=$MODE"
-../programs/ssl/ssl_server2 $P_SERVER_ARGS force_version=$MODE > /dev/null &
+log "../programs/ssl/ssl_server2 server_addr=0.0.0.0 $P_SERVER_ARGS force_version=$MODE"
+../programs/ssl/ssl_server2 server_addr=0.0.0.0 $P_SERVER_ARGS force_version=$MODE > /dev/null &
 PROCESS_ID=$!
 
 sleep 1