]> granicus.if.org Git - apache/blobdiff - server/listen.c
Enhancements for APR network_io. Adds separate local/remote access methods for
[apache] / server / listen.c
index 9f7c121b7345a51a3a09d8b1cbeb9f7bad783081..b9c5950499496cbeb23a1c0b88d031e1f7093852 100644 (file)
@@ -55,6 +55,7 @@
  *
  */
 
+#include "apr_network_io.h"
 #include "httpd.h"
 #include "http_config.h"
 #include "ap_listen.h"
@@ -66,41 +67,30 @@ static int ap_listenbacklog;
 static int send_buffer_size;
 
 /* TODO: make_sock is just begging and screaming for APR abstraction */
-static int make_sock(const struct sockaddr_in *server)
+static ap_status_t make_sock(ap_context_t *p, ap_listen_rec *server)
 {
-    int s;
+    ap_socket_t *s = server->sd;
     int one = 1;
     char addr[512];
+    ap_status_t stat;
 
-    if (server->sin_addr.s_addr != htonl(INADDR_ANY))
-       ap_snprintf(addr, sizeof(addr), "address %s port %d",
-               inet_ntoa(server->sin_addr), ntohs(server->sin_port));
-    else
-       ap_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
+    ap_cpystrn(addr, "[@main/listen.c:make_sock(): inet_ntoa(server->sin_addr)]", sizeof addr);
 
-    if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
-       ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
-                   "make_sock: failed to get a socket for %s", addr);
-       return -1;
-    }
-
-#ifdef SO_REUSEADDR
-    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) {
-       ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+    stat = ap_setsocketopt(s, APR_SO_REUSEADDR, one);
+    if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
+       ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
                    "make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
-       close(s);
-       return -1;
+       ap_close_socket(s);
+       return stat;
     }
-#endif
-    one = 1;
-#ifdef SO_KEEPALIVE
-    if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(int)) < 0) {
-       ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+    
+    stat = ap_setsocketopt(s, APR_SO_KEEPALIVE, one);
+    if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
+       ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
                    "make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
-       close(s);
-       return -1;
+       ap_close_socket(s);
+       return stat;
     }
-#endif
 
     /*
      * To send data over high bandwidth-delay connections at full
@@ -121,54 +111,61 @@ static int make_sock(const struct sockaddr_in *server)
      *
      * If no size is specified, use the kernel default.
      */
-#ifndef SO_SNDBUF
     if (send_buffer_size) {
-       if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
-               (char *) &send_buffer_size, sizeof(int)) < 0) {
-           ap_log_error(APLOG_MARK, APLOG_WARNING, NULL,
+       stat = ap_setsocketopt(s, APR_SO_SNDBUF,  send_buffer_size);
+        if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, stat, NULL,
                        "make_sock: failed to set SendBufferSize for %s, "
                        "using default", addr);
            /* not a fatal error */
        }
     }
-#endif
 
-    if (bind(s, (struct sockaddr *) server, sizeof(struct sockaddr_in)) == -1) {
-       ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+    if ((stat = ap_bind(s)) != APR_SUCCESS) {
+       ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
            "make_sock: could not bind to %s", addr);
-       close(s);
-       return -1;
+       ap_close_socket(s);
+       return stat;
     }
 
-    if (listen(s, ap_listenbacklog) == -1) {
-       ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
+    if ((stat = ap_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
+       ap_log_error(APLOG_MARK, APLOG_ERR, stat, NULL,
            "make_sock: unable to listen for connections on %s", addr);
-       close(s);
-       return -1;
+       ap_close_socket(s);
+       return stat;
     }
 
-    return s;
+    server->sd = s;
+    server->active = 1;
+    return APR_SUCCESS;
 }
 
 
-static void close_listeners_on_exec(void *v)
+static ap_status_t close_listeners_on_exec(void *v)
 {
     ap_listen_rec *lr;
 
     for (lr = ap_listeners; lr; lr = lr->next) {
-       close(lr->fd);
+       ap_close_socket(lr->sd);
+       lr->active = 0;
     }
+    return APR_SUCCESS;
 }
 
 
-static void alloc_listener(struct sockaddr_in *local_addr)
+static void alloc_listener(process_rec *process, char *addr, unsigned int port)
 {
     ap_listen_rec **walk;
     ap_listen_rec *new;
+    ap_status_t status;
+    char *oldaddr;
+    unsigned int oldport;
 
     /* see if we've got an old listener for this address:port */
     for (walk = &old_listeners; *walk; walk = &(*walk)->next) {
-       if (!memcmp(&(*walk)->local_addr, local_addr, sizeof(local_addr))) {
+        ap_get_local_port(&oldport, (*walk)->sd);
+       ap_get_local_ipaddr(&oldaddr,(*walk)->sd);
+       if (!strcmp(oldaddr, addr) && port == oldport) {
            /* re-use existing record */
            new = *walk;
            *walk = new->next;
@@ -179,44 +176,52 @@ static void alloc_listener(struct sockaddr_in *local_addr)
     }
 
     /* this has to survive restarts */
-    new = malloc(sizeof(ap_listen_rec));
-    new->local_addr = *local_addr;
-    new->fd = -1;
+    /* XXX - We need to deal with freeing this structure properly. */
+    new = ap_palloc(process->pool, sizeof(ap_listen_rec));
+    new->active = 0;
+    if ((status = ap_create_tcp_socket(&new->sd, NULL)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, status, NULL,
+                 "make_sock: failed to get a socket for %s", addr);
+        return;
+    }
+    ap_set_local_port(new->sd, port);
+    ap_set_local_ipaddr(new->sd, addr);
     new->next = ap_listeners;
     ap_listeners = new;
 }
 
 
-int ap_listen_open(pool *pconf, unsigned port)
+int ap_listen_open(process_rec *process, unsigned port)
 {
+    ap_context_t *pconf = process->pconf;
     ap_listen_rec *lr;
     ap_listen_rec *next;
     int num_open;
-    struct sockaddr_in local_addr;
 
     /* allocate a default listener if necessary */
     if (ap_listeners == NULL) {
-       local_addr.sin_family = AF_INET;
-       local_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* XXX */
-       local_addr.sin_port = htons(port ? port : DEFAULT_HTTP_PORT);
-       alloc_listener(&local_addr);
+       alloc_listener(process, APR_ANYADDR, port ? port : DEFAULT_HTTP_PORT);
     }
 
     num_open = 0;
     for (lr = ap_listeners; lr; lr = lr->next) {
-       if (lr->fd < 0) {
-           lr->fd = make_sock(&lr->local_addr);
-       }
-       if (lr->fd >= 0) {
+       if (lr->active) {
            ++num_open;
        }
+       else {
+           if (make_sock(pconf, lr) == APR_SUCCESS) {
+               ++num_open;
+               lr->active = 1;
+           }
+       }
     }
 
     /* close the old listeners */
     for (lr = old_listeners; lr; lr = next) {
-       close(lr->fd);
+       ap_close_socket(lr->sd);
+       lr->active = 0;
        next = lr->next;
-       free(lr);
+/*     free(lr);*/
     }
     old_listeners = NULL;
 
@@ -238,7 +243,6 @@ const char *ap_set_listener(cmd_parms *cmd, void *dummy, char *ips)
 {
     char *ports;
     unsigned short port;
-    struct sockaddr_in local_addr;
 
     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
     if (err != NULL) {
@@ -259,20 +263,18 @@ const char *ap_set_listener(cmd_parms *cmd, void *dummy, char *ips)
        ports = ips;
     }
 
-    local_addr.sin_family = AF_INET;
-    if (ports == ips) { /* no address */
-       local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    }
-    else {
-       local_addr.sin_addr.s_addr = ap_get_virthost_addr(ips, NULL);
-    }
     port = atoi(ports);
     if (!port) {
        return "Port must be numeric";
     }
-    local_addr.sin_port = htons(port);
 
-    alloc_listener(&local_addr);
+    if (ports == ips) { /* no address */
+        alloc_listener(cmd->server->process, APR_ANYADDR, port);
+    }
+    else {
+        ips[(ports - ips) - 1] = '\0';
+       alloc_listener(cmd->server->process, ips, port);
+    }
 
     return NULL;
 }