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.