I have written a patch to provide a new OS native sockaddr type (called
apr_os_sockaddr_t).
The new functions apr_os_sockaddr_get() / apr_os_sockaddr_put() allow to
convert from / to the apr_sockaddr_t (like apr_os_socket_t / apr_socket_t
conversion).

Unlike apr_sockaddr_t, this "serialized" type can be placed in shared memory
for multiple processes to use it.
I find it very useful for an apache's mod_proxy patch I'm writting (and
submitting to dev@httpd), where the current backend address is updated
according to a TTL parameter (and shared between the children).
The sockaddr info has to be in the scoreboard for this to be feasible.

Finally, the patch also provides a apr_sockaddr_dup function which is
terribly missing (IMHO), one may want to copy an address from a pool to
another without a new DNS lookup.

The joined patches are for trunk and 1.4.x.
Thanks for your feedback,
Yann.
Index: network_io/unix/sockaddr.c
===================================================================
--- network_io/unix/sockaddr.c	(revision 1095053)
+++ network_io/unix/sockaddr.c	(working copy)
@@ -141,17 +141,23 @@
 void apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port)
 {
     addr->family = family;
-    addr->sa.sin.sin_family = family;
-    if (port) {
-        /* XXX IPv6: assumes sin_port and sin6_port at same offset */
-        addr->sa.sin.sin_port = htons(port);
-        addr->port = port;
-    }
+    addr->sa.family = family;
+    switch (family) {
+    case APR_INET:
+#if APR_HAVE_IPV6
+    case APR_INET6:
+#endif
+        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 {
-        addr->sa.sin.sin_port = htons(port);
+        else {
+            addr->sa.sin.sin_port = htons(port);
+        }
+#endif
     }
-#endif
 
     if (family == APR_INET) {
         addr->salen = sizeof(struct sockaddr_in);
@@ -598,13 +604,7 @@
             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)->ipaddr_ptr = &((*sa)->sa.unx.sun_path);
-            (*sa)->ipaddr_len = (*sa)->addr_str_len;
-
+            apr_sockaddr_vars_set(*sa, APR_UNIX, 0);
             return APR_SUCCESS;
         }
         else
@@ -628,6 +628,78 @@
     return find_addresses(sa, hostname, family, port, flags, p);
 }
 
+APR_DECLARE(apr_status_t) apr_os_sockaddr_get(apr_os_sockaddr_t *osa,
+                                              const apr_sockaddr_t *sa)
+{
+    memcpy(osa, &sa->sa, sizeof *osa);
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_os_sockaddr_put(apr_sockaddr_t **sa,
+                                              const apr_os_sockaddr_t *osa,
+                                              const char *hostname,
+                                              apr_pool_t *p)
+{
+    *sa = apr_pcalloc(p, sizeof **sa);
+    (*sa)->pool = p;
+
+    memcpy(&(*sa)->sa, osa, sizeof (*sa)->sa);
+    if (hostname) {
+        (*sa)->hostname = apr_pstrdup(p, hostname);
+    }
+#if APR_HAVE_SOCKADDR_UN
+    else if (osa->family == APR_UNIX) {
+        (*sa)->hostname = apr_pstrmemdup(p, osa->unx.sun_path, 
+                                         sizeof osa->unx.sun_path);
+    }
+#endif
+    else {
+        apr_sockaddr_ip_get(&(*sa)->hostname, (*sa));
+    }
+
+    /* XXX IPv6: assumes sin_port and sin6_port at same offset */
+    apr_sockaddr_vars_set(*sa, osa->family, ntohs(osa->sin.sin_port));
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_sockaddr_dup(apr_sockaddr_t **newsa,
+                                           const apr_sockaddr_t *sa,
+                                           apr_pool_t *p)
+{
+    const apr_sockaddr_t *s;
+    apr_sockaddr_t *d;
+    *newsa = NULL;
+
+    for (d = NULL, s = sa; s; s = s->next) {
+        /* TODO: APR_ENOMEM ? */
+        if (d) {
+            d->next = apr_pmemdup(p, s, sizeof *s);
+            d = d->next;
+        }
+        else {
+            *newsa = apr_pmemdup(p, s, sizeof *s);
+            d = *newsa;
+        }
+        d->pool = p;
+
+        if (s->hostname) {
+            d->hostname = (s == sa || s->hostname != sa->hostname)
+                          ? apr_pstrdup(p, s->hostname)
+                          : (*newsa)->hostname;
+        }
+        if (s->servname) {
+            d->servname = (s == sa || s->servname != sa->servname)
+                          ? apr_pstrdup(p, s->servname)
+                          : (*newsa)->servname;
+        }
+
+        apr_sockaddr_vars_set(d, s->family, s->port);
+    }
+
+    return APR_SUCCESS;
+}
+
 APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname,
                                           apr_sockaddr_t *sockaddr,
                                           apr_int32_t flags)
Index: include/apr_network_io.h
===================================================================
--- include/apr_network_io.h	(revision 1095053)
+++ include/apr_network_io.h	(working copy)
@@ -224,6 +224,27 @@
 /** @remark use apr_uint16_t just in case some system has a short that isn't 16 bits... */
 typedef apr_uint16_t            apr_port_t;
 
+/** The OS native sockaddr type (union of all the handled sockaddr families). */
+typedef union {
+    /** IPv4 sockaddr structure */
+    struct sockaddr_in sin;
+#if APR_HAVE_IPV6
+    /** IPv6 sockaddr structure */
+    struct sockaddr_in6 sin6;
+#endif
+#if APR_HAVE_SA_STORAGE
+    /** Placeholder to ensure that the size of this union is not
+     * dependent on whether APR_HAVE_IPV6 is defined. */
+    struct sockaddr_storage sas;
+#endif
+#if APR_HAVE_SOCKADDR_UN
+    /** Unix domain socket sockaddr structure */
+    struct sockaddr_un unx;
+#endif
+    /** The sockaddr family (assumes sin/sin6/sun_family at offset zero) */
+    sa_family_t family;
+} apr_os_sockaddr_t;
+
 /** @remark It's defined here as I think it should all be platform safe...
  * @see apr_sockaddr_t
  */
@@ -255,24 +276,8 @@
     /** If multiple addresses were found by apr_sockaddr_info_get(), this 
      *  points to a representation of the next address. */
     apr_sockaddr_t *next;
-    /** Union of either IPv4 or IPv6 sockaddr. */
-    union {
-        /** IPv4 sockaddr structure */
-        struct sockaddr_in sin;
-#if APR_HAVE_IPV6
-        /** IPv6 sockaddr structure */
-        struct sockaddr_in6 sin6;
-#endif
-#if APR_HAVE_SA_STORAGE
-        /** Placeholder to ensure that the size of this union is not
-         * dependent on whether APR_HAVE_IPV6 is defined. */
-        struct sockaddr_storage sas;
-#endif
-#if APR_HAVE_SOCKADDR_UN
-        /** Unix domain socket sockaddr structure */
-        struct sockaddr_un unx;
-#endif
-    } sa;
+    /** The OS native sockaddr type. */
+    apr_os_sockaddr_t sa;
 };
 
 #if APR_HAS_SENDFILE
@@ -422,6 +427,37 @@
 
 
 /**
+ * Get the apr_os_sockaddr_t of an apr_sockaddr_t.
+ * @param osa The apr_os_sockaddr_t of the apr_sockaddr_t.
+ * @param sa The apr_sockaddr_t to get the apr_os_sockaddr_t from.
+ */
+APR_DECLARE(apr_status_t) apr_os_sockaddr_get(apr_os_sockaddr_t *osa,
+                                              const apr_sockaddr_t *sa);
+
+/**
+ * Put an apr_os_sockaddr_t (and hostname) to an apr_sockaddr_t.
+ * @param sa The new apr_sockaddr_t.
+ * @param osa The apr_os_sockaddr_t to put in.
+ * @param hostname The hostname or numeric address string to assign, or
+ *                 NULL to build a hostname that corresponds to the IP address.
+ * @param p The pool for the apr_sockaddr_t and associated storage.
+ */
+APR_DECLARE(apr_status_t) apr_os_sockaddr_put(apr_sockaddr_t **sa,
+                                              const apr_os_sockaddr_t *osa,
+                                              const char *hostname,
+                                              apr_pool_t *p);
+
+/**
+ * Duplicate an apr_sockaddr_t on a(nother) pool.
+ * @param newsa The apr_sockaddr_t duplicata.
+ * @param sa The apr_sockaddr_t to duplicate.
+ * @param p The pool for the duplicata and associated storage.
+ */
+APR_DECLARE(apr_status_t) apr_sockaddr_dup(apr_sockaddr_t **newsa,
+                                           const apr_sockaddr_t *sa,
+                                           apr_pool_t *p);
+
+/**
  * Look up the host name from an apr_sockaddr_t.
  * @param hostname The hostname.
  * @param sa The apr_sockaddr_t.
Index: network_io/unix/sockaddr.c
===================================================================
--- network_io/unix/sockaddr.c	(revision 1095066)
+++ network_io/unix/sockaddr.c	(working copy)
@@ -141,7 +141,7 @@
 void apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port)
 {
     addr->family = family;
-    addr->sa.sin.sin_family = family;
+    addr->sa.family = family;
     if (port) {
         /* XXX IPv6: assumes sin_port and sin6_port at same offset */
         addr->sa.sin.sin_port = htons(port);
@@ -594,6 +594,72 @@
     return find_addresses(sa, hostname, family, port, flags, p);
 }
 
+APR_DECLARE(apr_status_t) apr_os_sockaddr_get(apr_os_sockaddr_t *osa,
+                                              const apr_sockaddr_t *sa)
+{
+    memcpy(osa, &sa->sa, sizeof *osa);
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_os_sockaddr_put(apr_sockaddr_t **sa,
+                                              const apr_os_sockaddr_t *osa,
+                                              const char *hostname,
+                                              apr_pool_t *p)
+{
+    *sa = apr_pcalloc(p, sizeof **sa);
+    (*sa)->pool = p;
+
+    memcpy(&(*sa)->sa, osa, sizeof (*sa)->sa);
+    if (hostname) {
+        (*sa)->hostname = apr_pstrdup(p, hostname);
+    }
+    else {
+        apr_sockaddr_ip_get(&(*sa)->hostname, (*sa));
+    }
+
+    /* XXX IPv6: assumes sin_port and sin6_port at same offset */
+    apr_sockaddr_vars_set(*sa, osa->family, ntohs(osa->sin.sin_port));
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_sockaddr_dup(apr_sockaddr_t **newsa,
+                                           const apr_sockaddr_t *sa,
+                                           apr_pool_t *p)
+{
+    const apr_sockaddr_t *s;
+    apr_sockaddr_t *d;
+    *newsa = NULL;
+
+    for (d = NULL, s = sa; s; s = s->next) {
+        /* TODO: APR_ENOMEM ? */
+        if (d) {
+            d->next = apr_pmemdup(p, s, sizeof *s);
+            d = d->next;
+        }
+        else {
+            *newsa = apr_pmemdup(p, s, sizeof *s);
+            d = *newsa;
+        }
+        d->pool = p;
+
+        if (s->hostname) {
+            d->hostname = (s == sa || s->hostname != sa->hostname)
+                          ? apr_pstrdup(p, s->hostname)
+                          : (*newsa)->hostname;
+        }
+        if (s->servname) {
+            d->servname = (s == sa || s->servname != sa->servname)
+                          ? apr_pstrdup(p, s->servname)
+                          : (*newsa)->servname;
+        }
+
+        apr_sockaddr_vars_set(d, s->family, s->port);
+    }
+
+    return APR_SUCCESS;
+}
+
 APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname,
                                           apr_sockaddr_t *sockaddr,
                                           apr_int32_t flags)
Index: include/apr_network_io.h
===================================================================
--- include/apr_network_io.h	(revision 1095066)
+++ include/apr_network_io.h	(working copy)
@@ -201,6 +201,23 @@
 /** @remark use apr_uint16_t just in case some system has a short that isn't 16 bits... */
 typedef apr_uint16_t            apr_port_t;
 
+/** The OS native sockaddr type (union of all the handled sockaddr families). */
+typedef union {
+    /** IPv4 sockaddr structure */
+    struct sockaddr_in sin;
+#if APR_HAVE_IPV6
+    /** IPv6 sockaddr structure */
+    struct sockaddr_in6 sin6;
+#endif
+#if APR_HAVE_SA_STORAGE
+    /** Placeholder to ensure that the size of this union is not
+     * dependent on whether APR_HAVE_IPV6 is defined. */
+    struct sockaddr_storage sas;
+#endif
+    /** The sockaddr family (assumes sin/sin6_family at offset zero) */
+    sa_family_t family;
+} apr_os_sockaddr_t;
+
 /** @remark It's defined here as I think it should all be platform safe...
  * @see apr_sockaddr_t
  */
@@ -232,20 +249,8 @@
     /** If multiple addresses were found by apr_sockaddr_info_get(), this 
      *  points to a representation of the next address. */
     apr_sockaddr_t *next;
-    /** Union of either IPv4 or IPv6 sockaddr. */
-    union {
-        /** IPv4 sockaddr structure */
-        struct sockaddr_in sin;
-#if APR_HAVE_IPV6
-        /** IPv6 sockaddr structure */
-        struct sockaddr_in6 sin6;
-#endif
-#if APR_HAVE_SA_STORAGE
-        /** Placeholder to ensure that the size of this union is not
-         * dependent on whether APR_HAVE_IPV6 is defined. */
-        struct sockaddr_storage sas;
-#endif
-    } sa;
+    /** The OS native sockaddr type. */
+    apr_os_sockaddr_t sa;
 };
 
 #if APR_HAS_SENDFILE
@@ -393,6 +398,37 @@
                                           apr_pool_t *p);
 
 /**
+ * Get the apr_os_sockaddr_t of an apr_sockaddr_t.
+ * @param osa The apr_os_sockaddr_t of the apr_sockaddr_t.
+ * @param sa The apr_sockaddr_t to get the apr_os_sockaddr_t from.
+ */
+APR_DECLARE(apr_status_t) apr_os_sockaddr_get(apr_os_sockaddr_t *osa,
+                                              const apr_sockaddr_t *sa);
+
+/**
+ * Put an apr_os_sockaddr_t (and hostname) to an apr_sockaddr_t.
+ * @param sa The new apr_sockaddr_t.
+ * @param osa The apr_os_sockaddr_t to put in.
+ * @param hostname The hostname or numeric address string to assign, or
+ *                 NULL to build a hostname that corresponds to the IP address.
+ * @param p The pool for the apr_sockaddr_t and associated storage.
+ */
+APR_DECLARE(apr_status_t) apr_os_sockaddr_put(apr_sockaddr_t **sa,
+                                              const apr_os_sockaddr_t *osa,
+                                              const char *hostname,
+                                              apr_pool_t *p);
+
+/**
+ * Duplicate an apr_sockaddr_t on a(nother) pool.
+ * @param newsa The apr_sockaddr_t duplicata.
+ * @param sa The apr_sockaddr_t to duplicate.
+ * @param p The pool for the duplicata and associated storage.
+ */
+APR_DECLARE(apr_status_t) apr_sockaddr_dup(apr_sockaddr_t **newsa,
+                                           const apr_sockaddr_t *sa,
+                                           apr_pool_t *p);
+
+/**
  * Look up the host name from an apr_sockaddr_t.
  * @param hostname The hostname.
  * @param sa The apr_sockaddr_t.

Reply via email to