The following patch makes the following changes to APR and
all callers in the apache-2.0 CVS repository:

1) change apr_bind() to take apr_sockaddr_t as second parameter,
   for specifying the local socket address to bind to

2) add apr_get_sockaddr() function for retrieving the local or
   remote apr_sockaddr_t associated with a function

3) tweak apr_getaddrinfo() to handle certain AF_INET6 usage a little
   better   

Concerns?

Would anybody like to see this patch before the next alpha?

Where is the API going from here? (mostly IMHO :) )

. more helper functions are needed for dealing with sockaddrs and
  IP addresses (non-disruptive)

. apr_sendto() and apr_recvfrom() are needed to support normal
  UDP idioms (non-disruptive)

. apr_get_port(), apr_set_port(), apr_get_ipaddr(),
  apr_set_ipaddr() should take apr_sockaddr_t as a parameter,
  not apr_socket_t+APR_LOCAL/APR_REMOTE;
  (a little disruptive, but really a trivial change for apps)

. apr_create_tcp_socket() can go away
  (a little disruptive, but really a trivial change for apps)

. change apr_get_hostname() to apr_getnameinfo(), make it
  take apr_sockaddr_t instead of apr_socket_t+APR_LOCAL/APR_REMOTE,
  let it cache result in apr_sockaddr_t
  (a little disruptive, but really a trivial change for apps)

. get rid of apr_get_remote_name() and apr_get_local_name();
  if an app wants to deal with the native sockaddr structure 
  directly, they can call apr_get_sockaddr() and look in the
  returned apr_sockaddr_t for the native structure
  (a little disruptive, but really a trivial change for apps)

. get rid of apr_get_inaddr(); apr_getaddrinfo() does that
  work + more
  (a little disruptive, but really a trivial change for apps)

. get rid of apr_get_socket_inaddr(); 
  if an app wants to deal with the native IP address structure 
  directly, they can call apr_get_sockaddr() and look in the
  returned apr_sockaddr_t for the native structure
  (a little disruptive, but really a trivial change for apps)

. decide what to do about apr_make_os_sock(): should it play the
  AF_INET/AF_INET6 game and make a socket really work?  currently,
  such a socket is not fully functional even for AF_INET; this isn't 
  terrible, because we save syscalls, and such sockets are usually 
  built only for use with apr_poll()

Where are the internals going from here?

. apr_getaddrinfo() needs to be changed support IPv6 (when the
  platform provides getipnodebyname() or getaddrinfo())

. test better with AF_INET6 and/or UDP to make sure those
  work properly and support expected idioms

. it is high time to get more commonality in the codebase

Index: lib/apr/aprlib.def
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/lib/apr/aprlib.def,v
retrieving revision 1.42
diff -u -r1.42 aprlib.def
--- lib/apr/aprlib.def  2000/11/17 03:45:03     1.42
+++ lib/apr/aprlib.def  2000/11/17 18:59:25
@@ -51,6 +51,7 @@
 
 ;
 ; apr_network_io.h
+        apr_get_sockaddr        @44
         apr_getaddrinfo         @45
         apr_create_socket       @46
        apr_create_tcp_socket   @47
Index: lib/apr/include/apr_network_io.h
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/lib/apr/include/apr_network_io.h,v
retrieving revision 1.72
diff -u -r1.72 apr_network_io.h
--- lib/apr/include/apr_network_io.h    2000/11/17 03:45:01     1.72
+++ lib/apr/include/apr_network_io.h    2000/11/17 18:59:27
@@ -232,10 +232,11 @@
 /**
  * Bind the socket to its associated port
  * @param sock The socket to bind 
- * @tip This is where we will find out if there is any other process
+ * @param sa The socket address to bind to
+ * @tip This may be where we will find out if there is any other process
  *      using the selected port.
  */
-apr_status_t apr_bind(apr_socket_t *sock);
+apr_status_t apr_bind(apr_socket_t *sock, apr_sockaddr_t *sa);
 
 /**
  * Listen to a bound socket for connections.
@@ -440,6 +441,14 @@
  * @param on Socket option returned on the call.
  */
 apr_status_t apr_getsocketopt(apr_socket_t *sock, apr_int32_t opt, 
apr_int32_t* on);
+
+/**
+ * Return an apr_sockaddr_t from an apr_socket_t
+ * @param sa The returned apr_sockaddr_t.
+ * @param which Which interface do we wnat the apr_sockaddr_t for?
+ * @param sock The socket to use
+ */
+apr_status_t apr_get_sockaddr(apr_sockaddr_t **sa, apr_interface_e which, 
apr_socket_t *sock);
 
 /**
  * Associate a port with a socket.
Index: lib/apr/network_io/os2/sockets.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/lib/apr/network_io/os2/sockets.c,v
retrieving revision 1.32
diff -u -r1.32 sockets.c
--- lib/apr/network_io/os2/sockets.c    2000/11/17 03:45:03     1.32
+++ lib/apr/network_io/os2/sockets.c    2000/11/17 18:59:27
@@ -189,14 +189,16 @@
 
 
 
-apr_status_t apr_bind(apr_socket_t *sock)
+apr_status_t apr_bind(apr_socket_t *sock, apr_sockaddr_t *sa)
 {
     if (bind(sock->socketdes, 
-             (struct sockaddr *)&sock->local_addr->sa,
-             sock->local_addr->sa_len) == -1)
+             (struct sockaddr *)&sa->sa,
+             sa->sa_len) == -1)
         return APR_OS2_STATUS(sock_errno());
-    else
+    else {
+        sock->local_sa = sa;
         return APR_SUCCESS;
+    }
 }
 
 apr_status_t apr_listen(apr_socket_t *sock, apr_int32_t backlog)
Index: lib/apr/network_io/unix/sa_common.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/lib/apr/network_io/unix/sa_common.c,v
retrieving revision 1.7
diff -u -r1.7 sa_common.c
--- lib/apr/network_io/unix/sa_common.c 2000/11/17 03:45:01     1.7
+++ lib/apr/network_io/unix/sa_common.c 2000/11/17 18:59:27
@@ -191,6 +191,22 @@
 #endif
 }
 
+apr_status_t apr_get_sockaddr(apr_sockaddr_t **sa, apr_interface_e which, 
apr_socket_t *sock)
+{
+    if (which == APR_LOCAL) {
+        *sa = sock->local_addr;
+    }
+    else if (which == APR_REMOTE) {
+        *sa = sock->remote_addr;
+    }
+    else {
+        *sa = NULL;
+        return APR_EINVAL;
+    }
+    return APR_SUCCESS;
+
+}
+
 apr_status_t apr_getaddrinfo(apr_sockaddr_t **sa, const char *hostname, 
                              apr_int32_t family, apr_port_t port,
                              apr_int32_t flags, apr_pool_t *p)
@@ -201,7 +217,12 @@
     if ((*sa) == NULL)
         return APR_ENOMEM;
     (*sa)->pool = p;
-    (*sa)->sa.sin.sin_family = AF_INET; /* we don't yet support IPv6 */
+    if (family == AF_UNSPEC) {
+        (*sa)->sa.sin.sin_family = AF_INET; /* we don't yet support IPv6 here 
*/
+    }
+    else {
+        (*sa)->sa.sin.sin_family = family;
+    }
     (*sa)->sa.sin.sin_port = htons(port);
     set_sockaddr_vars(*sa, (*sa)->sa.sin.sin_family);
 
Index: lib/apr/network_io/unix/sockets.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/lib/apr/network_io/unix/sockets.c,v
retrieving revision 1.57
diff -u -r1.57 sockets.c
--- lib/apr/network_io/unix/sockets.c   2000/11/17 03:45:01     1.57
+++ lib/apr/network_io/unix/sockets.c   2000/11/17 18:59:28
@@ -162,12 +162,14 @@
     return socket_cleanup(thesocket);
 }
 
-apr_status_t apr_bind(apr_socket_t *sock)
+apr_status_t apr_bind(apr_socket_t *sock, apr_sockaddr_t *sa)
 {
     if (bind(sock->socketdes, 
-             (struct sockaddr *)&sock->local_addr->sa, 
sock->local_addr->sa_len) == -1)
+             (struct sockaddr *)&sa->sa, sa->sa_len) == -1) {
         return 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 */
Index: lib/apr/network_io/win32/sockets.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/lib/apr/network_io/win32/sockets.c,v
retrieving revision 1.42
diff -u -r1.42 sockets.c
--- lib/apr/network_io/win32/sockets.c  2000/11/17 03:45:03     1.42
+++ lib/apr/network_io/win32/sockets.c  2000/11/17 18:59:28
@@ -196,14 +196,15 @@
     return socket_cleanup(thesocket);
 }
 
-apr_status_t apr_bind(apr_socket_t *sock)
+apr_status_t apr_bind(apr_socket_t *sock, apr_sockaddr_t *sa)
 {
     if (bind(sock->sock, 
-             (struct sockaddr *)&sock->local_addr->sa, 
-             sock->local_addr->sa_len) == -1) {
+             (struct sockaddr *)&sa->sa, 
+             sa->sa_len) == -1) {
         return apr_get_netos_error();
     }
     else {
+        sock->local_addr = sa;
         if (sock->local_addr->sa.sin.sin_port == 0) {
             sock->local_port_unknown = 1; /* ephemeral port */
         }
Index: lib/apr/test/server.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/lib/apr/test/server.c,v
retrieving revision 1.18
diff -u -r1.18 server.c
--- lib/apr/test/server.c       2000/11/16 14:48:50     1.18
+++ lib/apr/test/server.c       2000/11/17 18:59:28
@@ -71,6 +71,10 @@
     char datarecv[STRLEN] = "Recv data test";
     char *local_ipaddr, *remote_ipaddr;
     apr_port_t local_port, remote_port;
+    apr_sockaddr_t *localsa;
+    apr_status_t stat;
+    int family;
+    char buf[128];
 
     fprintf(stdout, "Initializing.........");
     if (apr_initialize() != APR_SUCCESS) {
@@ -94,6 +98,18 @@
     }
     fprintf(stdout, "OK\n");
 
+    fprintf(stdout, "\tServer:  Grabbing local socket address........");
+    if (apr_get_sockaddr(&localsa, APR_LOCAL, sock) != APR_SUCCESS) {
+        fprintf(stderr, "Couldn't grab local address\n");
+        exit(-1);
+    }
+    fprintf(stdout, "OK\n");
+
+    /* APR chose the address family of socket for us, so we need to build a 
+     * socket address later for the same address family.
+     */
+    family = localsa->sa.sin.sin_family;
+
     fprintf(stdout, "\tServer:  Setting socket option NONBLOCK.......");
     if (apr_setsocketopt(sock, APR_SO_NONBLOCK, 1) != APR_SUCCESS) {
         apr_close_socket(sock);
@@ -110,18 +126,20 @@
     }
     fprintf(stdout, "OK\n");
 
-    fprintf(stdout, "\tServer:  Setting port for socket.......");
-    if (apr_set_port(sock, APR_LOCAL, 8021) != APR_SUCCESS) {
+    fprintf(stdout, "\tServer:  Building local socket address.........");
+    if (apr_getaddrinfo(&localsa, NULL, family, 8021, 0, context)
+        != APR_SUCCESS) {
         apr_close_socket(sock);
-        fprintf(stderr, "Couldn't set the port correctly\n");
+        fprintf(stderr, "Couldn't build the socket address correctly\n");
         exit(-1);
     }
     fprintf(stdout, "OK\n");
 
     fprintf(stdout, "\tServer:  Binding socket to port.......");
-    if (apr_bind(sock) != APR_SUCCESS) {
+    if ((stat = apr_bind(sock, localsa)) != APR_SUCCESS) {
         apr_close_socket(sock);
-        fprintf(stderr, "Could not bind\n");
+        fprintf(stderr, "Could not bind: %s\n",
+                apr_strerror(stat, buf, sizeof buf));
         exit(-1);
     }
     fprintf(stdout, "OK\n");
Index: lib/apr/test/testsf.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/lib/apr/test/testsf.c,v
retrieving revision 1.14
diff -u -r1.14 testsf.c
--- lib/apr/test/testsf.c       2000/11/17 03:45:01     1.14
+++ lib/apr/test/testsf.c       2000/11/17 18:59:29
@@ -90,7 +90,7 @@
 
 typedef enum {BLK, NONBLK, TIMEOUT} client_socket_mode_t;
 
-static void apr_setup(apr_pool_t **p, apr_socket_t **sock)
+static void apr_setup(apr_pool_t **p, apr_socket_t **sock, int *family)
 {
     char buf[120];
     apr_status_t rv;
@@ -114,13 +114,26 @@
     }
 
     *sock = NULL;
-    rv = apr_create_tcp_socket(sock, *p);
+    rv = apr_create_socket(sock, *family, SOCK_STREAM, *p);
     if (rv != APR_SUCCESS) {
         fprintf(stderr, "apr_create_tcp_socket()->%d/%s\n",
                 rv,
                 apr_strerror(rv, buf, sizeof buf));
         exit(1);
     }
+
+    if (*family == AF_UNSPEC) {
+        apr_sockaddr_t *localsa;
+
+        rv = apr_get_sockaddr(&localsa, APR_LOCAL, *sock);
+        if (rv != APR_SUCCESS) {
+            fprintf(stderr, "apr_get_sockaddr()->%d/%s\n",
+                    rv,
+                    apr_strerror(rv, buf, sizeof buf));
+            exit(1);
+        }
+        *family = localsa->sa.sin.sin_family;
+    }
 }
 
 static void create_testfile(apr_pool_t *p, const char *fname)
@@ -205,9 +218,11 @@
     apr_pollfd_t *pfd;
     apr_int32_t nsocks;
     int i;
+    int family;
     apr_sockaddr_t *destsa;
 
-    apr_setup(&p, &sock);
+    family = AF_INET;
+    apr_setup(&p, &sock, &family);
     create_testfile(p, TESTFILE);
 
     rv = apr_open(&f, TESTFILE, APR_READ, 0, p);
@@ -218,7 +233,7 @@
         exit(1);
     }
 
-    rv = apr_getaddrinfo(&destsa, "127.0.0.1", AF_INET, TESTSF_PORT, 0, p);
+    rv = apr_getaddrinfo(&destsa, "127.0.0.1", family, TESTSF_PORT, 0, p);
     if (rv != APR_SUCCESS) {
         fprintf(stderr, "apr_getaddrinfo()->%d/%s\n",
                 rv,
@@ -493,26 +508,29 @@
     int i;
     apr_socket_t *newsock = NULL;
     apr_ssize_t bytes_read;
+    apr_sockaddr_t *localsa;
+    int family;
 
-    apr_setup(&p, &sock);
+    family = AF_UNSPEC;
+    apr_setup(&p, &sock, &family);
 
-    rv = apr_set_port(sock, APR_LOCAL, TESTSF_PORT);
+    rv = apr_setsocketopt(sock, APR_SO_REUSEADDR, 1);
     if (rv != APR_SUCCESS) {
-        fprintf(stderr, "apr_set_local_port()->%d/%s\n",
+        fprintf(stderr, "apr_setsocketopt()->%d/%s\n",
                 rv,
                apr_strerror(rv, buf, sizeof buf));
         exit(1);
     }
 
-    rv = apr_setsocketopt(sock, APR_SO_REUSEADDR, 1);
+    rv = apr_getaddrinfo(&localsa, NULL, family, TESTSF_PORT, 0, p);
     if (rv != APR_SUCCESS) {
-        fprintf(stderr, "apr_setsocketopt()->%d/%s\n",
+        fprintf(stderr, "apr_getaddrinfo()->%d/%s\n",
                 rv,
                apr_strerror(rv, buf, sizeof buf));
         exit(1);
     }
 
-    rv = apr_bind(sock);
+    rv = apr_bind(sock, localsa);
     if (rv != APR_SUCCESS) {
         fprintf(stderr, "apr_bind()->%d/%s\n",
                 rv,
Index: main/listen.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/main/listen.c,v
retrieving revision 1.36
diff -u -r1.36 listen.c
--- main/listen.c       2000/11/09 19:38:26     1.36
+++ main/listen.c       2000/11/17 18:59:29
@@ -85,12 +85,22 @@
     apr_status_t stat;
     apr_port_t port;
     char *ipaddr;
+    apr_sockaddr_t *localsa;
 
     apr_get_port(&port, APR_LOCAL, s);
     apr_get_ipaddr(&ipaddr, APR_LOCAL, s);
     apr_snprintf(addr, sizeof(addr), "address %s port %u", ipaddr,
                (unsigned) port);
 
+    stat = apr_getaddrinfo(&localsa, ipaddr, AF_INET, port, 0, p);
+    if (stat != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
+                     "make_sock: for %s/%hu, apr_getaddrinfo() failed", 
+                     ipaddr, port);
+        apr_close_socket(s);
+        return stat;
+    }
+
     stat = apr_setsocketopt(s, APR_SO_REUSEADDR, one);
     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
@@ -140,7 +150,7 @@
     ap_sock_disable_nagle(s);
 #endif
 
-    if ((stat = apr_bind(s)) != APR_SUCCESS) {
+    if ((stat = apr_bind(s, localsa)) != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
            "make_sock: could not bind to %s", addr);
        apr_close_socket(s);
Index: main/rfc1413.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/main/rfc1413.c,v
retrieving revision 1.29
diff -u -r1.29 rfc1413.c
--- main/rfc1413.c      2000/11/17 03:45:02     1.29
+++ main/rfc1413.c      2000/11/17 18:59:30
@@ -119,7 +119,7 @@
     char *cp;
     char buffer[RFC1413_MAXDATA + 1];
     int buflen;
-    apr_sockaddr_t *destsa;
+    apr_sockaddr_t *localsa, *destsa;
 
     /*
      * Bind the local and remote ends of the query socket to the same
@@ -130,10 +130,16 @@
      * addresses from the query socket.
      */
 
-    apr_set_port(sock, APR_LOCAL, ANY_PORT);
-    apr_set_ipaddr(sock, APR_LOCAL, local_ip);
+    if ((status = apr_getaddrinfo(&localsa, local_ip, AF_INET, 0, 0, p)) 
+        != APR_SUCCESS) {
+        /* This should not fail since we have a numeric address string
+         * as the host. */
+        ap_log_error(APLOG_MARK, APLOG_CRIT, status, srv,
+                     "rfc1413: apr_getaddrinfo() failed");
+        return -1;
+    }
 
-    if ((status = apr_bind(sock)) != APR_SUCCESS) {
+    if ((status = apr_bind(sock, localsa)) != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, status, srv,
                    "bind: rfc1413: Error binding to local port");
        return -1;
Index: modules/proxy/proxy_ftp.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/modules/proxy/proxy_ftp.c,v
retrieving revision 1.23
diff -u -r1.23 proxy_ftp.c
--- modules/proxy/proxy_ftp.c   2000/11/16 01:57:46     1.23
+++ modules/proxy/proxy_ftp.c   2000/11/17 18:59:31
@@ -873,8 +873,6 @@
        }
         apr_get_port(&npport, APR_LOCAL, sock);
         apr_get_ipaddr(&npaddr, APR_LOCAL, sock);
-        apr_set_port(dsock, APR_LOCAL, npport);
-        apr_set_ipaddr(dsock, APR_LOCAL, npaddr);
 
        if (apr_setsocketopt(dsock, APR_SO_REUSEADDR, one) != APR_SUCCESS) {
 #ifndef _OSD_POSIX /* BS2000 has this option "always on" */
@@ -886,7 +884,15 @@
 #endif /*_OSD_POSIX*/
        }
 
-       if (apr_bind(dsock) != APR_SUCCESS) {
+        if (apr_getaddrinfo(&localsa, npaddr, AF_INET, npport, 0, r->pool) 
+            != APR_SUCCESS) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                          "proxy: error creating local socket address");
+            ap_bclose(f);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+       if (apr_bind(dsock, localsa) != APR_SUCCESS) {
            char buff[22];
 
            apr_snprintf(buff, sizeof(buff), "%s:%d", npaddr, npport);
Index: support/httpd.exp
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/support/httpd.exp,v
retrieving revision 1.12
diff -u -r1.12 httpd.exp
--- support/httpd.exp   2000/11/17 03:45:02     1.12
+++ support/httpd.exp   2000/11/17 18:59:33
@@ -425,6 +425,7 @@
 apr_get_port
 apr_get_remote_name
 apr_get_revents
+apr_get_sockaddr
 apr_get_socket_inaddr
 apr_get_socketdata
 apr_get_thread_private


-- 
Jeff Trawick | [EMAIL PROTECTED] | PGP public key at web site:
     http://www.geocities.com/SiliconValley/Park/9289/
          Born in Roswell... married an alien...

Reply via email to