[prev in list] [next in list] [prev in thread] [next in thread] 

List:       apr-dev
Subject:    [PATCH] apr_sockaddr with APR_UNIX socket paths longer than sizeof(sun_path)
From:       Yann Ylavic <ylavic.dev () gmail ! com>
Date:       2014-10-07 1:37:59
Message-ID: CAKQ1sVM+C2yFCwDhUo55-h-0Y1CZ5tdFkKJ9YYafD61WqN4o0g () mail ! gmail ! com
[Download RAW message or body]

Hello,

the attached patch allows the APR to handle Unix Domain Socket paths
longer than the the limit imposed by the size of struct sockaddr_un
(for systems that support it, eg. *BSD), with no API/ABI change.

To do so, new functions to manipulate the different type of addresses
and socket internals (about local/remote addresses) are implemented in
network_io/unix/sockaddr.c, and declared in each
include/arch/*/apr_arch_networkio.h, like the existing
apr_sockaddr_vars_set().

This allows to also reuse code for non-unix platforms (Windows, OS/2),
hence all network_io/*/sockets.c have been modified (aligned) to use
them where needed.

The corresponding tests have also been added to the suite.

Unfortunatly I can't test nor even compile on Windows/OS2 currently,
testers welcome (TIA).

Thanks for your feedbacks.

Regards,
Yann.

["apr-trunk-sockaddr.patch" (application/x-download)]

Index: include/apr_portable.h
===================================================================
--- include/apr_portable.h	(revision 1628634)
+++ include/apr_portable.h	(working copy)
@@ -386,6 +386,11 @@ APR_DECLARE(apr_status_t) apr_os_dir_put(apr_dir_t
  * @param cont The socket we are converting to an apr type.
  * @remark If it is a true socket, it is best to call apr_os_sock_make()
  *         and provide APR with more information about the socket.
+ *         The given *sock MUST either point to an existing apr_socket_t or
+ *         be NULL. In the former case, no action is taken by this function
+ *         on the existing os socket descriptor, it is up to the caller to
+ *         close it either with apr_socket_close() before the call or by using
+ *         the corresponding os (native) function on the available descriptor.
  */
 APR_DECLARE(apr_status_t) apr_os_sock_put(apr_socket_t **sock, 
                                           apr_os_sock_t *thesock, 
Index: include/arch/win32/apr_arch_networkio.h
===================================================================
--- include/arch/win32/apr_arch_networkio.h	(revision 1628634)
+++ include/arch/win32/apr_arch_networkio.h	(working copy)
@@ -19,6 +19,7 @@
 
 #include "apr_network_io.h"
 #include "apr_general.h"
+#include "apr_portable.h"
 #include "apr_poll.h"
 
 typedef struct sock_userdata_t sock_userdata_t;
@@ -74,6 +75,11 @@ apr_status_t status_from_res_error(int);
 const char *apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size);
 int apr_inet_pton(int af, const char *src, void *dst);
 void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t);
+void apr_sockaddr_put(apr_sockaddr_t **addr, int family,
+                      const struct sockaddr *sa, apr_socklen_t salen,
+                      const char *hostname, const char *servname,
+                      apr_pool_t *pool);
+void apr_socket_addr_put(apr_socket_t *sock, const apr_os_sock_info_t *info);
 
 #define apr_is_option_set(skt, option)  \
     (((skt)->options & (option)) == (option))
Index: include/arch/os2/apr_arch_networkio.h
===================================================================
--- include/arch/os2/apr_arch_networkio.h	(revision 1628634)
+++ include/arch/os2/apr_arch_networkio.h	(working copy)
@@ -20,6 +20,7 @@
 #include "apr_private.h"
 #include "apr_network_io.h"
 #include "apr_general.h"
+#include "apr_portable.h"
 #include "apr_arch_os2calls.h"
 #include "apr_poll.h"
 
@@ -71,6 +72,11 @@ struct apr_socket_t {
 const char *apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size);
 int apr_inet_pton(int af, const char *src, void *dst);
 void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t);
+void apr_sockaddr_put(apr_sockaddr_t **addr, int family,
+                      const struct sockaddr *sa, apr_socklen_t salen,
+                      const char *hostname, const char *servname,
+                      apr_pool_t *pool);
+void apr_socket_addr_put(apr_socket_t *sock, const apr_os_sock_info_t *info);
 
 #endif  /* ! NETWORK_IO_H */
 
Index: include/arch/unix/apr_arch_networkio.h
===================================================================
--- include/arch/unix/apr_arch_networkio.h	(revision 1628634)
+++ include/arch/unix/apr_arch_networkio.h	(working copy)
@@ -22,6 +22,7 @@
 #include "apr_network_io.h"
 #include "apr_errno.h"
 #include "apr_general.h"
+#include "apr_portable.h"
 #include "apr_lib.h"
 #ifndef WAITIO_USES_POLL
 #include "apr_poll.h"
@@ -129,6 +130,11 @@ struct apr_socket_t {
 const char *apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size);
 int apr_inet_pton(int af, const char *src, void *dst);
 void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t);
+void apr_sockaddr_put(apr_sockaddr_t **addr, int family,
+                      const struct sockaddr *sa, apr_socklen_t salen,
+                      const char *hostname, const char *servname,
+                      apr_pool_t *pool);
+void apr_socket_addr_put(apr_socket_t *sock, const apr_os_sock_info_t *info);
 
 #define apr_is_option_set(skt, option)  \
     (((skt)->options & (option)) == (option))
Index: include/apr_network_io.h
===================================================================
--- include/apr_network_io.h	(revision 1628634)
+++ include/apr_network_io.h	(working copy)
@@ -784,6 +784,7 @@ APR_DECLARE(int) apr_sockaddr_is_wildcard(const ap
 * Return the type of the socket.
 * @param sock The socket to query.
 * @param type The returned type (e.g., SOCK_STREAM).
+ * @return non-zero if the type cannot be determined.
 */
 APR_DECLARE(apr_status_t) apr_socket_type_get(apr_socket_t *sock,
                                               int *type);
Index: network_io/unix/sockaddr.c
===================================================================
--- network_io/unix/sockaddr.c	(revision 1628634)
+++ network_io/unix/sockaddr.c	(working copy)
@@ -77,39 +77,95 @@ static void *getservbyname(const char *name, const
 }
 #endif
 
-static apr_status_t get_local_addr(apr_socket_t *sock)
+static apr_status_t get_sock_addr(apr_socket_t *sock, apr_interface_e which)
 {
-    sock->local_addr->salen = sizeof(sock->local_addr->sa);
-    if (getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa,
-                    &sock->local_addr->salen) < 0) {
-        return apr_get_netos_error();
+    int rc;
+    apr_sockaddr_t *sa;
+
+    if (which == APR_LOCAL) {
+        sa = sock->local_addr;
+        sa->salen = sizeof(sa->sa);
+        rc = getsockname(sock->socketdes,
+                         (struct sockaddr *)&sa->sa,
+                         &sa->salen);
     }
     else {
-        sock->local_port_unknown = sock->local_interface_unknown = 0;
-        /* XXX assumes sin_port and sin6_port at same offset */
-        sock->local_addr->port = ntohs(sock->local_addr->sa.sin.sin_port);
-        return APR_SUCCESS;
+        sa = sock->remote_addr;
+        sa->salen = sizeof(sa->sa);
+        rc = getpeername(sock->socketdes,
+                         (struct sockaddr *)&sa->sa,
+                         &sa->salen);
     }
-}
-
-static apr_status_t get_remote_addr(apr_socket_t *sock)
-{
-    sock->remote_addr->salen = sizeof(sock->remote_addr->sa);
-    if (getpeername(sock->socketdes, (struct sockaddr *)&sock->remote_addr->sa,
-                    &sock->remote_addr->salen) < 0) {
+    if (rc < 0) {
         return apr_get_netos_error();
     }
     else {
-        sock->remote_addr_unknown = 0;
-        /* XXX assumes sin_port and sin6_port at same offset */
-        sock->remote_addr->port = ntohs(sock->remote_addr->sa.sin.sin_port);
-        return APR_SUCCESS;
+        apr_port_t port = 0;
+        int family = sa->sa.sin.sin_family;
+        if (family == APR_INET) {
+            port = ntohs(sa->sa.sin.sin_port);
+        }
+#if APR_HAVE_IPV6
+        else if (family == APR_INET6) {
+            port = ntohs(sa->sa.sin6.sin6_port);
+        }
+#endif
+        else if (family == APR_UNIX) {
+#if !APR_HAVE_SOCKADDR_UN
+            return APR_ENOTIMPL;
+#else
+            /* Always NUL terminate sun_path. */
+            if (sa->salen >= sizeof(sa->sa)) {
+                apr_sockaddr_t *newsa;
+                newsa = apr_pcalloc(sock->pool,
+                                    APR_OFFSETOF(apr_sockaddr_t, sa) +
+                                    sa->salen + 1);
+                memcpy(newsa, sa, APR_OFFSETOF(apr_sockaddr_t, sa));
+                newsa->salen = sa->salen + 1;
+                if (which == APR_LOCAL) {
+                    rc = getsockname(sock->socketdes,
+                                     (struct sockaddr *)&newsa->sa,
+                                     &newsa->salen);
+                    if (rc < 0) {
+                        return apr_get_netos_error();
+                    }
+                    sock->local_addr = newsa;
+                }
+                else {
+                    rc = getpeername(sock->socketdes,
+                                     (struct sockaddr *)&newsa->sa,
+                                     &newsa->salen);
+                    if (rc < 0) {
+                        return apr_get_netos_error();
+                    }
+                    sock->remote_addr = newsa;
+                }
+                sa = newsa;
+            }
+            ((char*)&sa->sa)[sa->salen] = '\0';
+#endif
+        }
+        apr_sockaddr_vars_set(sa, family, port);
     }
+
+    return APR_SUCCESS;
 }
 
 APR_DECLARE(apr_status_t) apr_sockaddr_ip_getbuf(char *buf, apr_size_t buflen,
                                                  apr_sockaddr_t *sockaddr)
 {
+#if APR_HAVE_SOCKADDR_UN
+    if (sockaddr->family == APR_UNIX) {
+        char *end = apr_cpystrn(buf, sockaddr->sa.unx.sun_path, buflen);
+        if (sockaddr->sa.unx.sun_path[end - buf] == '\0') {
+            return APR_SUCCESS;
+        }
+        else {
+            return APR_ENOSPC;
+        }
+    }
+#endif
+
     if (!apr_inet_ntop(sockaddr->family, sockaddr->ipaddr_ptr, buf, buflen)) {
         return APR_ENOSPC;
     }
@@ -142,10 +198,10 @@ void apr_sockaddr_vars_set(apr_sockaddr_t *addr, i
 {
     addr->family = family;
     addr->sa.sin.sin_family = family;
+    addr->port = port;
     if (port) {
         /* XXX IPv6: assumes sin_port and sin6_port at same offset */
         addr->sa.sin.sin_port = htons(port);
-        addr->port = port;
     }
 #if AIX_SERVNAME_HACK
     else {
@@ -169,35 +225,113 @@ void apr_sockaddr_vars_set(apr_sockaddr_t *addr, i
 #endif
 #if APR_HAVE_SOCKADDR_UN
     else if (family == APR_UNIX) {
-        addr->salen = sizeof(struct sockaddr_un);
-        addr->addr_str_len = sizeof(addr->sa.unx.sun_path);;
+        apr_socklen_t pathlen = strlen(addr->sa.unx.sun_path);
+        addr->salen = APR_OFFSETOF(struct sockaddr_un, sun_path) + pathlen;
+        addr->addr_str_len = pathlen + 1;
         addr->ipaddr_ptr = &(addr->sa.unx.sun_path);
-        addr->ipaddr_len = addr->addr_str_len;
+        addr->ipaddr_len = pathlen;
+        addr->port = 0;
     }
 #endif
 }
 
+void apr_sockaddr_put(apr_sockaddr_t **addr, int family,
+                      const struct sockaddr *sa, apr_socklen_t salen,
+                      const char *hostname, const char *servname,
+                      apr_pool_t *pool)
+{
+    apr_size_t len;
+    apr_port_t port = 0;
+
+    if (salen == 0) {
+        if (family == APR_INET) {
+            salen = sizeof(struct sockaddr_in);
+        }
+#if APR_HAVE_IPV6
+        else if (family == APR_INET6) {
+            salen = sizeof(struct sockaddr_in6);
+        }
+#endif
+#if APR_HAVE_SOCKADDR_UN
+        else if (family == APR_UNIX) {
+            struct sockaddr_un *sun = (struct sockaddr_un *)sa;
+            salen = APR_OFFSETOF(struct sockaddr_un, sun_path) +
+                    strlen(sun->sun_path);
+        }
+#endif
+    }
+    len = APR_OFFSETOF(apr_sockaddr_t, sa) + salen;
+#if APR_HAVE_SOCKADDR_UN
+    if (family == APR_UNIX) {
+        len++;
+    }
+#endif
+    if (len < sizeof(apr_sockaddr_t)) {
+        len = sizeof(apr_sockaddr_t);
+    }
+    *addr = apr_pcalloc(pool, len);
+    memcpy(&(*addr)->sa, sa, salen);
+    (*addr)->hostname = apr_pstrdup(pool, hostname);
+    (*addr)->servname = apr_pstrdup(pool, servname);
+    (*addr)->pool = pool;
+
+    if (family == APR_INET) {
+        port = ntohs((*addr)->sa.sin.sin_port);
+    }
+#if APR_HAVE_IPV6
+    else if (family == APR_INET6) {
+        port = ntohs((*addr)->sa.sin6.sin6_port);
+    }
+#endif
+#if APR_HAVE_SOCKADDR_UN
+    else if (family == APR_UNIX) {
+        ((char*)&(*addr)->sa)[salen] = '\0';
+    }
+#endif
+
+    apr_sockaddr_vars_set(*addr, family, port);
+}
+
+void apr_socket_addr_put(apr_socket_t *sock, const apr_os_sock_info_t *info)
+{
+    /* XXX: apr_os_sock_info_t does not not allow to specify
+     * the length of the struct sockaddr (eg. local_len for 
+     * local_addr, or remote_len for remote_addr), so with
+     * APR_UNIX we asume that the sun_path is NUL terminated.
+     */
+    if (info->local) {
+        apr_sockaddr_put(&sock->local_addr, info->family,
+                         info->local, 0, NULL, NULL, sock->pool);
+        sock->local_port_unknown = sock->local_interface_unknown = 0;
+    }
+    if (info->remote) {
+        apr_sockaddr_put(&sock->remote_addr, info->family,
+                         info->remote, 0, NULL, NULL, sock->pool);
+        sock->remote_addr_unknown = 0;
+    }
+}
+
 APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa,
                                            apr_interface_e which,
                                            apr_socket_t *sock)
 {
     if (which == APR_LOCAL) {
         if (sock->local_interface_unknown || sock->local_port_unknown) {
-            apr_status_t rv = get_local_addr(sock);
-
+            apr_status_t rv = get_sock_addr(sock, which);
             if (rv != APR_SUCCESS) {
                 return rv;
             }
+            sock->local_port_unknown = sock->local_interface_unknown = 0;
         }
         *sa = sock->local_addr;
     }
     else if (which == APR_REMOTE) {
         if (sock->remote_addr_unknown) {
-            apr_status_t rv = get_remote_addr(sock);
-
+            apr_status_t rv = get_sock_addr(sock, which);
             if (rv != APR_SUCCESS) {
                 return rv;
             }
+            sock->remote_addr_unknown = 0;
         }
         *sa = sock->remote_addr;
     }
@@ -625,26 +759,32 @@ APR_DECLARE(apr_status_t) apr_sockaddr_info_get(ap
     if (family == APR_UNIX) {
 #if APR_HAVE_SOCKADDR_UN
         if (hostname) {
-            *sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
+            apr_socklen_t salen, pathlen = strlen(hostname);
+            salen = APR_OFFSETOF(struct sockaddr_un, sun_path) + pathlen;
+            /* Always NUL terminate sun_path. */
+            if (salen >= sizeof((*sa)->sa)) {
+                *sa = apr_pcalloc(p, APR_OFFSETOF(apr_sockaddr_t, sa) +
+                                     salen + 1);
+            }
+            else {
+                *sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
+            }
             (*sa)->pool = p;
-            apr_cpystrn((*sa)->sa.unx.sun_path, hostname,
-                        sizeof((*sa)->sa.unx.sun_path));
-            (*sa)->hostname = apr_pstrdup(p, hostname);
-            (*sa)->family = APR_UNIX;
-            (*sa)->sa.unx.sun_family = APR_UNIX;
-            (*sa)->salen = sizeof(struct sockaddr_un);
-            (*sa)->addr_str_len = sizeof((*sa)->sa.unx.sun_path);
+            (*sa)->salen = salen;
+            (*sa)->addr_str_len = pathlen + 1;
+            (*sa)->hostname = apr_pstrmemdup(p, hostname, pathlen);
+            (*sa)->family = (*sa)->sa.unx.sun_family = APR_UNIX;
+            memcpy((*sa)->sa.unx.sun_path, hostname, pathlen);
             (*sa)->ipaddr_ptr = &((*sa)->sa.unx.sun_path);
-            (*sa)->ipaddr_len = (*sa)->addr_str_len;
-
+            (*sa)->ipaddr_len = pathlen;
             return APR_SUCCESS;
         }
-        else
+        else {
+            return APR_EINVAL;
+        }
+#else
+        return APR_ENOTIMPL;
 #endif
-        {
-            *sa = NULL;
-            return APR_ENOTIMPL;
-        }
     }
 #if !APR_HAVE_IPV6
     /* What may happen is that APR is not IPv6-enabled, but we're still
@@ -668,11 +808,17 @@ APR_DECLARE(apr_status_t) apr_sockaddr_info_copy(a
     const apr_sockaddr_t *s;
 
     for (*dst = d = NULL, s = src; s; s = s->next) {
+        apr_size_t n = sizeof(*s);
+#if APR_HAVE_SOCKADDR_UN
+        if (s->family == APR_UNIX && s->salen >= sizeof(s->sa)) {
+            n += s->salen - sizeof(s->sa) + 1;
+        }
+#endif
         if (!d) {
-            *dst = d = apr_pmemdup(p, s, sizeof *s);
+            *dst = d = apr_pmemdup(p, s, n);
         }
         else {
-            d = d->next = apr_pmemdup(p, s, sizeof *s);
+            d = d->next = apr_pmemdup(p, s, n);
         }
         if (s->hostname) {
             if (s == src || s->hostname != src->hostname) {
@@ -693,6 +839,7 @@ APR_DECLARE(apr_status_t) apr_sockaddr_info_copy(a
         d->pool = p;
         apr_sockaddr_vars_set(d, s->family, s->port);
     }
+
     return APR_SUCCESS;
 }
 
@@ -925,6 +1072,11 @@ APR_DECLARE(int) apr_sockaddr_is_wildcard(const ap
 #endif
     ] = {0};
 
+#if APR_HAVE_SOCKADDR_UN
+    if (addr->family == APR_UNIX) {
+        return 0;
+    }
+#endif
     if (addr->ipaddr_ptr /* IP address initialized */
         && addr->ipaddr_len <= sizeof inaddr_any) { /* else bug elsewhere? */
         if (!memcmp(inaddr_any, addr->ipaddr_ptr, addr->ipaddr_len)) {
Index: network_io/unix/sockets.c
===================================================================
--- network_io/unix/sockets.c	(revision 1628634)
+++ network_io/unix/sockets.c	(working copy)
@@ -26,15 +26,6 @@
 #define close closesocket
 #endif /* BEOS_R5 */
 
-#if APR_HAVE_SOCKADDR_UN
-#define GENERIC_INADDR_ANY_LEN  sizeof(struct sockaddr_un)
-#else
-#define GENERIC_INADDR_ANY_LEN  16
-#endif
-
-/* big enough for IPv4, IPv6 and optionally sun_path */
-static char generic_inaddr_any[GENERIC_INADDR_ANY_LEN] = {0};
-
 static apr_status_t socket_cleanup(void *sock)
 {
     apr_socket_t *thesocket = sock;
@@ -78,8 +69,18 @@ static void set_socket_vars(apr_socket_t *sock, in
 {
     sock->type = type;
     sock->protocol = protocol;
-    apr_sockaddr_vars_set(sock->local_addr, family, 0);
-    apr_sockaddr_vars_set(sock->remote_addr, family, 0);
+    if (sock->local_addr == NULL) {
+        sock->local_addr = (apr_sockaddr_t *)apr_pcalloc(sock->pool,
+                                                       sizeof(apr_sockaddr_t));
+        sock->local_addr->pool = sock->pool;
+        apr_sockaddr_vars_set(sock->local_addr, family, 0);
+    }
+    if (sock->remote_addr == NULL) {
+        sock->remote_addr = (apr_sockaddr_t *)apr_pcalloc(sock->pool,
+                                                       sizeof(apr_sockaddr_t));
+        sock->remote_addr->pool = sock->pool;
+        apr_sockaddr_vars_set(sock->remote_addr, family, 0);
+    }
     sock->options = 0;
 #if defined(BEOS) && !defined(BEOS_BONE)
     /* BeOS pre-BONE has TCP_NODELAY on by default and it can't be
@@ -93,13 +94,9 @@ static void alloc_socket(apr_socket_t **new, apr_p
 {
     *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t));
     (*new)->pool = p;
-    (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
-                                                       sizeof(apr_sockaddr_t));
-    (*new)->local_addr->pool = p;
-    (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
-                                                        sizeof(apr_sockaddr_t));
-    (*new)->remote_addr->pool = p;
     (*new)->remote_addr_unknown = 1;
+    (*new)->local_port_unknown = (*new)->local_interface_unknown = 1;
+
 #ifndef WAITIO_USES_POLL
     /* Create a pollset with room for one descriptor. */
     /* ### check return codes */
@@ -130,11 +127,13 @@ apr_status_t apr_socket_create(apr_socket_t **new,
         family = APR_INET;
 #endif
     }
+    else if (family == APR_UNIX) {
 #if APR_HAVE_SOCKADDR_UN
-    if (family == APR_UNIX) {
         protocol = 0;
+#else
+        return APR_ENOTIMPL;
+#endif
     }
-#endif
     alloc_socket(new, cont);
 
 #ifndef BEOS_R5
@@ -170,7 +169,6 @@ apr_status_t apr_socket_create(apr_socket_t **new,
     if ((*new)->socketdes < 0) {
         return errno;
     }
-    set_socket_vars(*new, family, type, oprotocol);
 
 #ifndef HAVE_SOCK_CLOEXEC
     {
@@ -191,8 +189,11 @@ apr_status_t apr_socket_create(apr_socket_t **new,
     }
 #endif
 
+    set_socket_vars(*new, family, type, oprotocol);
+
     (*new)->timeout = -1;
     (*new)->inherit = 0;
+
     apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup,
                               socket_child_cleanup);
 
@@ -217,17 +218,39 @@ apr_status_t apr_socket_bind(apr_socket_t *sock, a
         return errno;
     }
     else {
-        sock->local_addr = sa;
-        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
+        /* Make local address. */
+        apr_sockaddr_put(&sock->local_addr, sa->sa.sin.sin_family,
+                         (const struct sockaddr*)&sa->sa, sa->salen,
+                         sa->hostname, sa->servname, sock->pool);
+        sock->local_port_unknown = sock->local_interface_unknown = 0;
 #if APR_HAVE_SOCKADDR_UN
         if (sock->local_addr->family == APR_UNIX) {
             sock->bound = 1;
-            sock->local_port_unknown = 1;
+            /* Local port and interface have no meaning for UDS,
+             * pretend we know them to avoid further resolution,
+             * hence keep unknown things to 0.
+             */
         }
         else
 #endif
-        if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */
-            sock->local_port_unknown = 1; /* kernel got us an ephemeral port */
+        {
+            /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
+            /* no need for ntohs() when comparing w/ 0 */
+            if (sock->local_addr->sa.sin.sin_port == 0) {
+                /* kernel got us an ephemeral port */
+                sock->local_port_unknown = 1;
+            }
+            if (apr_sockaddr_is_wildcard(sock->local_addr)) {
+                /* If the interface address inside the listening socket's
+                 * local_addr wasn't up-to-date, we don't know local interface
+                 * of the connected socket either.
+                 *
+                 * If the listening socket was not bound to a specific
+                 * interface, we don't know the local_addr of the connected
+                 * socket.
+                 */
+                sock->local_interface_unknown = 1;
+            }
         }
         return APR_SUCCESS;
     }
@@ -277,59 +300,66 @@ apr_status_t apr_socket_accept(apr_socket_t **new,
         return APR_EINTR;
     }
 #endif
+
     alloc_socket(new, connection_context);
 
-    /* Set up socket variables -- note that it may be possible for
-     * *new to be an AF_INET socket when sock is AF_INET6 in some
-     * dual-stack configurations, so ensure that the remote_/local_addr
-     * structures are adjusted for the family of the accepted
-     * socket: */
-    set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol);
-
 #ifndef HAVE_POLL
     (*new)->connected = 1;
 #endif
     (*new)->timeout = -1;
 
-    (*new)->remote_addr_unknown = 0;
-
     (*new)->socketdes = s;
 
-    /* Copy in peer's address. */
-    (*new)->remote_addr->sa = sa.sa;
-    (*new)->remote_addr->salen = sa.salen;
+    /* Make peer address. */
+    apr_sockaddr_put(&(*new)->remote_addr, sa.sa.sin.sin_family,
+                     (const struct sockaddr*)&sa.sa, sa.salen,
+                     NULL, NULL, (*new)->pool);
+    (*new)->remote_addr_unknown = 0;
 
-    *(*new)->local_addr = *sock->local_addr;
-
-    /* The above assignment just overwrote the pool entry. Setting the local_addr 
-       pool for the accepted socket back to what it should be.  Otherwise all 
-       allocations for this socket will come from a server pool that is not
-       freed until the process goes down.*/
-    (*new)->local_addr->pool = connection_context;
-
-    /* fix up any pointers which are no longer valid */
-    if (sock->local_addr->sa.sin.sin_family == AF_INET) {
-        (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr;
-    }
-#if APR_HAVE_IPV6
-    else if (sock->local_addr->sa.sin.sin_family == AF_INET6) {
-        (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr;
-    }
-#endif
+    /* Make local address. */
+    apr_sockaddr_put(&(*new)->local_addr, sa.sa.sin.sin_family,
+                     (const struct sockaddr*)&sock->local_addr->sa,
+                     sock->local_addr->salen,
+                     sock->local_addr->hostname,
+                     sock->local_addr->servname,
+                     (*new)->pool);
+    (*new)->local_port_unknown = 0;
+    (*new)->local_interface_unknown = 0;
 #if APR_HAVE_SOCKADDR_UN
-    else if (sock->local_addr->sa.sin.sin_family == AF_UNIX) {
-        *(*new)->remote_addr = *sock->local_addr;
-        (*new)->local_addr->ipaddr_ptr = &((*new)->local_addr->sa.unx.sun_path);
-        (*new)->remote_addr->ipaddr_ptr = &((*new)->remote_addr->sa.unx.sun_path);
+    if (sa.sa.sin.sin_family == APR_UNIX) {
+        /* Local port and interface have no meaning for UDS,
+         * pretend we know them to avoid further resolution,
+         * hence keep unknown things to 0.
+         */
     }
-    if (sock->local_addr->sa.sin.sin_family != AF_UNIX)
+    else
 #endif
-    (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port);
-    if (sock->local_port_unknown) {
-        /* not likely for a listening socket, but theoretically possible :) */
-        (*new)->local_port_unknown = 1;
+    {
+        if ((*new)->local_addr->port == 0) {
+            /* not likely for a listening socket,
+             * but theoretically possible :) */
+            (*new)->local_port_unknown = 1;
+        }
+        if (apr_sockaddr_is_wildcard(sock->local_addr)) {
+            /* If the interface address inside the listening socket's
+             * local_addr wasn't up-to-date, we don't know local interface
+             * of the connected socket either.
+             *
+             * If the listening socket was not bound to a specific
+             * interface, we don't know the local_addr of the connected
+             * socket.
+             */
+            (*new)->local_interface_unknown = 1;
+        }
     }
 
+    /* Set up socket variables -- note that it may be possible for
+     * *new to be an AF_INET socket when sock is AF_INET6 in some
+     * dual-stack configurations, so ensure that the remote_/local_addr
+     * structures are adjusted for the family of the accepted
+     * socket: */
+    set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol);
+
 #if APR_TCP_NODELAY_INHERITED
     if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) {
         apr_set_option(*new, APR_TCP_NODELAY, 1);
@@ -341,19 +371,6 @@ apr_status_t apr_socket_accept(apr_socket_t **new,
     }
 #endif /* APR_O_NONBLOCK_INHERITED */
 
-    if (sock->local_interface_unknown ||
-        !memcmp(sock->local_addr->ipaddr_ptr,
-                generic_inaddr_any,
-                sock->local_addr->ipaddr_len)) {
-        /* If the interface address inside the listening socket's local_addr wasn't 
-         * up-to-date, we don't know local interface of the connected socket either.
-         *
-         * If the listening socket was not bound to a specific interface, we
-         * don't know the local_addr of the connected socket.
-         */
-        (*new)->local_interface_unknown = 1;
-    }
-
 #ifndef HAVE_ACCEPT4
     {
         int flags;
@@ -385,15 +402,17 @@ apr_status_t apr_socket_connect(apr_socket_t *sock
 
     do {
         rc = connect(sock->socketdes,
-                     (const struct sockaddr *)&sa->sa.sin,
+                     (const struct sockaddr *)&sa->sa,
                      sa->salen);
     } while (rc == -1 && errno == EINTR);
+    if (rc == -1) {
+        rc = errno;
+    }
 
     /* we can see EINPROGRESS the first time connect is called on a non-blocking
      * socket; if called again, we can see EALREADY
      */
-    if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY)
-                   && (sock->timeout > 0)) {
+    if ((rc == EINPROGRESS || rc == EALREADY) && (sock->timeout > 0)) {
         rc = apr_wait_for_io_or_timeout(NULL, sock, 0);
         if (rc != APR_SUCCESS) {
             return rc;
@@ -414,41 +433,56 @@ apr_status_t apr_socket_connect(apr_socket_t *sock
 #endif /* SO_ERROR */
     }
 
-    if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) {
+    if (0 ||
+#if APR_HAVE_SOCKADDR_UN
+            sa->sa.sin.sin_family == APR_UNIX ||
+
+#endif
+            !apr_sockaddr_is_wildcard(sa)) {
         /* A real remote address was passed in.  If the unspecified
          * address was used, the actual remote addr will have to be
          * determined using getpeername() if required. */
         sock->remote_addr_unknown = 0;
 
-        /* Copy the address structure details in. */
-        sock->remote_addr->sa = sa->sa;
-        sock->remote_addr->salen = sa->salen;
-        /* Adjust ipaddr_ptr et al. */
-        apr_sockaddr_vars_set(sock->remote_addr, sa->family, sa->port);
+        /* Make remote address from connect()ed one. */
+        apr_sockaddr_put(&sock->remote_addr, sa->sa.sin.sin_family,
+                         (const struct sockaddr*)&sa->sa, sa->salen,
+                         sa->hostname, sa->servname, sock->pool);
     }
+    else {
+        sock->remote_addr_unknown = 1;
+    }
 
-    if (sock->local_addr->port == 0) {
-        /* connect() got us an ephemeral port */
-        sock->local_port_unknown = 1;
-    }
+    sock->local_port_unknown = 0;
+    sock->local_interface_unknown = 0;
 #if APR_HAVE_SOCKADDR_UN
-    if (sock->local_addr->sa.sin.sin_family == AF_UNIX) {
-        /* Assign connect address as local. */
-        sock->local_addr = sa;
+    if (sa->sa.sin.sin_family == APR_UNIX) {
+        /* Make local address from connect()ed one. */
+        apr_sockaddr_put(&sock->local_addr, sa->sa.sin.sin_family,
+                         (const struct sockaddr*)&sa->sa, sa->salen,
+                         sa->hostname, sa->servname, sock->pool);
+        /* Local port and interface have no meaning for UDS,
+         * pretend we know them to avoid further resolution,
+         * hence keep unknown things set to 0 above.
+         */
     }
     else
 #endif
-    if (!memcmp(sock->local_addr->ipaddr_ptr,
-                generic_inaddr_any,
-                sock->local_addr->ipaddr_len)) {
-        /* not bound to specific local interface; connect() had to assign
-         * one for the socket
-         */
-        sock->local_interface_unknown = 1;
+    {
+        if (sock->local_addr->port == 0) {
+            /* connect() got us an ephemeral port */
+            sock->local_port_unknown = 1;
+        }
+        if (apr_sockaddr_is_wildcard(sock->local_addr)) {
+            /* not bound to specific local interface; connect() had to assign
+             * one for the socket
+             */
+            sock->local_interface_unknown = 1;
+        }
     }
 
-    if (rc == -1 && errno != EISCONN) {
-        return errno;
+    if (rc && rc != EISCONN) {
+        return rc;
     }
 
 #ifndef HAVE_POLL
@@ -508,49 +542,45 @@ apr_status_t apr_os_sock_make(apr_socket_t **apr_s
                               apr_pool_t *cont)
 {
     alloc_socket(apr_sock, cont);
-    set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol);
+
+#if !APR_HAVE_SOCKADDR_UN
+    if (os_sock_info->family == APR_UNIX) {
+        return APR_ENOTIMPL;
+    }
+#endif
+
     (*apr_sock)->timeout = -1;
     (*apr_sock)->socketdes = *os_sock_info->os_sock;
-    if (os_sock_info->local) {
-        memcpy(&(*apr_sock)->local_addr->sa.sin, 
-               os_sock_info->local, 
-               (*apr_sock)->local_addr->salen);
-        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
-        (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port);
-    }
-    else {
-        (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1;
-    }
+#ifndef HAVE_POLL
     if (os_sock_info->remote) {
-#ifndef HAVE_POLL
         (*apr_sock)->connected = 1;
+    }
 #endif
-        memcpy(&(*apr_sock)->remote_addr->sa.sin, 
-               os_sock_info->remote,
-               (*apr_sock)->remote_addr->salen);
-        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
-        (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port);
-    }
-    else {
-        (*apr_sock)->remote_addr_unknown = 1;
-    }
-        
-    (*apr_sock)->inherit = 0;
+
+    apr_socket_addr_put((*apr_sock), os_sock_info);
+    set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type,
+                    os_sock_info->protocol);
+
     apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), 
                               socket_cleanup, socket_cleanup);
     return APR_SUCCESS;
 }
 
 apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, 
-                           apr_pool_t *cont)
+                             apr_pool_t *cont)
 {
-    /* XXX Bogus assumption that *sock points at anything legit */
+    /* XXX: *sock must point to something legit or be NULL
+     * according to the declaration/doc(xygen).
+     */
     if ((*sock) == NULL) {
+        if (cont == NULL) {
+            return APR_ENOPOOL;
+        }
         alloc_socket(sock, cont);
-        /* XXX IPv6 figure out the family here! */
-        /* XXX figure out the actual socket type here */
-        /* *or* just decide that apr_os_sock_put() has to be told the family and type */
-        set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0);
+        /* Let's wait for the user to ask for them before determining
+         * the socket type or the local/remote addresses.
+         */
+        set_socket_vars(*sock, APR_UNSPEC, SOCK_STREAM, 0);
         (*sock)->timeout = -1;
     }
     (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1;
Index: network_io/win32/sockets.c
===================================================================
--- network_io/win32/sockets.c	(revision 1628634)
+++ network_io/win32/sockets.c	(working copy)
@@ -24,8 +24,6 @@
 #include "apr_arch_inherit.h"
 #include "apr_arch_misc.h"
 
-static char generic_inaddr_any[16] = {0}; /* big enough for IPv4 or IPv6 */
-
 static apr_status_t socket_cleanup(void *sock)
 {
     apr_socket_t *thesocket = sock;
@@ -49,8 +47,18 @@ static void set_socket_vars(apr_socket_t *sock, in
 {
     sock->type = type;
     sock->protocol = protocol;
-    apr_sockaddr_vars_set(sock->local_addr, family, 0);
-    apr_sockaddr_vars_set(sock->remote_addr, family, 0);
+    if (sock->local_addr == NULL) {
+        sock->local_addr = (apr_sockaddr_t *)apr_pcalloc(sock->pool,
+                                                       sizeof(apr_sockaddr_t));
+        sock->local_addr->pool = sock->pool;
+        apr_sockaddr_vars_set(sock->local_addr, family, 0);
+    }
+    if (sock->remote_addr == NULL) {
+        sock->remote_addr = (apr_sockaddr_t *)apr_pcalloc(sock->pool,
+                                                       sizeof(apr_sockaddr_t));
+        sock->remote_addr->pool = sock->pool;
+        apr_sockaddr_vars_set(sock->remote_addr, family, 0);
+    }
 #if APR_HAVE_IPV6
     /* hard-coded behavior for older Windows IPv6 */
     if (apr_os_level < APR_WIN_VISTA && family == AF_INET6) {
@@ -62,14 +70,8 @@ static void alloc_socket(apr_socket_t **new, apr_p
 {
     *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t));
     (*new)->pool = p;
-    (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
-                                                       sizeof(apr_sockaddr_t));
-    (*new)->local_addr->pool = p;
-    
-    (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
-                                                        sizeof(apr_sockaddr_t));
-    (*new)->remote_addr->pool = p;
     (*new)->remote_addr_unknown = 1;
+    (*new)->local_port_unknown = (*new)->local_interface_unknown = 1;
 
     /* Create a pollset with room for one descriptor. */
     /* ### check return codes */
@@ -91,11 +93,11 @@ APR_DECLARE(apr_status_t) apr_socket_create(apr_so
     int downgrade = (family == AF_UNSPEC);
 #endif
 
-    if (family == AF_UNSPEC) {
+    if (family == APR_UNSPEC) {
 #if APR_HAVE_IPV6
-        family = AF_INET6;
+        family = APR_INET6;
 #else
-        family = AF_INET;
+        family = APR_INET;
 #endif
     }
 
@@ -107,7 +109,7 @@ APR_DECLARE(apr_status_t) apr_socket_create(apr_so
     (*new)->socketdes = socket(family, type, protocol);
 #if APR_HAVE_IPV6
     if ((*new)->socketdes == INVALID_SOCKET && downgrade) {
-        family = AF_INET;
+        family = APR_INET;
         (*new)->socketdes = socket(family, type, protocol);
     }
 #endif
@@ -212,10 +214,25 @@ APR_DECLARE(apr_status_t) apr_socket_bind(apr_sock
         return apr_get_netos_error();
     }
     else {
-        sock->local_addr = sa;
+        /* Make local address. */
+        apr_sockaddr_put(&sock->local_addr, sa->sa.sin.sin_family,
+                         (const struct sockaddr*)&sa->sa, sa->salen,
+                         sa->hostname, sa->servname, sock->pool);
+        sock->local_port_unknown = sock->local_interface_unknown = 0;
         if (sock->local_addr->sa.sin.sin_port == 0) {
             sock->local_port_unknown = 1; /* ephemeral port */
         }
+        if (apr_sockaddr_is_wildcard(sock->local_addr)) {
+            /* If the interface address inside the listening socket's
+             * local_addr wasn't up-to-date, we don't know local interface
+             * of the connected socket either.
+             *
+             * If the listening socket was not bound to a specific
+             * interface, we don't know the local_addr of the connected
+             * socket.
+             */
+            sock->local_interface_unknown = 1;
+        }
         return APR_SUCCESS;
     }
 }
@@ -233,56 +250,57 @@ APR_DECLARE(apr_status_t) apr_socket_accept(apr_so
                                             apr_socket_t *sock, apr_pool_t *p)
 {
     SOCKET s;
-#if APR_HAVE_IPV6
-    struct sockaddr_storage sa;
-#else
-    struct sockaddr sa;
-#endif
-    int salen = sizeof(sock->remote_addr->sa);
+    apr_sockaddr_t sa;
 
+    sa.salen = sizeof(sa.sa);
+
     /* Don't allocate the memory until after we call accept. This allows
        us to work with nonblocking sockets. */
-    s = accept(sock->socketdes, (struct sockaddr *)&sa, &salen);
+    s = accept(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen);
     if (s == INVALID_SOCKET) {
         return apr_get_netos_error();
     }
 
     alloc_socket(new, p);
-    set_socket_vars(*new, sock->local_addr->sa.sin.sin_family, SOCK_STREAM, 
-                    sock->protocol);
 
     (*new)->timeout = -1;   
     (*new)->disconnected = 0;
 
     (*new)->socketdes = s;
-    /* XXX next line looks bogus w.r.t. AF_INET6 support */
-    (*new)->remote_addr->salen = sizeof((*new)->remote_addr->sa);
-    memcpy (&(*new)->remote_addr->sa, &sa, salen);
+
+    /* Make peer address. */
+    apr_sockaddr_put(&(*new)->remote_addr, sa.sa.sin.sin_family,
+                     (const struct sockaddr*)&sa.sa, sa.salen,
+                     NULL, NULL, (*new)->pool);
     (*new)->remote_addr_unknown = 0;
 
-    *(*new)->local_addr = *sock->local_addr;
-
-    /* The above assignment just overwrote the pool entry. Setting the local_addr 
-       pool for the accepted socket back to what it should be.  Otherwise all 
-       allocations for this socket will come from a server pool that is not
-       freed until the process goes down.*/
-    (*new)->local_addr->pool = p;
-
-    /* fix up any pointers which are no longer valid */
-    if (sock->local_addr->sa.sin.sin_family == AF_INET) {
-        (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr;
-    }
-#if APR_HAVE_IPV6
-    else if (sock->local_addr->sa.sin.sin_family == AF_INET6) {
-        (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr;
-    }
-#endif
-    (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port);
-    if (sock->local_port_unknown) {
+    /* Make local address. */
+    apr_sockaddr_put(&(*new)->local_addr, sa.sa.sin.sin_family,
+                     (const struct sockaddr*)&sock->local_addr->sa,
+                     sock->local_addr->salen,
+                     sock->local_addr->hostname,
+                     sock->local_addr->servname,
+                     (*new)->pool);
+    (*new)->local_port_unknown = 0;
+    (*new)->local_interface_unknown = 0;
+    if ((*new)->local_addr->port == 0) {
         /* not likely for a listening socket, but theoretically possible :) */
         (*new)->local_port_unknown = 1;
     }
+    if (apr_sockaddr_is_wildcard((*new)->local_addr)) {
+        /* If the interface address inside the listening socket's
+         * local_addr wasn't up-to-date, we don't know local interface
+         * of the connected socket either.
+         *
+         * If the listening socket was not bound to a specific
+         * interface, we don't know the local_addr of the connected
+         * socket.
+         */
+        (*new)->local_interface_unknown = 1;
+    }
 
+    set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol);
+
 #if APR_TCP_NODELAY_INHERITED
     if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) {
         apr_set_option(*new, APR_TCP_NODELAY, 1);
@@ -294,19 +312,6 @@ APR_DECLARE(apr_status_t) apr_socket_accept(apr_so
     }
 #endif /* APR_O_NONBLOCK_INHERITED */
 
-    if (sock->local_interface_unknown ||
-        !memcmp(sock->local_addr->ipaddr_ptr,
-                generic_inaddr_any,
-                sock->local_addr->ipaddr_len)) {
-        /* If the interface address inside the listening socket's local_addr wasn't
-         * up-to-date, we don't know local interface of the connected socket either.
-         *
-         * If the listening socket was not bound to a specific interface, we
-         * don't know the local_addr of the connected socket.
-         */
-        (*new)->local_interface_unknown = 1;
-    }
-
     apr_pool_cleanup_register((*new)->pool, (void *)(*new), 
                         socket_cleanup, apr_pool_cleanup_null);
     return APR_SUCCESS;
@@ -387,23 +392,28 @@ APR_DECLARE(apr_status_t) apr_socket_connect(apr_s
         }
     }
 
-    if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) {
+    if (!apr_sockaddr_is_wildcard(sa)) {
         /* A real remote address was passed in.  If the unspecified
          * address was used, the actual remote addr will have to be
          * determined using getpeername() if required. */
         sock->remote_addr_unknown = 0;
 
-        /* Copy the address structure details in. */
-        sock->remote_addr = sa;
+        /* Make remote address from connect()ed one. */
+        apr_sockaddr_put(&sock->remote_addr, sa->sa.sin.sin_family,
+                         (const struct sockaddr*)&sa->sa, sa->salen,
+                         sa->hostname, sa->servname, sock->pool);
     }
+    else {
+        sock->remote_addr_unknown = 1;
+    }
 
-    if (sock->local_addr->sa.sin.sin_port == 0) {
+    sock->local_port_unknown = 0;
+    sock->local_interface_unknown = 0;
+    if (sock->local_addr->port == 0) {
         /* connect() got us an ephemeral port */
         sock->local_port_unknown = 1;
     }
-    if (!memcmp(sock->local_addr->ipaddr_ptr,
-                generic_inaddr_any,
-                sock->local_addr->ipaddr_len)) {
+    if (apr_sockaddr_is_wildcard(sock->local_addr)) {
         /* not bound to specific local interface; connect() had to assign
          * one for the socket
          */
@@ -471,31 +481,14 @@ APR_DECLARE(apr_status_t) apr_os_sock_make(apr_soc
                                            apr_pool_t *cont)
 {
     alloc_socket(apr_sock, cont);
-    set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol);
+
     (*apr_sock)->timeout = -1;
-    (*apr_sock)->disconnected = 0;
     (*apr_sock)->socketdes = *os_sock_info->os_sock;
-    if (os_sock_info->local) {
-        memcpy(&(*apr_sock)->local_addr->sa.sin, 
-               os_sock_info->local, 
-               (*apr_sock)->local_addr->salen);
-        (*apr_sock)->local_addr->pool = cont;
-        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
-        (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port);
-    }
-    else {
-        (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1;
-    }
-    if (os_sock_info->remote) {
-        memcpy(&(*apr_sock)->remote_addr->sa.sin, 
-               os_sock_info->remote,
-               (*apr_sock)->remote_addr->salen);
-        (*apr_sock)->remote_addr->pool = cont;
-        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
-        (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port);
-        (*apr_sock)->remote_addr_unknown = 0;
-    }
-        
+
+    apr_socket_addr_put((*apr_sock), os_sock_info);
+    set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type,
+                    os_sock_info->protocol);
+
     apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), 
                         socket_cleanup, apr_pool_cleanup_null);
 
@@ -506,11 +499,18 @@ APR_DECLARE(apr_status_t) apr_os_sock_put(apr_sock
                                           apr_os_sock_t *thesock,
                                           apr_pool_t *cont)
 {
+    /* XXX: *sock must point to something legit or be NULL
+     * according to the declaration/doc(xygen).
+     */
     if ((*sock) == NULL) {
+        if (cont == NULL) {
+            return APR_ENOPOOL;
+        }
         alloc_socket(sock, cont);
-        /* XXX figure out the actual socket type here */
-        /* *or* just decide that apr_os_sock_put() has to be told the family and type */
-        set_socket_vars(*sock, AF_INET, SOCK_STREAM, 0);
+        /* Let's wait for the user to ask for them before determining
+         * the socket type or the local/remote addresses.
+         */
+        set_socket_vars(*sock, APR_UNSPEC, SOCK_STREAM, 0);
         (*sock)->timeout = -1;
         (*sock)->disconnected = 0;
     }
Index: network_io/os2/sockets.c
===================================================================
--- network_io/os2/sockets.c	(revision 1628634)
+++ network_io/os2/sockets.c	(working copy)
@@ -51,22 +51,26 @@ static void set_socket_vars(apr_socket_t *sock, in
 {
     sock->type = type;
     sock->protocol = protocol;
-    apr_sockaddr_vars_set(sock->local_addr, family, 0);
-    apr_sockaddr_vars_set(sock->remote_addr, family, 0);
+    if (sock->local_addr == NULL) {
+        sock->local_addr = (apr_sockaddr_t *)apr_pcalloc(sock->pool,
+                                                       sizeof(apr_sockaddr_t));
+        sock->local_addr->pool = sock->pool;
+        apr_sockaddr_vars_set(sock->local_addr, family, 0);
+    }
+    if (sock->remote_addr == NULL) {
+        sock->remote_addr = (apr_sockaddr_t *)apr_pcalloc(sock->pool,
+                                                       sizeof(apr_sockaddr_t));
+        sock->remote_addr->pool = sock->pool;
+        apr_sockaddr_vars_set(sock->remote_addr, family, 0);
+    }
 }
 
 static void alloc_socket(apr_socket_t **new, apr_pool_t *p)
 {
     *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t));
     (*new)->pool = p;
-    (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
-                                                       sizeof(apr_sockaddr_t));
-    (*new)->local_addr->pool = p;
-
-    (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
-                                                        sizeof(apr_sockaddr_t));
-    (*new)->remote_addr->pool = p;
     (*new)->remote_addr_unknown = 1;
+    (*new)->local_port_unknown = (*new)->local_interface_unknown = 1;
 
     /* Create a pollset with room for one descriptor. */
     /* ### check return codes */
@@ -86,15 +90,14 @@ APR_DECLARE(apr_status_t) apr_socket_create(apr_so
     apr_pollfd_t pfd;
     int oprotocol = protocol;
 
-    if (family == AF_UNSPEC) {
+    if (family == APR_UNSPEC) {
 #if APR_HAVE_IPV6
-        family = AF_INET6;
+        family = APR_INET6;
 #else
-        family = AF_INET;
+        family = APR_INET;
 #endif
     }
-
-    if (family == APR_UNIX) {
+    else if (family == APR_UNIX) {
         protocol = 0;
     }
 
@@ -103,7 +106,7 @@ APR_DECLARE(apr_status_t) apr_socket_create(apr_so
     (*new)->socketdes = socket(family, type, protocol);
 #if APR_HAVE_IPV6
     if ((*new)->socketdes < 0 && downgrade) {
-        family = AF_INET;
+        family = APR_INET;
         (*new)->socketdes = socket(family, type, protocol);
     }
 #endif
@@ -146,11 +149,25 @@ APR_DECLARE(apr_status_t) apr_socket_bind(apr_sock
              sa->salen) == -1)
         return APR_FROM_OS_ERROR(sock_errno());
     else {
-        sock->local_addr = sa;
-        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
-        if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */
-            sock->local_port_unknown = 1; /* kernel got us an ephemeral port */
+        /* Make local address. */
+        apr_sockaddr_put(&sock->local_addr, sa->sa.sin.sin_family,
+                         (const struct sockaddr*)&sa->sa, sa->salen,
+                         sa->hostname, sa->servname, sock->pool);
+        sock->local_port_unknown = sock->local_interface_unknown = 0;
+        if (sock->local_addr->sa.sin.sin_port == 0) {
+            sock->local_port_unknown = 1; /* ephemeral port */
         }
+        if (apr_sockaddr_is_wildcard(sock->local_addr)) {
+            /* If the interface address inside the listening socket's
+             * local_addr wasn't up-to-date, we don't know local interface
+             * of the connected socket either.
+             *
+             * If the listening socket was not bound to a specific
+             * interface, we don't know the local_addr of the connected
+             * socket.
+             */
+            sock->local_interface_unknown = 1;
+        }
         return APR_SUCCESS;
     }
 }
@@ -182,15 +199,39 @@ APR_DECLARE(apr_status_t) apr_socket_accept(apr_so
         return APR_FROM_OS_ERROR(sock_errno());
     }
 
-    *(*new)->local_addr = *sock->local_addr;
-    (*new)->local_addr->pool = connection_context;
-    (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port);
+    /* Make peer address. */
+    apr_sockaddr_put(&(*new)->remote_addr, sa.sa.sin.sin_family,
+                     (const struct sockaddr*)&sa.sa, sa.salen,
+                     NULL, NULL, (*new)->pool);
+    (*new)->remote_addr_unknown = 0;
 
-    /* fix up any pointers which are no longer valid */
-    if (sock->local_addr->sa.sin.sin_family == AF_INET) {
-        (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr;
+    /* Make local address. */
+    apr_sockaddr_put(&(*new)->local_addr, sa.sa.sin.sin_family,
+                     (const struct sockaddr*)&sock->local_addr->sa,
+                     sock->local_addr->salen,
+                     sock->local_addr->hostname,
+                     sock->local_addr->servname,
+                     (*new)->pool);
+    (*new)->local_port_unknown = 0;
+    (*new)->local_interface_unknown = 0;
+    if ((*new)->local_addr->port == 0) {
+        /* not likely for a listening socket, but theoretically possible :) */
+        (*new)->local_port_unknown = 1;
     }
+    if (apr_sockaddr_is_wildcard((*new)->local_addr)) {
+        /* If the interface address inside the listening socket's
+         * local_addr wasn't up-to-date, we don't know local interface
+         * of the connected socket either.
+         *
+         * If the listening socket was not bound to a specific
+         * interface, we don't know the local_addr of the connected
+         * socket.
+         */
+        (*new)->local_interface_unknown = 1;
+    }
 
+    set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol);
+
     apr_pool_cleanup_register((*new)->pool, (void *)(*new), 
                         socket_cleanup, apr_pool_cleanup_null);
     return APR_SUCCESS;
@@ -204,13 +245,36 @@ APR_DECLARE(apr_status_t) apr_socket_connect(apr_s
         (sock_errno() != SOCEINPROGRESS)) {
         return APR_FROM_OS_ERROR(sock_errno());
     }
+
+    if (!apr_sockaddr_is_wildcard(sa)) {
+        /* A real remote address was passed in.  If the unspecified
+         * address was used, the actual remote addr will have to be
+         * determined using getpeername() if required. */
+        sock->remote_addr_unknown = 0;
+
+        /* Make remote address from connect()ed one. */
+        apr_sockaddr_put(&sock->remote_addr, sa->sa.sin.sin_family,
+                         (const struct sockaddr*)&sa->sa, sa->salen,
+                         sa->hostname, sa->servname, sock->pool);
+    }
     else {
-        int namelen = sizeof(sock->local_addr->sa.sin);
-        getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa.sin, 
-                    &namelen);
-        sock->remote_addr = sa;
-        return APR_SUCCESS;
+        sock->remote_addr_unknown = 1;
     }
+
+    sock->local_port_unknown = 0;
+    sock->local_interface_unknown = 0;
+    if (sock->local_addr->port == 0) {
+        /* connect() got us an ephemeral port */
+        sock->local_port_unknown = 1;
+    }
+    if (apr_sockaddr_is_wildcard(sock->local_addr)) {
+        /* not bound to specific local interface; connect() had to assign
+         * one for the socket
+         */
+        sock->local_interface_unknown = 1;
+    }
+
+    return APR_SUCCESS;
 }
 
 APR_DECLARE(apr_status_t) apr_socket_type_get(apr_socket_t *sock, int *type)
@@ -267,47 +331,38 @@ APR_DECLARE(apr_status_t) apr_os_sock_make(apr_soc
                                            apr_pool_t *cont)
 {
     alloc_socket(apr_sock, cont);
-    set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol);
+
     (*apr_sock)->timeout = -1;
     (*apr_sock)->socketdes = *os_sock_info->os_sock;
-    if (os_sock_info->local) {
-        memcpy(&(*apr_sock)->local_addr->sa.sin, 
-               os_sock_info->local, 
-               (*apr_sock)->local_addr->salen);
-        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
-        (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port);
-    }
-    else {
-        (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1;
-    }
-    if (os_sock_info->remote) {
-        memcpy(&(*apr_sock)->remote_addr->sa.sin, 
-               os_sock_info->remote,
-               (*apr_sock)->remote_addr->salen);
-        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
-        (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port);
-    }
-    else {
-        (*apr_sock)->remote_addr_unknown = 1;
-    }
-        
+
+    apr_socket_addr_put((*apr_sock), os_sock_info);
+    set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type,
+                    os_sock_info->protocol);
+
     apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), 
                         socket_cleanup, apr_pool_cleanup_null);
 
     return APR_SUCCESS;
 }
 
-APR_DECLARE(apr_status_t) apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, apr_pool_t *cont)
+APR_DECLARE(apr_status_t) apr_os_sock_put(apr_socket_t **sock,
+                                          apr_os_sock_t *thesock,
+                                          apr_pool_t *cont)
 {
-    if (cont == NULL) {
-        return APR_ENOPOOL;
-    }
+    /* XXX: *sock must point to something legit or be NULL
+     * according to the declaration/doc(xygen).
+     */
     if ((*sock) == NULL) {
+        if (cont == NULL) {
+            return APR_ENOPOOL;
+        }
         alloc_socket(sock, cont);
-        set_socket_vars(*sock, AF_INET, SOCK_STREAM, 0);
+        /* Let's wait for the user to ask for them before determining
+         * the socket type or the local/remote addresses.
+         */
+        set_socket_vars(*sock, APR_UNSPEC, SOCK_STREAM, 0);
         (*sock)->timeout = -1;
     }
-
     (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1;
     (*sock)->remote_addr_unknown = 1;
     (*sock)->socketdes = *thesock;
Index: strings/apr_snprintf.c
===================================================================
--- strings/apr_snprintf.c	(revision 1628634)
+++ strings/apr_snprintf.c	(working copy)
@@ -449,31 +449,59 @@ static char *conv_apr_sockaddr(apr_sockaddr_t *sa,
     int is_negative;
     apr_size_t sub_len;
     char *ipaddr_str;
+    char trailer;
 
+#if APR_HAVE_SOCKADDR_UN
+    if (sa->family == APR_UNIX) {
+        ipaddr_str = buf_end - NUM_BUF_SIZE;
+        if (apr_sockaddr_ip_getbuf(ipaddr_str, p - ipaddr_str, sa)) {
+            /* Should only fail if the buffer is too small,
+             * mark the returned path as truncated. */
+            *(p - 2) = '?';
+        }
+        /* Add a trailing '=' (like ls -F for sockets). */
+        *len = strlen(ipaddr_str);
+        ipaddr_str[(*len)++] = '=';
+        return ipaddr_str;
+    }
+#endif
     p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len);
-    *--p = ':';
     ipaddr_str = buf_end - NUM_BUF_SIZE;
-    if (apr_sockaddr_ip_getbuf(ipaddr_str, sa->addr_str_len, sa)) {
+#if APR_HAVE_IPV6
+    if (sa->family == APR_INET6 &&
+            !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) {
+        *--p = ':';
+        *ipaddr_str++ = '[';
+        trailer = ']';
+    }
+    else
+#endif
+    trailer = ':';
+    *--p = trailer;
+    if (apr_sockaddr_ip_getbuf(ipaddr_str, p - ipaddr_str, sa)) {
         /* Should only fail if the buffer is too small, which it
          * should not be; but fail safe anyway: */
+        *p = trailer; /* replace the '\0' */
         *--p = '?';
-        *len = buf_end - p;
-        return p;
+        if (trailer == ']') {
+            *--p = '[';
+        }
     }
-    sub_len = strlen(ipaddr_str);
-#if APR_HAVE_IPV6
-    if (sa->family == APR_INET6 &&
-        !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) {
-        *(p - 1) = ']';
-        p -= sub_len + 2;
-        *p = '[';
-        memcpy(p + 1, ipaddr_str, sub_len);
+    else if (*p == '\0') {
+        /* We are already aligned (unlikely). */
+        *p = trailer; /* replace the '\0' */
+        p = ipaddr_str;
     }
-    else
-#endif
-    {
+    else {
+        /* We have to align from :port (likely). */
+        sub_len = strlen(ipaddr_str);
+        if (trailer == ']') {
+            ipaddr_str--;
+            sub_len++;
+        }
         p -= sub_len;
-        memcpy(p, ipaddr_str, sub_len);
+        /* Use memmove since source and destination may overlap */
+        memmove(p, ipaddr_str, sub_len);
     }
 
     *len = buf_end - p;
Index: test/testsock.c
===================================================================
--- test/testsock.c	(revision 1628634)
+++ test/testsock.c	(working copy)
@@ -26,11 +26,14 @@
 #define APR_WANT_BYTEFUNC
 #include "apr_want.h"
 
-#define UNIX_SOCKET_NAME    "/tmp/apr-socket"
-#define IPV4_SOCKET_NAME    "127.0.0.1"
-static char *socket_name = NULL;
-static int   socket_type = APR_INET;
+#define IPV4_SOCKET_NAME "127.0.0.1"
+#define IPV6_SOCKET_NAME "::1"
+#define UNIX_SOCKET_NAME "/tmp/apr-socket"
 
+static const char *socket_name = IPV4_SOCKET_NAME;
+static int         socket_type = APR_INET;
+static int         socket_prot = APR_PROTO_TCP;
+
 static void launch_child(abts_case *tc, apr_proc_t *proc, const char *arg1, apr_pool_t *p)
 {
     apr_procattr_t *procattr;
@@ -86,10 +89,31 @@ static void test_addr_info(abts_case *tc, void *da
     rv = apr_sockaddr_info_get(&sa, "127.0.0.1", APR_UNSPEC, 80, 0, p);
     APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
     ABTS_STR_EQUAL(tc, "127.0.0.1", sa->hostname);
+    ABTS_INT_EQUAL(tc, 80, sa->port);
 
     rc = apr_sockaddr_is_wildcard(sa);
     ABTS_INT_EQUAL(tc, 0, rc);
 
+#if APR_HAVE_IPV6
+    rv = apr_sockaddr_info_get(&sa, IPV6_SOCKET_NAME, APR_UNSPEC, 80, 0, p);
+    APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
+    ABTS_STR_EQUAL(tc, IPV6_SOCKET_NAME, sa->hostname);
+    ABTS_INT_EQUAL(tc, 80, sa->port);
+
+    rc = apr_sockaddr_is_wildcard(sa);
+    ABTS_INT_EQUAL(tc, 0, rc);
+#endif
+
+#if APR_HAVE_SOCKADDR_UN
+    rv = apr_sockaddr_info_get(&sa, UNIX_SOCKET_NAME, APR_UNSPEC, 80, 0, p);
+    APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
+    ABTS_STR_EQUAL(tc, UNIX_SOCKET_NAME, sa->hostname);
+    ABTS_INT_EQUAL(tc, 0, sa->port);
+
+    rc = apr_sockaddr_is_wildcard(sa);
+    ABTS_INT_EQUAL(tc, 0, rc);
+#endif
+
     rv = apr_sockaddr_info_get(&sa, "127.0.0.1", APR_UNSPEC, 0, 0, p);
     APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
     ABTS_STR_EQUAL(tc, "127.0.0.1", sa->hostname);
@@ -102,17 +126,24 @@ static void test_addr_copy(abts_case *tc, void *da
     apr_status_t rv;
     apr_sockaddr_t *sa1, *sa2;
     int rc;
-    const char *hosts[] = {
-        "127.0.0.1",
+    struct {
+        const char *host;
+        apr_port_t port;
+    } entries[] = {
+        {IPV4_SOCKET_NAME, 80},
 #if APR_HAVE_IPV6
-        "::1",
+        {IPV6_SOCKET_NAME, 80},
 #endif
-        NULL
-    }, **host = hosts;
+#if APR_HAVE_SOCKADDR_UN
+        {UNIX_SOCKET_NAME, 0},
+#endif
+        {NULL,             80}
+    }, *entry = entries;
 
     /* Loop up to and including NULL */
     do {
-        rv = apr_sockaddr_info_get(&sa1, *host, APR_UNSPEC, 80, 0, p);
+        rv = apr_sockaddr_info_get(&sa1, entry->host, APR_UNSPEC,
+                                   entry->port, 0, p);
         APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
 
         rv = apr_sockaddr_info_copy(&sa2, sa1, p);
@@ -124,15 +155,18 @@ static void test_addr_copy(abts_case *tc, void *da
 
             rc = apr_sockaddr_equal(sa2, sa1);
             ABTS_INT_NEQUAL(tc, 0, rc);
-            ABTS_INT_EQUAL(tc, 80, sa1->port);
+            ABTS_INT_EQUAL(tc, entry->port, sa1->port);
             ABTS_INT_EQUAL(tc, sa2->port, sa1->port);
-            ABTS_INT_EQUAL(tc, 80, ntohs(sa1->sa.sin.sin_port));
-            ABTS_INT_EQUAL(tc, ntohs(sa2->sa.sin.sin_port), ntohs(sa1->sa.sin.sin_port));
+            if (entry->port) {
+                ABTS_INT_EQUAL(tc, entry->port, ntohs(sa1->sa.sin.sin_port));
+                ABTS_INT_EQUAL(tc, ntohs(sa2->sa.sin.sin_port),
+                                   ntohs(sa1->sa.sin.sin_port));
+            }
 
-            if (*host) {
+            if (entry->host) {
                 ABTS_PTR_NOTNULL(tc, sa1->hostname);
                 ABTS_PTR_NOTNULL(tc, sa2->hostname);
-                ABTS_STR_EQUAL(tc, *host, sa1->hostname);
+                ABTS_STR_EQUAL(tc, entry->host, sa1->hostname);
                 ABTS_STR_EQUAL(tc, sa1->hostname, sa2->hostname);
                 ABTS_TRUE(tc, sa1->hostname != sa2->hostname);
             }
@@ -144,7 +178,7 @@ static void test_addr_copy(abts_case *tc, void *da
         } while ((sa2 = sa2->next, sa1 = sa1->next));
         ABTS_PTR_EQUAL(tc, NULL, sa2);
 
-    } while (*host++);
+    } while ((entry++)->host);
 }
 
 static void test_serv_by_name(abts_case *tc, void *data)
@@ -176,7 +210,7 @@ static apr_socket_t *setup_socket(abts_case *tc)
     rv = apr_sockaddr_info_get(&sa, socket_name, socket_type, 8021, 0, p);
     APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
 
-    rv = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, p);
+    rv = apr_socket_create(&sock, sa->family, SOCK_STREAM, socket_prot, p);
     APR_ASSERT_SUCCESS(tc, "Problem creating socket", rv);
 
     rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1);
@@ -221,7 +255,7 @@ static void test_send(abts_case *tc, void *data)
     APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv);
 
     apr_socket_protocol_get(sock2, &protocol);
-    ABTS_INT_EQUAL(tc, APR_PROTO_TCP, protocol);
+    ABTS_INT_EQUAL(tc, socket_prot, protocol);
     
     length = strlen(DATASTR);
     apr_socket_send(sock2, DATASTR, &length);
@@ -254,7 +288,7 @@ static void test_recv(abts_case *tc, void *data)
     APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv);
 
     apr_socket_protocol_get(sock2, &protocol);
-    ABTS_INT_EQUAL(tc, APR_PROTO_TCP, protocol);
+    ABTS_INT_EQUAL(tc, socket_prot, protocol);
     
     memset(datastr, 0, STRLEN);
     apr_socket_recv(sock2, datastr, &length);
@@ -348,7 +382,7 @@ static void test_timeout(abts_case *tc, void *data
     APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv);
 
     apr_socket_protocol_get(sock2, &protocol);
-    ABTS_INT_EQUAL(tc, APR_PROTO_TCP, protocol);
+    ABTS_INT_EQUAL(tc, socket_prot, protocol);
     
     exit = wait_child(tc, &proc);    
     ABTS_INT_EQUAL(tc, SOCKET_TIMEOUT, exit);
@@ -367,23 +401,25 @@ static void test_print_addr(abts_case *tc, void *d
     apr_sockaddr_t *sa;
     apr_status_t rv;
     char *s;
+    int rc;
 
     rv = apr_sockaddr_info_get(&sa, "0.0.0.0", APR_INET, 80, 0, p);
     APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
 
+    rc = apr_sockaddr_is_wildcard(sa);
+    ABTS_INT_NEQUAL(tc, 0, rc);
+
     s = apr_psprintf(p, "foo %pI bar", sa);
-
     ABTS_STR_EQUAL(tc, "foo 0.0.0.0:80 bar", s);
 
 #if APR_HAVE_IPV6
+    /* sa should be a v4-mapped IPv6 address. */
     rv = apr_sockaddr_info_get(&sa, "::ffff:0.0.0.0", APR_INET6, 80, 0, p);
     APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
     if (rv == APR_SUCCESS)
         ABTS_TRUE(tc, sa != NULL);
     if (rv == APR_SUCCESS && sa) {
-        /* sa should now be a v4-mapped IPv6 address. */
         char buf[128];
-        int rc;
 
         rc = apr_sockaddr_is_wildcard(sa);
         ABTS_INT_NEQUAL(tc, 0, rc);
@@ -391,11 +427,103 @@ static void test_print_addr(abts_case *tc, void *d
         memset(buf, 'z', sizeof buf);
         
         APR_ASSERT_SUCCESS(tc, "could not get IP address",
-                           apr_sockaddr_ip_getbuf(buf, 22, sa));
-        
+                           apr_sockaddr_ip_getbuf(buf, sizeof buf, sa));
         ABTS_STR_EQUAL(tc, "0.0.0.0", buf);
+
+        s = apr_psprintf(p, "%pI", sa);
+        ABTS_STR_EQUAL(tc, "0.0.0.0:80", s);
     }
+
+    /* sa should be a real (though arbitrary choosen) IPv6 address. */
+    rv = apr_sockaddr_info_get(&sa, "fe80::250:56ff:fec0:8", APR_INET6, 80, 0, p);
+    APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
+    if (rv == APR_SUCCESS)
+        ABTS_TRUE(tc, sa != NULL);
+    if (rv == APR_SUCCESS && sa) {
+        char buf[128];
+        int rc;
+
+        rc = apr_sockaddr_is_wildcard(sa);
+        ABTS_INT_EQUAL(tc, 0, rc);
+
+        memset(buf, 'z', sizeof buf);
+        
+        APR_ASSERT_SUCCESS(tc, "could not get IP address",
+                           apr_sockaddr_ip_getbuf(buf, sizeof buf, sa));
+        ABTS_STR_EQUAL(tc, "fe80::250:56ff:fec0:8", buf);
+
+        s = apr_psprintf(p, "%pI", sa);
+        ABTS_STR_EQUAL(tc, "[fe80::250:56ff:fec0:8]:80", s);
+    }
 #endif
+
+#if APR_HAVE_SOCKADDR_UN
+    rv = apr_sockaddr_info_get(&sa, UNIX_SOCKET_NAME, APR_UNIX, 0, 0, p);
+    APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
+    if (rv == APR_SUCCESS)
+        ABTS_TRUE(tc, sa != NULL);
+    if (rv == APR_SUCCESS && sa) {
+        char buf[128];
+        int rc;
+
+        rc = apr_sockaddr_is_wildcard(sa);
+        ABTS_INT_EQUAL(tc, 0, rc);
+
+        memset(buf, 'z', sizeof buf);
+        
+        APR_ASSERT_SUCCESS(tc, "could not get IP address",
+                           apr_sockaddr_ip_getbuf(buf, sizeof buf, sa));
+        ABTS_STR_EQUAL(tc, UNIX_SOCKET_NAME, buf);
+
+        s = apr_psprintf(p, "%pI", sa);
+        ABTS_STR_EQUAL(tc, UNIX_SOCKET_NAME"=", s);
+    }
+    /* Let's try a huge path of length APR_PATH_MAX - 1:
+     * creating a sockaddr should always work, binding
+     * or connecting a socket on that path depends on the
+     * OS though, we won't try this...
+     */
+    {
+        char *sockpath;
+        apr_size_t namelen;
+#define NUM_BUF_SIZE 512 /* from strings/apr_snprintf.c */
+
+        namelen = strlen(UNIX_SOCKET_NAME);
+        sockpath = apr_palloc(p, APR_PATH_MAX + 1);
+        memcpy(sockpath, UNIX_SOCKET_NAME, namelen);
+        memset(sockpath + namelen, 'x', APR_PATH_MAX - namelen - 1);
+        sockpath[APR_PATH_MAX - 1] = '\0';
+
+        rv = apr_sockaddr_info_get(&sa, sockpath, APR_UNIX, 0, 0, p);
+        APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);
+        if (rv == APR_SUCCESS)
+            ABTS_TRUE(tc, sa != NULL);
+        if (rv == APR_SUCCESS && sa) {
+            char *path;
+
+            path = apr_palloc(p, APR_PATH_MAX + 1);
+            memset(path, 'z', APR_PATH_MAX + 1);
+            
+            APR_ASSERT_SUCCESS(tc, "could not get IP address",
+                               apr_sockaddr_ip_getbuf(path, APR_PATH_MAX + 1,
+                                                      sa));
+            ABTS_STR_EQUAL(tc, sockpath, path);
+
+            if (NUM_BUF_SIZE >= APR_PATH_MAX) {
+                sockpath[APR_PATH_MAX - 1] = '=';
+                sockpath[APR_PATH_MAX] = '\0';
+            }
+            else {
+                /* the path will be truncated by apr_psprintf() */
+                sockpath[NUM_BUF_SIZE - 2] = '?';
+                sockpath[NUM_BUF_SIZE - 1] = '=';
+                sockpath[NUM_BUF_SIZE] = '\0';
+            }
+            s = apr_psprintf(p, "%pI", sa);
+            ABTS_STR_EQUAL(tc, sockpath, s);
+        }
+    }
+#endif
 }
 
 static void test_get_addr(abts_case *tc, void *data)
@@ -415,28 +543,16 @@ static void test_get_addr(abts_case *tc, void *dat
                        "get local address of bound socket",
                        apr_socket_addr_get(&sa, APR_LOCAL, ld));
 
-    rv = apr_socket_create(&cd, sa->family, SOCK_STREAM,
-                           APR_PROTO_TCP, subp);
+    rv = apr_socket_create(&cd, sa->family, SOCK_STREAM, socket_prot, subp);
     APR_ASSERT_SUCCESS(tc, "create client socket", rv);
 
     APR_ASSERT_SUCCESS(tc, "enable non-block mode",
                        apr_socket_opt_set(cd, APR_SO_NONBLOCK, 1));
 
-    /* It is valid for a connect() on a socket with NONBLOCK set to
-     * succeed (if the connection can be established synchronously),
-     * but if it does, this test cannot proceed.  */
     rv = apr_socket_connect(cd, sa);
-    if (rv == APR_SUCCESS) {
+    if (rv != APR_SUCCESS && !APR_STATUS_IS_EINPROGRESS(rv)) {
         apr_socket_close(ld);
         apr_socket_close(cd);
-        ABTS_NOT_IMPL(tc, "Cannot test if connect completes "
-                      "synchronously");
-        return;
-    }
-
-    if (!APR_STATUS_IS_EINPROGRESS(rv)) {
-        apr_socket_close(ld);
-        apr_socket_close(cd);
         APR_ASSERT_SUCCESS(tc, "connect to listener", rv);
         return;
     }
@@ -444,7 +560,10 @@ static void test_get_addr(abts_case *tc, void *dat
     APR_ASSERT_SUCCESS(tc, "accept connection",
                        apr_socket_accept(&sd, ld, subp));
     
-    {
+    /* It is valid for a connect() on a socket with NONBLOCK set to
+     * succeed (if the connection can be established synchronously),
+     * and if it does, we don't need to wait here. */
+    if (rv != APR_SUCCESS) {
         /* wait for writability */
         apr_pollfd_t pfd;
         int n;
@@ -484,8 +603,16 @@ static void test_get_addr(abts_case *tc, void *dat
     /* Check equivalence. */
     a = apr_psprintf(p, "%pI fam=%d", sa, sa->family);
     b = apr_psprintf(p, "%pI fam=%d", ca, ca->family);
+    if (socket_type == APR_UNIX && *b == '=') {
+        /* The remote address may be empty (unavailable)
+         * for APR_UNIX, compare from %pI's trailing '='. */
+        a = strchr(a, '=');
+        ABTS_PTR_NOTNULL(tc, a);
+    }
     ABTS_STR_EQUAL(tc, a, b);
 
+    /* Test that the pool of the returned sockaddr objects exactly
+     * match the socket. */
     ABTS_PTR_EQUAL(tc, subp, sa->pool);
     ABTS_PTR_EQUAL(tc, subp, ca->pool);
                        
@@ -610,30 +737,54 @@ static void test_nonblock_inheritance(abts_case *t
 abts_suite *testsock(abts_suite *suite)
 {
     suite = ADD_SUITE(suite)
-    socket_name = IPV4_SOCKET_NAME;
+
     abts_run_test(suite, test_addr_info, NULL);
     abts_run_test(suite, test_addr_copy, NULL);
     abts_run_test(suite, test_serv_by_name, NULL);
+
+    socket_name = IPV4_SOCKET_NAME;
+    socket_type = APR_INET;
+    socket_prot = APR_PROTO_TCP;
     abts_run_test(suite, test_create_bind_listen, NULL);
+    abts_run_test(suite, test_print_addr, NULL);
     abts_run_test(suite, test_send, NULL);
     abts_run_test(suite, test_recv, NULL);
     abts_run_test(suite, test_atreadeof, NULL);
     abts_run_test(suite, test_timeout, NULL);
-    abts_run_test(suite, test_print_addr, NULL);
     abts_run_test(suite, test_get_addr, NULL);
     abts_run_test(suite, test_wait, NULL);
     abts_run_test(suite, test_nonblock_inheritance, NULL);
+
+#if APR_HAVE_IPV6
+    socket_name = IPV6_SOCKET_NAME;
+    socket_type = APR_INET6;
+    socket_prot = APR_PROTO_TCP;
+    abts_run_test(suite, test_create_bind_listen, NULL);
+    abts_run_test(suite, test_send, NULL);
+    abts_run_test(suite, test_recv, NULL);
+    abts_run_test(suite, test_atreadeof, NULL);
+    abts_run_test(suite, test_timeout, NULL);
+    abts_run_test(suite, test_get_addr, NULL);
+    abts_run_test(suite, test_wait, NULL);
+    abts_run_test(suite, test_nonblock_inheritance, NULL);
+#endif
+
 #if APR_HAVE_SOCKADDR_UN
     socket_name = UNIX_SOCKET_NAME;
     socket_type = APR_UNIX;
+    socket_prot = 0;
     /* in case AF_UNIX socket exists from a previous run: */
     apr_file_remove(socket_name, p);
     abts_run_test(suite, test_create_bind_listen, NULL);
     abts_run_test(suite, test_send, NULL);
     abts_run_test(suite, test_recv, NULL);
+    abts_run_test(suite, test_atreadeof, NULL);
     abts_run_test(suite, test_timeout, NULL);
+    abts_run_test(suite, test_get_addr, NULL);
     abts_run_test(suite, test_wait, NULL);
+    abts_run_test(suite, test_nonblock_inheritance, NULL);
 #endif
+
     return suite;
 }
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic