[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: UDP support in mod_perl2/apache


Nice.  A cursory look appears to match what I have.

I also dug up another nugget - a complete patch against httpd-2.2.6 for
the UDP support (excluding only the APR recvfrom issue) - I thought I
had it lying around somewhere.  I included two; one with and one without
the APR backport.  Rolf, try to use this (use the one with the
apr-backport) instead of downloading and patching trunk.

  Issac

William A. Rowe, Jr. wrote:
> Issac Goldstand wrote:
>>
>> The same patchset can be used for 2.2.x branch pretty much as is with
>> the single addition of backporting the apr_socket_sendto function from
>> trunk (it's broken in the APR that ships with 2.2.x)
> 
> We agree that's true - have you looked at apr 1.2.x branch lately?  A week
> or so ago I backported the fixes to properly fix up apr_socket_recvfrom,
> and am wondering if there are additional bug fixes required to this code?
> Or is this the addition of a feature (which 1.2.x will not offer)?
> 
> Bill
Only in httpd-2.2.6: config.nice
Only in httpd-2.2.6-orig: .deps
Only in httpd-2.2.6: httpd-udp-disconnected.patch
diff -r -U3 httpd-2.2.6-orig/include/ap_listen.h httpd-2.2.6/include/ap_listen.h
--- httpd-2.2.6-orig/include/ap_listen.h	2007-05-09 22:35:45.000000000 +0300
+++ httpd-2.2.6/include/ap_listen.h	2007-09-23 12:24:00.000000000 +0200
@@ -81,6 +81,26 @@
 AP_DECLARE(void) ap_listen_pre_config(void);
 
 /**
+ * Allocate a new listener to be created during ap_setup_listeners.
+ * @param process The process_rec of the parent process
+ * @param addr The IP address to bind the socket to (uses same format as
+ * the Listen directive in httpd.conf)
+ * @param port The port to bind the socket to
+ * @param type The socket type (SOCK_STREAM, etc)
+ * @param protocol The socket protocol (APR_PROTO_TCP, etc)
+ * @param proto The optional protocol argument is not required for most
+ * configurations. If not specified, https is the default for port 443
+ * and http the default for all other ports. The protocol is used to
+ * determine which module should handle a request, and to apply
+ * protocol specific optimizations with the AcceptFilter directive.
+ * @return NULL on success, or an error message on failure
+ */
+
+AP_DECLARE(const char *) ap_alloc_listener(process_rec *process, char *addr,
+                                  apr_port_t port, int type, int protocol,
+                                  const char* proto);
+
+/**
  * Loop through the global ap_listen_rec list and create all of the required
  * sockets.  This executes the listen and bind on the sockets.
  * @param s The global server_rec
@@ -103,6 +123,9 @@
 AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg);
 AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, 
                                                 int argc, char *const argv[]);
+AP_DECLARE_NONSTD(const char *) ap_set_udp_listener(cmd_parms *cmd,
+                                                    void *dummy, int argc,
+                                                    char *const argv[]);
 AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
 				    const char *arg);
 AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd,
@@ -114,6 +137,10 @@
   "Maximum length of the queue of pending connections, as used by listen(2)"), \
 AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \
   "A port number or a numeric IP address and a port number, and an optional protocol"), \
+AP_INIT_TAKE_ARGV("ListenTCP", ap_set_listener, NULL, RSRC_CONF, \
+  "A port number or a numeric IP address and a port number, and an optional protocol"), \
+AP_INIT_TAKE_ARGV("ListenUDP", ap_set_udp_listener, NULL, RSRC_CONF, \
+  "A port number or a numeric IP address and a port number, and an optional protocol"), \
 AP_INIT_TAKE1("SendBufferSize", ap_set_send_buffer_size, NULL, RSRC_CONF, \
   "Send buffer size in bytes"), \
 AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \
diff -r -U3 httpd-2.2.6-orig/include/httpd.h httpd-2.2.6/include/httpd.h
--- httpd-2.2.6-orig/include/httpd.h	2006-10-13 00:55:03.000000000 +0200
+++ httpd-2.2.6/include/httpd.h	2007-09-23 12:29:57.000000000 +0200
@@ -1225,7 +1225,8 @@
     /** subpool of c->pool used for resources 
      * which may outlive the request
      */
-    apr_pool_t *deferred_write_pool;
+    apr_pool_t *deferred_write_pool;
+    int connected;
 } core_output_filter_ctx_t;
  
 typedef struct core_filter_ctx {
diff -r -U3 httpd-2.2.6-orig/server/core.c httpd-2.2.6/server/core.c
--- httpd-2.2.6-orig/server/core.c	2007-08-07 15:12:20.000000000 +0300
+++ httpd-2.2.6/server/core.c	2007-09-23 12:24:00.000000000 +0200
@@ -3872,6 +3872,7 @@
                                   apr_bucket_alloc_t *alloc)
 {
     apr_status_t rv;
+    int sd_type;
     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
 
     c->sbh = sbh;
@@ -3891,16 +3892,38 @@
         apr_socket_close(csd);
         return NULL;
     }
-
     apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
-    if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
-        != APR_SUCCESS) {
+    
+    apr_socket_type_get(csd, &sd_type);
+    if (sd_type == SOCK_STREAM &&
+        (rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
+        != APR_SUCCESS)
+    {
         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
                      "apr_socket_addr_get(APR_REMOTE)");
         apr_socket_close(csd);
         return NULL;
     }
-
+    if (sd_type != SOCK_STREAM) {
+        if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
+        != APR_SUCCESS)
+        {
+            char tmpbuf = 0;
+            apr_size_t tmpbuflen = 1;
+            /** Allocate a apr_sockaddr_t, since we can't use the one in csd */
+            c->remote_addr = apr_pcalloc(c->pool, sizeof(apr_sockaddr_t));
+            c->remote_addr->pool = c->pool;
+            if ((rv = apr_socket_recvfrom(c->remote_addr, csd, MSG_PEEK, 
+                                          &tmpbuf, &tmpbuflen))
+                != APR_SUCCESS)
+            {
+                ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
+                             "Error reading UDP peer");
+                /* Don't close non-connected UDP sockets */
+                return NULL;
+            }
+        }
+    }
     apr_sockaddr_ip_get(&c->remote_ip, c->remote_addr);
     c->base_server = server;
 
@@ -3913,6 +3936,7 @@
 static int core_pre_connection(conn_rec *c, void *csd)
 {
     core_net_rec *net = apr_palloc(c->pool, sizeof(*net));
+    int sd_type;
     apr_status_t rv;
 
 #ifdef AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
@@ -3923,13 +3947,17 @@
      * performance penalties.  (Failing to disable Nagle is not much of a
      * problem with simple HTTP.)
      */
-    rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
-    if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
-        /* expected cause is that the client disconnected already,
-         * hence the debug level
-         */
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
-                      "apr_socket_opt_set(APR_TCP_NODELAY)");
+
+    apr_socket_type_get(csd, &sd_type);
+    if (sd_type == SOCK_STREAM) {
+        rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
+        if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
+            /* expected cause is that the client disconnected already,
+             * hence the debug level
+             */
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
+                          "apr_socket_opt_set(APR_TCP_NODELAY)");
+        }
     }
 #endif
 
Only in httpd-2.2.6/server: core.c.orig
diff -r -U3 httpd-2.2.6-orig/server/core_filters.c httpd-2.2.6/server/core_filters.c
--- httpd-2.2.6-orig/server/core_filters.c	2006-07-12 06:38:44.000000000 +0300
+++ httpd-2.2.6/server/core_filters.c	2007-09-23 12:50:52.000000000 +0200
@@ -305,7 +305,9 @@
     return APR_SUCCESS;
 }
 
-static apr_status_t writev_it_all(apr_socket_t *s,
+static apr_status_t writev_it_all(apr_socket_t *s,
+                                  core_net_rec *c, 
+                                  int connected, 
                                   struct iovec *vec, int nvec,
                                   apr_size_t len, apr_size_t *nbytes)
 {
@@ -317,8 +319,12 @@
     *nbytes = 0;
 
     /* XXX handle checking for non-blocking socket */
-    while (bytes_written != len) {
-        rv = apr_socket_sendv(s, vec + i, nvec - i, &n);
+    while (bytes_written != len) {
+        if (connected) {
+            rv = apr_socket_sendv(s, vec + i, nvec - i, &n);
+        } else {
+            rv = apr_socket_sendtov(s, c->c->remote_addr, 0, vec + i, nvec - i, &n);
+        }
         *nbytes += n;
         bytes_written += n;
         if (rv != APR_SUCCESS)
@@ -448,7 +454,7 @@
  * to the network. emulate_sendfile will return only when all the bytes have been
  * sent (i.e., it handles partial writes) or on a network error condition.
  */
-static apr_status_t emulate_sendfile(core_net_rec *c, apr_file_t *fd,
+static apr_status_t emulate_sendfile(core_net_rec *c, int connected, apr_file_t *fd,
                                      apr_hdtr_t *hdtr, apr_off_t offset,
                                      apr_size_t length, apr_size_t *nbytes)
 {
@@ -472,7 +478,7 @@
             sendlen += hdtr->headers[i].iov_len;
         }
 
-        rv = writev_it_all(c->client_socket, hdtr->headers, hdtr->numheaders,
+        rv = writev_it_all(c->client_socket, c, connected, hdtr->headers, hdtr->numheaders,
                            sendlen, &bytes_sent);
         *nbytes += bytes_sent;     /* track total bytes sent */
     }
@@ -489,8 +495,12 @@
         o = 0;
         rv = apr_file_read(fd, buffer, &sendlen);
         while (rv == APR_SUCCESS && sendlen) {
-            bytes_sent = sendlen;
-            rv = apr_socket_send(c->client_socket, &buffer[o], &bytes_sent);
+            bytes_sent = sendlen;
+            if (connected) {
+                rv = apr_socket_send(c->client_socket, &buffer[o], &bytes_sent);
+            } else {
+                rv = apr_socket_sendto(c->client_socket, c->c->remote_addr, 0, &buffer[o], &bytes_sent);
+            }
             *nbytes += bytes_sent;
             if (rv == APR_SUCCESS) {
                 sendlen -= bytes_sent; /* sendlen != bytes_sent ==> partial write */
@@ -509,7 +519,7 @@
         for (i = 0; i < hdtr->numtrailers; i++) {
             sendlen += hdtr->trailers[i].iov_len;
         }
-        rv = writev_it_all(c->client_socket, hdtr->trailers, hdtr->numtrailers,
+        rv = writev_it_all(c->client_socket, c, connected, hdtr->trailers, hdtr->numtrailers,
                            sendlen, &bytes_sent);
         *nbytes += bytes_sent;
     }
@@ -542,9 +552,21 @@
     apr_read_type_e eblock = APR_NONBLOCK_READ;
     apr_pool_t *input_pool = b->p;
 
-    if (ctx == NULL) {
+    if (ctx == NULL) {
+        int sd_type;
         ctx = apr_pcalloc(c->pool, sizeof(*ctx));
-        net->out_ctx = ctx;
+        net->out_ctx = ctx;
+        ctx->connected = 1;
+        /* Check for non-connected socket */
+        apr_socket_type_get(net->client_socket, &sd_type);
+        if (sd_type != SOCK_STREAM) {
+            apr_sockaddr_t *peer;
+            if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE,
+                                          net->client_socket)) != APR_SUCCESS)
+                /* Disconnected socket */
+                ctx->connected = 0;
+        }
+
     }
 
     /* If we have a saved brigade, concatenate the new brigade to it */
@@ -831,7 +853,7 @@
             }
 
 #if APR_HAS_SENDFILE
-            if (apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) {
+            if ((apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) && ctx->connected) {
 
                 if (c->keepalive == AP_CONN_CLOSE && APR_BUCKET_IS_EOS(last_e)) {
                     /* Prepare the socket to be reused */
@@ -853,7 +875,7 @@
             else
 #endif
             {
-                rv = emulate_sendfile(net, fd, &hdtr, foffset, flen,
+                rv = emulate_sendfile(net, ctx->connected, fd, &hdtr, foffset, flen,
                                       &bytes_sent);
             }
 
@@ -865,7 +887,7 @@
         else {
             apr_size_t bytes_sent;
 
-            rv = writev_it_all(net->client_socket,
+            rv = writev_it_all(net->client_socket, net, ctx->connected,
                                vec, nvec,
                                nbytes, &bytes_sent);
 
Only in httpd-2.2.6/server: core_filters.c.orig
diff -r -U3 httpd-2.2.6-orig/server/listen.c httpd-2.2.6/server/listen.c
--- httpd-2.2.6-orig/server/listen.c	2006-12-20 04:04:39.000000000 +0200
+++ httpd-2.2.6/server/listen.c	2007-09-23 12:27:32.000000000 +0200
@@ -49,6 +49,7 @@
     int v6only_setting = 1;
 #endif
 #endif
+    int type;
     apr_status_t stat;
 
 #ifndef WIN32
@@ -136,8 +137,17 @@
         apr_socket_close(s);
         return stat;
     }
-
-    if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
+    
+    if ((stat = apr_socket_type_get(s, &type)) != APR_SUCCESS) {
+        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p,
+                      "make_sock: could not determine socket type for "
+                      "address %pI", server->bind_addr);
+        apr_socket_close(s);
+        return stat;
+    }
+    
+    if (type == SOCK_STREAM &&
+        ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS)) {
         ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p,
                       "make_sock: unable to listen for connections "
                       "on address %pI",
@@ -204,7 +214,8 @@
     const char *accf;
     apr_status_t rv;
     const char *proto;
-
+    int protocol;
+    
     proto = lis->protocol;
 
     if (!proto) {
@@ -224,11 +235,14 @@
                           accf);
         }
 #else
-#ifdef APR_TCP_DEFER_ACCEPT
-        rv = apr_socket_opt_set(s, APR_TCP_DEFER_ACCEPT, 1);
-        if (rv != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(rv)) {
-            ap_log_perror(APLOG_MARK, APLOG_WARNING, rv, p,
-                              "Failed to enable APR_TCP_DEFER_ACCEPT");
+#ifdef APR_TCP_DEFER_ACCEPT
+        rv = apr_socket_protocol_get(s, &protocol);
+        if ((rv == APR_SUCCESS) && (protocol == APR_PROTO_TCP)) {
+            rv = apr_socket_opt_set(s, APR_TCP_DEFER_ACCEPT, 1);
+            if (rv != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(rv)) {
+                ap_log_perror(APLOG_MARK, APLOG_WARNING, rv, p,
+                                  "Failed to enable APR_TCP_DEFER_ACCEPT");
+            }
         }
 #endif
 #endif
@@ -241,12 +255,14 @@
     return APR_SUCCESS;
 }
 
-static const char *alloc_listener(process_rec *process, char *addr,
-                                  apr_port_t port, const char* proto)
+AP_DECLARE(const char *) ap_alloc_listener(process_rec *process, char *addr,
+                                  apr_port_t port, int type, int protocol,
+                                  const char* proto)
 {
     ap_listen_rec **walk, *last;
     apr_status_t status;
     apr_sockaddr_t *sa;
+    apr_socket_t *sd;
     int found_listener = 0;
 
     /* see if we've got an old listener for this address:port */
@@ -255,13 +271,20 @@
         /* Some listeners are not real so they will not have a bind_addr. */
         if (sa) {
             ap_listen_rec *new;
+            sd = (*walk)->sd;
             apr_port_t oldport;
+            int oldprotocol = -1;
+            int oldtype = -1;
 
             oldport = sa->port;
-            /* If both ports are equivalent, then if their names are equivalent,
+            apr_socket_type_get(sd, &oldtype);
+            apr_socket_protocol_get(sd, &oldprotocol);
+            /* If both ports are equivalent and both socket type/protocols are
+             * equivalent, then if their names are equivalent,
              * then we will re-use the existing record.
              */
-            if (port == oldport &&
+            if ((port == oldport &&
+                 (type == oldtype && protocol == oldprotocol)) &&
                 ((!addr && !sa->hostname) ||
                  ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
                 new = *walk;
@@ -284,7 +307,7 @@
                                         process->pool))
         != APR_SUCCESS) {
         ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
-                      "alloc_listener: failed to set up sockaddr for %s",
+                      "ap_alloc_listener: failed to set up sockaddr for %s",
                       addr);
         return "Listen setup failed";
     }
@@ -309,7 +332,7 @@
         sa = sa->next;
 
         status = apr_socket_create(&new->sd, new->bind_addr->family,
-                                    SOCK_STREAM, 0, process->pool);
+                                    type, protocol, process->pool);
 
 #if APR_HAVE_IPV6
         /* What could happen is that we got an IPv6 address, but this system
@@ -322,7 +345,7 @@
 #endif
         if (status != APR_SUCCESS) {
             ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
-                          "alloc_listener: failed to get a socket for %s",
+                          "ap_alloc_listener: failed to get a socket for %s",
                           addr);
             return "Listen setup failed";
         }
@@ -583,7 +606,6 @@
     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
 }
 
-
 AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
                                                 int argc, char *const argv[])
 {
@@ -626,7 +648,55 @@
         ap_str_tolower(proto);
     }
 
-    return alloc_listener(cmd->server->process, host, port, proto);
+    return ap_alloc_listener(cmd->server->process, host, port,
+                             SOCK_STREAM, 0, proto);
+}
+
+AP_DECLARE_NONSTD(const char *) ap_set_udp_listener(cmd_parms *cmd,
+                                                    void *dummy, int argc,
+                                                    char *const argv[])
+{
+    char *host, *scope_id, *proto;
+    apr_port_t port;
+    apr_status_t rv;
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+    if (err != NULL) {
+        return err;
+    }
+
+    if (argc < 1 || argc > 2) {
+        return "Listen requires 1 or 2 arguments.";
+    }
+
+    rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool);
+    if (rv != APR_SUCCESS) {
+        return "Invalid address or port";
+    }
+
+    if (host && !strcmp(host, "*")) {
+        host = NULL;
+    }
+
+    if (scope_id) {
+        /* XXX scope id support is useful with link-local IPv6 addresses */
+        return "Scope id is not supported";
+    }
+
+    if (!port) {
+        return "Port must be specified";
+    }
+
+    if (argc != 2) {
+        proto = "http";
+    }
+    else {
+        proto = apr_pstrdup(cmd->pool, argv[1]);
+        ap_str_tolower(proto);
+    }
+
+    return ap_alloc_listener(cmd->server->process, host, port,
+                             SOCK_DGRAM, APR_PROTO_UDP, proto);
 }
 
 AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd,
Only in httpd-2.2.6/server: listen.c.orig
diff -r -U3 httpd-2.2.6-orig/server/mpm/experimental/event/event.c httpd-2.2.6/server/mpm/experimental/event/event.c
--- httpd-2.2.6-orig/server/mpm/experimental/event/event.c	2007-07-17 17:48:25.000000000 +0300
+++ httpd-2.2.6/server/mpm/experimental/event/event.c	2007-09-23 12:24:00.000000000 +0200
@@ -970,7 +970,9 @@
 
                 apr_pool_tag(ptrans, "transaction");
 
-                rc = lr->accept_func(&csd, lr, ptrans);
+                rc = APR_SUCCESS;
+                if (lr->accept_func)
+                    rc = lr->accept_func(&csd, lr, ptrans);
 
                 /* later we trash rv and rely on csd to indicate
                  * success/failure
Only in httpd-2.2.6/server/mpm/experimental/event: event.c.orig
diff -r -U3 httpd-2.2.6-orig/server/mpm/prefork/prefork.c httpd-2.2.6/server/mpm/prefork/prefork.c
--- httpd-2.2.6-orig/server/mpm/prefork/prefork.c	2007-07-17 17:48:25.000000000 +0300
+++ httpd-2.2.6/server/mpm/prefork/prefork.c	2007-09-23 12:24:00.000000000 +0200
@@ -474,6 +474,7 @@
     ap_sb_handle_t *sbh;
     apr_bucket_alloc_t *bucket_alloc;
     int last_poll_idx = 0;
+    int sd_type;
 
     mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
                                    * child initializes
@@ -514,24 +515,6 @@
 
     ap_create_sb_handle(&sbh, pchild, my_child_num, 0);
 
-    (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
-
-    /* Set up the pollfd array */
-    /* ### check the status */
-    (void) apr_pollset_create(&pollset, num_listensocks, pchild, 0);
-
-    for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) {
-        apr_pollfd_t pfd = { 0 };
-
-        pfd.desc_type = APR_POLL_SOCKET;
-        pfd.desc.s = lr->sd;
-        pfd.reqevents = APR_POLLIN;
-        pfd.client_data = lr;
-
-        /* ### check the status */
-        (void) apr_pollset_add(pollset, &pfd);
-    }
-
     mpm_state = AP_MPMQ_RUNNING;
 
     bucket_alloc = apr_bucket_alloc_create(pchild);
@@ -560,6 +543,34 @@
         /* Lock around "accept", if necessary */
         SAFE_ACCEPT(accept_mutex_on());
 
+        /* Set up the pollfd array - we waste cycles on doing it inside the 
+         * loop, but we've got to do it this way to lock the non-accept() 
+         * ports */
+        /* ### check the status */
+        (void) apr_pollset_create(&pollset, num_listensocks, pchild, 0);
+
+        for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) {
+            apr_pollfd_t pfd = { 0 };
+            /** FIXME: We currently use this as a hack to see if we're actively 
+             *  operating on a UDP socket, since there's no accept()
+             *  
+             *  There's a really nasty gotcha here: since we only unlock the UDP
+             *  port at the end of the operation, but by that point another child
+             *  will already be polling the sockets, we won't start polling the
+             *  UDP port until after the next connection is received (and the next
+             *  child starts polling) */
+            if (lr->active != 1)
+                continue;
+
+            pfd.desc_type = APR_POLL_SOCKET;
+            pfd.desc.s = lr->sd;
+            pfd.reqevents = APR_POLLIN;
+            pfd.client_data = lr;
+
+            /* ### check the status */
+            (void) apr_pollset_add(pollset, &pfd);
+        }
+
         if (num_listensocks == 1) {
             /* There is only one listener record, so refer to that one. */
             lr = ap_listeners;
@@ -618,8 +629,24 @@
         /* if we accept() something we don't want to die, so we have to
          * defer the exit
          */
-        status = lr->accept_func(&csd, lr, ptrans);
 
+        status = APR_SUCCESS;
+        
+        /** Check for non-stream socket + lock */
+        apr_socket_type_get(lr->sd, &sd_type);
+
+        if (sd_type == SOCK_STREAM) {
+            status = lr->accept_func(&csd, lr, ptrans);
+        } else {
+            /** TODO: Tie this worker to this socket permanently - or come up
+             *  with a better way to ensure that a subsequent request can be
+             *  polled */
+            csd = lr->sd;
+            lr->active = 2; 
+        }
+
+        /** Release the pollset */
+        apr_pollset_destroy(pollset);        
         SAFE_ACCEPT(accept_mutex_off());      /* unlock after "accept" */
 
         if (status == APR_EGENERAL) {
@@ -638,7 +665,9 @@
         current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc);
         if (current_conn) {
             ap_process_connection(current_conn, csd);
-            ap_lingering_close(current_conn);
+            if (sd_type == SOCK_STREAM) {
+                ap_lingering_close(current_conn);
+            } 
         }
 
         /* Check the pod and the generation number after processing a
@@ -656,6 +685,9 @@
              */
             die_now = 1;
         }
+
+        /** Unlock socket, if needed.  No need to lock this */
+        lr->active = 1;
     }
     clean_child_exit(0);
 }
Only in httpd-2.2.6/server/mpm/prefork: prefork.c.orig
diff -r -U3 httpd-2.2.6-orig/server/mpm/worker/worker.c httpd-2.2.6/server/mpm/worker/worker.c
--- httpd-2.2.6-orig/server/mpm/worker/worker.c	2007-07-17 17:48:25.000000000 +0300
+++ httpd-2.2.6/server/mpm/worker/worker.c	2007-09-23 12:24:00.000000000 +0200
@@ -739,7 +739,9 @@
                 apr_allocator_owner_set(allocator, ptrans);
             }
             apr_pool_tag(ptrans, "transaction");
-            rv = lr->accept_func(&csd, lr, ptrans);
+            rv = APR_SUCCESS;
+            if (lr->accept_func)
+                rv = lr->accept_func(&csd, lr, ptrans);
             /* later we trash rv and rely on csd to indicate success/failure */
             AP_DEBUG_ASSERT(rv == APR_SUCCESS || !csd);
 
@@ -2258,3 +2260,4 @@
     worker_hooks                /* register_hooks */
 };
 
+
Only in httpd-2.2.6/server/mpm/worker: worker.c.orig
diff -r -U3 httpd-2.2.6-orig/server/mpm_common.c httpd-2.2.6/server/mpm_common.c
--- httpd-2.2.6-orig/server/mpm_common.c	2007-07-17 17:48:25.000000000 +0300
+++ httpd-2.2.6/server/mpm_common.c	2007-09-23 12:24:00.000000000 +0200
@@ -485,6 +485,13 @@
      *
      * In spite of these problems, failure here is not a shooting offense.
      */
+
+    int protocol;
+    if (!((apr_socket_protocol_get(s, &protocol) == APR_SUCCESS) &&
+          protocol == APR_PROTO_TCP))
+        /** Don't do anything unless we're a TCP socket */
+        return;
+    
     apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);
 
     if (status != APR_SUCCESS) {
@@ -648,6 +655,13 @@
     apr_socket_t *sock;
     apr_pool_t *p;
     apr_size_t len;
+    int protocol;
+    int type;
+    
+    if (apr_socket_type_get(ap_listeners->sd, &type) != APR_SUCCESS)
+        type = SOCK_STREAM;
+    if (apr_socket_protocol_get(ap_listeners->sd, &protocol) != APR_SUCCESS)
+        type = 0;
 
     /* create a temporary pool for the socket.  pconf stays around too long */
     rv = apr_pool_create(&p, pod->p);
@@ -656,7 +670,7 @@
     }
 
     rv = apr_socket_create(&sock, ap_listeners->bind_addr->family,
-                           SOCK_STREAM, 0, p);
+                           type, protocol, p);
     if (rv != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
                      "get socket to connect to listener");
Only in httpd-2.2.6/server: mpm_common.c.orig
Only in httpd-2.2.6/srclib/apr: apr-sock-sendtov.patch
Only in httpd-2.2.6/srclib/apr: config.nice
diff -r -U3 httpd-2.2.6-orig/srclib/apr/include/apr_network_io.h httpd-2.2.6/srclib/apr/include/apr_network_io.h
--- httpd-2.2.6-orig/srclib/apr/include/apr_network_io.h	2006-08-03 14:05:27.000000000 +0300
+++ httpd-2.2.6/srclib/apr/include/apr_network_io.h	2007-09-23 12:13:57.000000000 +0200
@@ -508,6 +508,34 @@
 
 /**
  * @param from The apr_sockaddr_t to fill in the recipient info
+ * Send multiple packets of data over a network.
+ * @param sock The socket to send the data over.
+ * @param where The apr_sockaddr_t describing where to send the data
+ * @param flags The flags to use
+ * @param vec The array of iovec structs containing the data to send 
+ * @param nvec The number of iovec structs in the array
+ * @param len Receives the number of bytes actually written
+ * @remark
+ * <PRE>
+ * This functions acts like a blocking write by default.  To change 
+ * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+ * socket option.
+ * The number of bytes actually sent is stored in argument 3.
+ *
+ * It is possible for both bytes to be sent and an error to be returned.
+ *
+ * APR_EINTR is never returned.
+ * </PRE>
+ */
+
+APR_DECLARE(apr_status_t) apr_socket_sendtov(apr_socket_t *sock,
+                                             apr_sockaddr_t *where,
+                                             apr_int32_t flags,
+                                             const struct iovec *vec,
+                                             apr_int32_t nvec,
+                                             apr_size_t *len);
+
+/**
  * @param sock The socket to use
  * @param flags The flags to use
  * @param buf  The buffer to use
Only in httpd-2.2.6/srclib/apr/include: apr_network_io.h.orig
diff -r -U3 httpd-2.2.6-orig/srclib/apr/network_io/unix/sendrecv.c httpd-2.2.6/srclib/apr/network_io/unix/sendrecv.c
--- httpd-2.2.6-orig/srclib/apr/network_io/unix/sendrecv.c	2007-04-23 13:45:55.000000000 +0300
+++ httpd-2.2.6/srclib/apr/network_io/unix/sendrecv.c	2007-09-23 12:13:00.000000000 +0200
@@ -180,7 +180,15 @@
     return APR_SUCCESS;
 }
 
-apr_status_t apr_socket_sendv(apr_socket_t * sock, const struct iovec *vec,
+apr_status_t apr_socket_sendtov(apr_socket_t *sock, apr_sockaddr_t *where,
+                                apr_int32_t flags, const struct iovec *vec,
+                                apr_int32_t nvec, apr_size_t *len)
+{
+    *len = vec[0].iov_len;
+    return apr_socket_sendto(sock, where, flags, vec[0].iov_base, len);
+}
+
+apr_status_t apr_socket_sendv(apr_socket_t *sock, const struct iovec *vec,
                               apr_int32_t nvec, apr_size_t *len)
 {
 #ifdef HAVE_WRITEV
Only in httpd-2.2.6/srclib/apr/network_io/unix: sendrecv.c.orig
Only in httpd-2.2.6/srclib/apr-util: aprutil-socket_bucket_udp.patch
diff -r -U3 httpd-2.2.6-orig/srclib/apr-util/buckets/apr_buckets_socket.c httpd-2.2.6/srclib/apr-util/buckets/apr_buckets_socket.c
--- httpd-2.2.6-orig/srclib/apr-util/buckets/apr_buckets_socket.c	2005-02-04 22:45:35.000000000 +0200
+++ httpd-2.2.6/srclib/apr-util/buckets/apr_buckets_socket.c	2007-09-23 12:06:15.000000000 +0200
@@ -23,6 +23,8 @@
     char *buf;
     apr_status_t rv;
     apr_interval_time_t timeout;
+    apr_sockaddr_t *peerptr, peer;
+    int sd_type;
 
     if (block == APR_NONBLOCK_READ) {
         apr_socket_timeout_get(p, &timeout);
@@ -33,7 +35,18 @@
     *len = APR_BUCKET_BUFF_SIZE;
     buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */
 
-    rv = apr_socket_recv(p, buf, len);
+    apr_socket_type_get(p, &sd_type);
+    if (sd_type == SOCK_STREAM) {
+        rv = apr_socket_recv(p, buf, len);    
+    } else {
+        /* Is socket connected? */
+        if (apr_socket_addr_get(&peerptr, APR_REMOTE, p) != APR_SUCCESS) {
+            rv = apr_socket_recv(p, buf, len);    
+        } else {
+            /* Caller is responsible for detecting peer on his own if needed */
+            rv = apr_socket_recvfrom(&peer, p, 0, buf, len);
+        }
+    }
 
     if (block == APR_NONBLOCK_READ) {
         apr_socket_timeout_set(p, timeout);
Only in httpd-2.2.6/srclib/apr-util: config.nice
Only in httpd-2.2.6: config.nice
Only in httpd-2.2.6-orig: .deps
Only in httpd-2.2.6: httpd-udp-disconnected.patch
diff -r -U3 httpd-2.2.6-orig/include/ap_listen.h httpd-2.2.6/include/ap_listen.h
--- httpd-2.2.6-orig/include/ap_listen.h	2007-05-09 22:35:45.000000000 +0300
+++ httpd-2.2.6/include/ap_listen.h	2007-09-23 12:24:00.000000000 +0200
@@ -81,6 +81,26 @@
 AP_DECLARE(void) ap_listen_pre_config(void);
 
 /**
+ * Allocate a new listener to be created during ap_setup_listeners.
+ * @param process The process_rec of the parent process
+ * @param addr The IP address to bind the socket to (uses same format as
+ * the Listen directive in httpd.conf)
+ * @param port The port to bind the socket to
+ * @param type The socket type (SOCK_STREAM, etc)
+ * @param protocol The socket protocol (APR_PROTO_TCP, etc)
+ * @param proto The optional protocol argument is not required for most
+ * configurations. If not specified, https is the default for port 443
+ * and http the default for all other ports. The protocol is used to
+ * determine which module should handle a request, and to apply
+ * protocol specific optimizations with the AcceptFilter directive.
+ * @return NULL on success, or an error message on failure
+ */
+
+AP_DECLARE(const char *) ap_alloc_listener(process_rec *process, char *addr,
+                                  apr_port_t port, int type, int protocol,
+                                  const char* proto);
+
+/**
  * Loop through the global ap_listen_rec list and create all of the required
  * sockets.  This executes the listen and bind on the sockets.
  * @param s The global server_rec
@@ -103,6 +123,9 @@
 AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg);
 AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, 
                                                 int argc, char *const argv[]);
+AP_DECLARE_NONSTD(const char *) ap_set_udp_listener(cmd_parms *cmd,
+                                                    void *dummy, int argc,
+                                                    char *const argv[]);
 AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
 				    const char *arg);
 AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd,
@@ -114,6 +137,10 @@
   "Maximum length of the queue of pending connections, as used by listen(2)"), \
 AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \
   "A port number or a numeric IP address and a port number, and an optional protocol"), \
+AP_INIT_TAKE_ARGV("ListenTCP", ap_set_listener, NULL, RSRC_CONF, \
+  "A port number or a numeric IP address and a port number, and an optional protocol"), \
+AP_INIT_TAKE_ARGV("ListenUDP", ap_set_udp_listener, NULL, RSRC_CONF, \
+  "A port number or a numeric IP address and a port number, and an optional protocol"), \
 AP_INIT_TAKE1("SendBufferSize", ap_set_send_buffer_size, NULL, RSRC_CONF, \
   "Send buffer size in bytes"), \
 AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \
diff -r -U3 httpd-2.2.6-orig/include/httpd.h httpd-2.2.6/include/httpd.h
--- httpd-2.2.6-orig/include/httpd.h	2006-10-13 00:55:03.000000000 +0200
+++ httpd-2.2.6/include/httpd.h	2007-09-23 12:29:57.000000000 +0200
@@ -1225,7 +1225,8 @@
     /** subpool of c->pool used for resources 
      * which may outlive the request
      */
-    apr_pool_t *deferred_write_pool;
+    apr_pool_t *deferred_write_pool;
+    int connected;
 } core_output_filter_ctx_t;
  
 typedef struct core_filter_ctx {
diff -r -U3 httpd-2.2.6-orig/server/core.c httpd-2.2.6/server/core.c
--- httpd-2.2.6-orig/server/core.c	2007-08-07 15:12:20.000000000 +0300
+++ httpd-2.2.6/server/core.c	2007-09-23 12:24:00.000000000 +0200
@@ -3872,6 +3872,7 @@
                                   apr_bucket_alloc_t *alloc)
 {
     apr_status_t rv;
+    int sd_type;
     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
 
     c->sbh = sbh;
@@ -3891,16 +3892,38 @@
         apr_socket_close(csd);
         return NULL;
     }
-
     apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
-    if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
-        != APR_SUCCESS) {
+    
+    apr_socket_type_get(csd, &sd_type);
+    if (sd_type == SOCK_STREAM &&
+        (rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
+        != APR_SUCCESS)
+    {
         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
                      "apr_socket_addr_get(APR_REMOTE)");
         apr_socket_close(csd);
         return NULL;
     }
-
+    if (sd_type != SOCK_STREAM) {
+        if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
+        != APR_SUCCESS)
+        {
+            char tmpbuf = 0;
+            apr_size_t tmpbuflen = 1;
+            /** Allocate a apr_sockaddr_t, since we can't use the one in csd */
+            c->remote_addr = apr_pcalloc(c->pool, sizeof(apr_sockaddr_t));
+            c->remote_addr->pool = c->pool;
+            if ((rv = apr_socket_recvfrom(c->remote_addr, csd, MSG_PEEK, 
+                                          &tmpbuf, &tmpbuflen))
+                != APR_SUCCESS)
+            {
+                ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
+                             "Error reading UDP peer");
+                /* Don't close non-connected UDP sockets */
+                return NULL;
+            }
+        }
+    }
     apr_sockaddr_ip_get(&c->remote_ip, c->remote_addr);
     c->base_server = server;
 
@@ -3913,6 +3936,7 @@
 static int core_pre_connection(conn_rec *c, void *csd)
 {
     core_net_rec *net = apr_palloc(c->pool, sizeof(*net));
+    int sd_type;
     apr_status_t rv;
 
 #ifdef AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
@@ -3923,13 +3947,17 @@
      * performance penalties.  (Failing to disable Nagle is not much of a
      * problem with simple HTTP.)
      */
-    rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
-    if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
-        /* expected cause is that the client disconnected already,
-         * hence the debug level
-         */
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
-                      "apr_socket_opt_set(APR_TCP_NODELAY)");
+
+    apr_socket_type_get(csd, &sd_type);
+    if (sd_type == SOCK_STREAM) {
+        rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
+        if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
+            /* expected cause is that the client disconnected already,
+             * hence the debug level
+             */
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
+                          "apr_socket_opt_set(APR_TCP_NODELAY)");
+        }
     }
 #endif
 
Only in httpd-2.2.6/server: core.c.orig
diff -r -U3 httpd-2.2.6-orig/server/core_filters.c httpd-2.2.6/server/core_filters.c
--- httpd-2.2.6-orig/server/core_filters.c	2006-07-12 06:38:44.000000000 +0300
+++ httpd-2.2.6/server/core_filters.c	2007-09-23 12:50:52.000000000 +0200
@@ -305,7 +305,9 @@
     return APR_SUCCESS;
 }
 
-static apr_status_t writev_it_all(apr_socket_t *s,
+static apr_status_t writev_it_all(apr_socket_t *s,
+                                  core_net_rec *c, 
+                                  int connected, 
                                   struct iovec *vec, int nvec,
                                   apr_size_t len, apr_size_t *nbytes)
 {
@@ -317,8 +319,12 @@
     *nbytes = 0;
 
     /* XXX handle checking for non-blocking socket */
-    while (bytes_written != len) {
-        rv = apr_socket_sendv(s, vec + i, nvec - i, &n);
+    while (bytes_written != len) {
+        if (connected) {
+            rv = apr_socket_sendv(s, vec + i, nvec - i, &n);
+        } else {
+            rv = apr_socket_sendtov(s, c->c->remote_addr, 0, vec + i, nvec - i, &n);
+        }
         *nbytes += n;
         bytes_written += n;
         if (rv != APR_SUCCESS)
@@ -448,7 +454,7 @@
  * to the network. emulate_sendfile will return only when all the bytes have been
  * sent (i.e., it handles partial writes) or on a network error condition.
  */
-static apr_status_t emulate_sendfile(core_net_rec *c, apr_file_t *fd,
+static apr_status_t emulate_sendfile(core_net_rec *c, int connected, apr_file_t *fd,
                                      apr_hdtr_t *hdtr, apr_off_t offset,
                                      apr_size_t length, apr_size_t *nbytes)
 {
@@ -472,7 +478,7 @@
             sendlen += hdtr->headers[i].iov_len;
         }
 
-        rv = writev_it_all(c->client_socket, hdtr->headers, hdtr->numheaders,
+        rv = writev_it_all(c->client_socket, c, connected, hdtr->headers, hdtr->numheaders,
                            sendlen, &bytes_sent);
         *nbytes += bytes_sent;     /* track total bytes sent */
     }
@@ -489,8 +495,12 @@
         o = 0;
         rv = apr_file_read(fd, buffer, &sendlen);
         while (rv == APR_SUCCESS && sendlen) {
-            bytes_sent = sendlen;
-            rv = apr_socket_send(c->client_socket, &buffer[o], &bytes_sent);
+            bytes_sent = sendlen;
+            if (connected) {
+                rv = apr_socket_send(c->client_socket, &buffer[o], &bytes_sent);
+            } else {
+                rv = apr_socket_sendto(c->client_socket, c->c->remote_addr, 0, &buffer[o], &bytes_sent);
+            }
             *nbytes += bytes_sent;
             if (rv == APR_SUCCESS) {
                 sendlen -= bytes_sent; /* sendlen != bytes_sent ==> partial write */
@@ -509,7 +519,7 @@
         for (i = 0; i < hdtr->numtrailers; i++) {
             sendlen += hdtr->trailers[i].iov_len;
         }
-        rv = writev_it_all(c->client_socket, hdtr->trailers, hdtr->numtrailers,
+        rv = writev_it_all(c->client_socket, c, connected, hdtr->trailers, hdtr->numtrailers,
                            sendlen, &bytes_sent);
         *nbytes += bytes_sent;
     }
@@ -542,9 +552,21 @@
     apr_read_type_e eblock = APR_NONBLOCK_READ;
     apr_pool_t *input_pool = b->p;
 
-    if (ctx == NULL) {
+    if (ctx == NULL) {
+        int sd_type;
         ctx = apr_pcalloc(c->pool, sizeof(*ctx));
-        net->out_ctx = ctx;
+        net->out_ctx = ctx;
+        ctx->connected = 1;
+        /* Check for non-connected socket */
+        apr_socket_type_get(net->client_socket, &sd_type);
+        if (sd_type != SOCK_STREAM) {
+            apr_sockaddr_t *peer;
+            if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE,
+                                          net->client_socket)) != APR_SUCCESS)
+                /* Disconnected socket */
+                ctx->connected = 0;
+        }
+
     }
 
     /* If we have a saved brigade, concatenate the new brigade to it */
@@ -831,7 +853,7 @@
             }
 
 #if APR_HAS_SENDFILE
-            if (apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) {
+            if ((apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) && ctx->connected) {
 
                 if (c->keepalive == AP_CONN_CLOSE && APR_BUCKET_IS_EOS(last_e)) {
                     /* Prepare the socket to be reused */
@@ -853,7 +875,7 @@
             else
 #endif
             {
-                rv = emulate_sendfile(net, fd, &hdtr, foffset, flen,
+                rv = emulate_sendfile(net, ctx->connected, fd, &hdtr, foffset, flen,
                                       &bytes_sent);
             }
 
@@ -865,7 +887,7 @@
         else {
             apr_size_t bytes_sent;
 
-            rv = writev_it_all(net->client_socket,
+            rv = writev_it_all(net->client_socket, net, ctx->connected,
                                vec, nvec,
                                nbytes, &bytes_sent);
 
Only in httpd-2.2.6/server: core_filters.c.orig
diff -r -U3 httpd-2.2.6-orig/server/listen.c httpd-2.2.6/server/listen.c
--- httpd-2.2.6-orig/server/listen.c	2006-12-20 04:04:39.000000000 +0200
+++ httpd-2.2.6/server/listen.c	2007-09-23 12:27:32.000000000 +0200
@@ -49,6 +49,7 @@
     int v6only_setting = 1;
 #endif
 #endif
+    int type;
     apr_status_t stat;
 
 #ifndef WIN32
@@ -136,8 +137,17 @@
         apr_socket_close(s);
         return stat;
     }
-
-    if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
+    
+    if ((stat = apr_socket_type_get(s, &type)) != APR_SUCCESS) {
+        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p,
+                      "make_sock: could not determine socket type for "
+                      "address %pI", server->bind_addr);
+        apr_socket_close(s);
+        return stat;
+    }
+    
+    if (type == SOCK_STREAM &&
+        ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS)) {
         ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p,
                       "make_sock: unable to listen for connections "
                       "on address %pI",
@@ -204,7 +214,8 @@
     const char *accf;
     apr_status_t rv;
     const char *proto;
-
+    int protocol;
+    
     proto = lis->protocol;
 
     if (!proto) {
@@ -224,11 +235,14 @@
                           accf);
         }
 #else
-#ifdef APR_TCP_DEFER_ACCEPT
-        rv = apr_socket_opt_set(s, APR_TCP_DEFER_ACCEPT, 1);
-        if (rv != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(rv)) {
-            ap_log_perror(APLOG_MARK, APLOG_WARNING, rv, p,
-                              "Failed to enable APR_TCP_DEFER_ACCEPT");
+#ifdef APR_TCP_DEFER_ACCEPT
+        rv = apr_socket_protocol_get(s, &protocol);
+        if ((rv == APR_SUCCESS) && (protocol == APR_PROTO_TCP)) {
+            rv = apr_socket_opt_set(s, APR_TCP_DEFER_ACCEPT, 1);
+            if (rv != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(rv)) {
+                ap_log_perror(APLOG_MARK, APLOG_WARNING, rv, p,
+                                  "Failed to enable APR_TCP_DEFER_ACCEPT");
+            }
         }
 #endif
 #endif
@@ -241,12 +255,14 @@
     return APR_SUCCESS;
 }
 
-static const char *alloc_listener(process_rec *process, char *addr,
-                                  apr_port_t port, const char* proto)
+AP_DECLARE(const char *) ap_alloc_listener(process_rec *process, char *addr,
+                                  apr_port_t port, int type, int protocol,
+                                  const char* proto)
 {
     ap_listen_rec **walk, *last;
     apr_status_t status;
     apr_sockaddr_t *sa;
+    apr_socket_t *sd;
     int found_listener = 0;
 
     /* see if we've got an old listener for this address:port */
@@ -255,13 +271,20 @@
         /* Some listeners are not real so they will not have a bind_addr. */
         if (sa) {
             ap_listen_rec *new;
+            sd = (*walk)->sd;
             apr_port_t oldport;
+            int oldprotocol = -1;
+            int oldtype = -1;
 
             oldport = sa->port;
-            /* If both ports are equivalent, then if their names are equivalent,
+            apr_socket_type_get(sd, &oldtype);
+            apr_socket_protocol_get(sd, &oldprotocol);
+            /* If both ports are equivalent and both socket type/protocols are
+             * equivalent, then if their names are equivalent,
              * then we will re-use the existing record.
              */
-            if (port == oldport &&
+            if ((port == oldport &&
+                 (type == oldtype && protocol == oldprotocol)) &&
                 ((!addr && !sa->hostname) ||
                  ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
                 new = *walk;
@@ -284,7 +307,7 @@
                                         process->pool))
         != APR_SUCCESS) {
         ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
-                      "alloc_listener: failed to set up sockaddr for %s",
+                      "ap_alloc_listener: failed to set up sockaddr for %s",
                       addr);
         return "Listen setup failed";
     }
@@ -309,7 +332,7 @@
         sa = sa->next;
 
         status = apr_socket_create(&new->sd, new->bind_addr->family,
-                                    SOCK_STREAM, 0, process->pool);
+                                    type, protocol, process->pool);
 
 #if APR_HAVE_IPV6
         /* What could happen is that we got an IPv6 address, but this system
@@ -322,7 +345,7 @@
 #endif
         if (status != APR_SUCCESS) {
             ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
-                          "alloc_listener: failed to get a socket for %s",
+                          "ap_alloc_listener: failed to get a socket for %s",
                           addr);
             return "Listen setup failed";
         }
@@ -583,7 +606,6 @@
     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
 }
 
-
 AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
                                                 int argc, char *const argv[])
 {
@@ -626,7 +648,55 @@
         ap_str_tolower(proto);
     }
 
-    return alloc_listener(cmd->server->process, host, port, proto);
+    return ap_alloc_listener(cmd->server->process, host, port,
+                             SOCK_STREAM, 0, proto);
+}
+
+AP_DECLARE_NONSTD(const char *) ap_set_udp_listener(cmd_parms *cmd,
+                                                    void *dummy, int argc,
+                                                    char *const argv[])
+{
+    char *host, *scope_id, *proto;
+    apr_port_t port;
+    apr_status_t rv;
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+    if (err != NULL) {
+        return err;
+    }
+
+    if (argc < 1 || argc > 2) {
+        return "Listen requires 1 or 2 arguments.";
+    }
+
+    rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool);
+    if (rv != APR_SUCCESS) {
+        return "Invalid address or port";
+    }
+
+    if (host && !strcmp(host, "*")) {
+        host = NULL;
+    }
+
+    if (scope_id) {
+        /* XXX scope id support is useful with link-local IPv6 addresses */
+        return "Scope id is not supported";
+    }
+
+    if (!port) {
+        return "Port must be specified";
+    }
+
+    if (argc != 2) {
+        proto = "http";
+    }
+    else {
+        proto = apr_pstrdup(cmd->pool, argv[1]);
+        ap_str_tolower(proto);
+    }
+
+    return ap_alloc_listener(cmd->server->process, host, port,
+                             SOCK_DGRAM, APR_PROTO_UDP, proto);
 }
 
 AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd,
Only in httpd-2.2.6/server: listen.c.orig
diff -r -U3 httpd-2.2.6-orig/server/mpm/experimental/event/event.c httpd-2.2.6/server/mpm/experimental/event/event.c
--- httpd-2.2.6-orig/server/mpm/experimental/event/event.c	2007-07-17 17:48:25.000000000 +0300
+++ httpd-2.2.6/server/mpm/experimental/event/event.c	2007-09-23 12:24:00.000000000 +0200
@@ -970,7 +970,9 @@
 
                 apr_pool_tag(ptrans, "transaction");
 
-                rc = lr->accept_func(&csd, lr, ptrans);
+                rc = APR_SUCCESS;
+                if (lr->accept_func)
+                    rc = lr->accept_func(&csd, lr, ptrans);
 
                 /* later we trash rv and rely on csd to indicate
                  * success/failure
Only in httpd-2.2.6/server/mpm/experimental/event: event.c.orig
diff -r -U3 httpd-2.2.6-orig/server/mpm/prefork/prefork.c httpd-2.2.6/server/mpm/prefork/prefork.c
--- httpd-2.2.6-orig/server/mpm/prefork/prefork.c	2007-07-17 17:48:25.000000000 +0300
+++ httpd-2.2.6/server/mpm/prefork/prefork.c	2007-09-23 12:24:00.000000000 +0200
@@ -474,6 +474,7 @@
     ap_sb_handle_t *sbh;
     apr_bucket_alloc_t *bucket_alloc;
     int last_poll_idx = 0;
+    int sd_type;
 
     mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
                                    * child initializes
@@ -514,24 +515,6 @@
 
     ap_create_sb_handle(&sbh, pchild, my_child_num, 0);
 
-    (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
-
-    /* Set up the pollfd array */
-    /* ### check the status */
-    (void) apr_pollset_create(&pollset, num_listensocks, pchild, 0);
-
-    for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) {
-        apr_pollfd_t pfd = { 0 };
-
-        pfd.desc_type = APR_POLL_SOCKET;
-        pfd.desc.s = lr->sd;
-        pfd.reqevents = APR_POLLIN;
-        pfd.client_data = lr;
-
-        /* ### check the status */
-        (void) apr_pollset_add(pollset, &pfd);
-    }
-
     mpm_state = AP_MPMQ_RUNNING;
 
     bucket_alloc = apr_bucket_alloc_create(pchild);
@@ -560,6 +543,34 @@
         /* Lock around "accept", if necessary */
         SAFE_ACCEPT(accept_mutex_on());
 
+        /* Set up the pollfd array - we waste cycles on doing it inside the 
+         * loop, but we've got to do it this way to lock the non-accept() 
+         * ports */
+        /* ### check the status */
+        (void) apr_pollset_create(&pollset, num_listensocks, pchild, 0);
+
+        for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) {
+            apr_pollfd_t pfd = { 0 };
+            /** FIXME: We currently use this as a hack to see if we're actively 
+             *  operating on a UDP socket, since there's no accept()
+             *  
+             *  There's a really nasty gotcha here: since we only unlock the UDP
+             *  port at the end of the operation, but by that point another child
+             *  will already be polling the sockets, we won't start polling the
+             *  UDP port until after the next connection is received (and the next
+             *  child starts polling) */
+            if (lr->active != 1)
+                continue;
+
+            pfd.desc_type = APR_POLL_SOCKET;
+            pfd.desc.s = lr->sd;
+            pfd.reqevents = APR_POLLIN;
+            pfd.client_data = lr;
+
+            /* ### check the status */
+            (void) apr_pollset_add(pollset, &pfd);
+        }
+
         if (num_listensocks == 1) {
             /* There is only one listener record, so refer to that one. */
             lr = ap_listeners;
@@ -618,8 +629,24 @@
         /* if we accept() something we don't want to die, so we have to
          * defer the exit
          */
-        status = lr->accept_func(&csd, lr, ptrans);
 
+        status = APR_SUCCESS;
+        
+        /** Check for non-stream socket + lock */
+        apr_socket_type_get(lr->sd, &sd_type);
+
+        if (sd_type == SOCK_STREAM) {
+            status = lr->accept_func(&csd, lr, ptrans);
+        } else {
+            /** TODO: Tie this worker to this socket permanently - or come up
+             *  with a better way to ensure that a subsequent request can be
+             *  polled */
+            csd = lr->sd;
+            lr->active = 2; 
+        }
+
+        /** Release the pollset */
+        apr_pollset_destroy(pollset);        
         SAFE_ACCEPT(accept_mutex_off());      /* unlock after "accept" */
 
         if (status == APR_EGENERAL) {
@@ -638,7 +665,9 @@
         current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc);
         if (current_conn) {
             ap_process_connection(current_conn, csd);
-            ap_lingering_close(current_conn);
+            if (sd_type == SOCK_STREAM) {
+                ap_lingering_close(current_conn);
+            } 
         }
 
         /* Check the pod and the generation number after processing a
@@ -656,6 +685,9 @@
              */
             die_now = 1;
         }
+
+        /** Unlock socket, if needed.  No need to lock this */
+        lr->active = 1;
     }
     clean_child_exit(0);
 }
Only in httpd-2.2.6/server/mpm/prefork: prefork.c.orig
diff -r -U3 httpd-2.2.6-orig/server/mpm/worker/worker.c httpd-2.2.6/server/mpm/worker/worker.c
--- httpd-2.2.6-orig/server/mpm/worker/worker.c	2007-07-17 17:48:25.000000000 +0300
+++ httpd-2.2.6/server/mpm/worker/worker.c	2007-09-23 12:24:00.000000000 +0200
@@ -739,7 +739,9 @@
                 apr_allocator_owner_set(allocator, ptrans);
             }
             apr_pool_tag(ptrans, "transaction");
-            rv = lr->accept_func(&csd, lr, ptrans);
+            rv = APR_SUCCESS;
+            if (lr->accept_func)
+                rv = lr->accept_func(&csd, lr, ptrans);
             /* later we trash rv and rely on csd to indicate success/failure */
             AP_DEBUG_ASSERT(rv == APR_SUCCESS || !csd);
 
@@ -2258,3 +2260,4 @@
     worker_hooks                /* register_hooks */
 };
 
+
Only in httpd-2.2.6/server/mpm/worker: worker.c.orig
diff -r -U3 httpd-2.2.6-orig/server/mpm_common.c httpd-2.2.6/server/mpm_common.c
--- httpd-2.2.6-orig/server/mpm_common.c	2007-07-17 17:48:25.000000000 +0300
+++ httpd-2.2.6/server/mpm_common.c	2007-09-23 12:24:00.000000000 +0200
@@ -485,6 +485,13 @@
      *
      * In spite of these problems, failure here is not a shooting offense.
      */
+
+    int protocol;
+    if (!((apr_socket_protocol_get(s, &protocol) == APR_SUCCESS) &&
+          protocol == APR_PROTO_TCP))
+        /** Don't do anything unless we're a TCP socket */
+        return;
+    
     apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);
 
     if (status != APR_SUCCESS) {
@@ -648,6 +655,13 @@
     apr_socket_t *sock;
     apr_pool_t *p;
     apr_size_t len;
+    int protocol;
+    int type;
+    
+    if (apr_socket_type_get(ap_listeners->sd, &type) != APR_SUCCESS)
+        type = SOCK_STREAM;
+    if (apr_socket_protocol_get(ap_listeners->sd, &protocol) != APR_SUCCESS)
+        type = 0;
 
     /* create a temporary pool for the socket.  pconf stays around too long */
     rv = apr_pool_create(&p, pod->p);
@@ -656,7 +670,7 @@
     }
 
     rv = apr_socket_create(&sock, ap_listeners->bind_addr->family,
-                           SOCK_STREAM, 0, p);
+                           type, protocol, p);
     if (rv != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
                      "get socket to connect to listener");
Only in httpd-2.2.6/server: mpm_common.c.orig
Only in httpd-2.2.6/srclib/apr: apr-sock-sendtov.patch
Only in httpd-2.2.6/srclib/apr: config.nice
diff -r -U3 httpd-2.2.6-orig/srclib/apr/include/apr_network_io.h httpd-2.2.6/srclib/apr/include/apr_network_io.h
--- httpd-2.2.6-orig/srclib/apr/include/apr_network_io.h	2006-08-03 14:05:27.000000000 +0300
+++ httpd-2.2.6/srclib/apr/include/apr_network_io.h	2007-09-23 12:13:57.000000000 +0200
@@ -508,6 +508,34 @@
 
 /**
  * @param from The apr_sockaddr_t to fill in the recipient info
+ * Send multiple packets of data over a network.
+ * @param sock The socket to send the data over.
+ * @param where The apr_sockaddr_t describing where to send the data
+ * @param flags The flags to use
+ * @param vec The array of iovec structs containing the data to send 
+ * @param nvec The number of iovec structs in the array
+ * @param len Receives the number of bytes actually written
+ * @remark
+ * <PRE>
+ * This functions acts like a blocking write by default.  To change 
+ * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+ * socket option.
+ * The number of bytes actually sent is stored in argument 3.
+ *
+ * It is possible for both bytes to be sent and an error to be returned.
+ *
+ * APR_EINTR is never returned.
+ * </PRE>
+ */
+
+APR_DECLARE(apr_status_t) apr_socket_sendtov(apr_socket_t *sock,
+                                             apr_sockaddr_t *where,
+                                             apr_int32_t flags,
+                                             const struct iovec *vec,
+                                             apr_int32_t nvec,
+                                             apr_size_t *len);
+
+/**
  * @param sock The socket to use
  * @param flags The flags to use
  * @param buf  The buffer to use
Only in httpd-2.2.6/srclib/apr/include: apr_network_io.h.orig
Only in httpd-2.2.6/srclib/apr/network_io/unix: apr-1.2.0-recvfrom-unixonly.patch
diff -r -U3 httpd-2.2.6-orig/srclib/apr/network_io/unix/sendrecv.c httpd-2.2.6/srclib/apr/network_io/unix/sendrecv.c
--- httpd-2.2.6-orig/srclib/apr/network_io/unix/sendrecv.c	2007-04-23 13:45:55.000000000 +0300
+++ httpd-2.2.6/srclib/apr/network_io/unix/sendrecv.c	2007-11-02 00:19:36.000000000 +0200
@@ -114,6 +114,8 @@
                                apr_size_t *len)
 {
     apr_ssize_t rv;
+    
+    from->salen = sizeof(from->sa);
 
     do {
         rv = sendto(sock->socketdes, buf, (*len), flags, 
@@ -147,40 +149,52 @@
                                  apr_int32_t flags, char *buf, 
                                  apr_size_t *len)
 {
-    apr_ssize_t rv;
-
-    do {
-        rv = recvfrom(sock->socketdes, buf, (*len), flags, 
-                      (struct sockaddr*)&from->sa, &from->salen);
-    } while (rv == -1 && errno == EINTR);
-
-    while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK)
-                      && (sock->timeout > 0)) {
-        apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 1);
-        if (arv != APR_SUCCESS) {
-            *len = 0;
-            return arv;
-        } else {
-            do {
-                rv = recvfrom(sock->socketdes, buf, (*len), flags,
-                              (struct sockaddr*)&from->sa, &from->salen);
-            } while (rv == -1 && errno == EINTR);
-        }
-    }
-    if (rv == -1) {
-        (*len) = 0;
-        return errno;
-    }
-
-    (*len) = rv;
-    if (rv == 0 && sock->type == SOCK_STREAM) {
-        return APR_EOF;
-    }
-
+    apr_ssize_t rv;
+    
+    from->salen = sizeof(from->sa);
+
+    do {
+        rv = recvfrom(sock->socketdes, buf, (*len), flags, 
+                      (struct sockaddr*)&from->sa, &from->salen);
+    } while (rv == -1 && errno == EINTR);
+
+    while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK)
+                      && (sock->timeout > 0)) {
+        apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 1);
+        if (arv != APR_SUCCESS) {
+            *len = 0;
+            return arv;
+        } else {
+            do {
+                rv = recvfrom(sock->socketdes, buf, (*len), flags,
+                              (struct sockaddr*)&from->sa, &from->salen);
+            } while (rv == -1 && errno == EINTR);
+        }
+    }
+    if (rv == -1) {
+        (*len) = 0;
+        return errno;
+    }
+
+    apr_sockaddr_vars_set(from, from->sa.sin.sin_family, ntohs(from->sa.sin.sin_port));
+
+    (*len) = rv;
+    if (rv == 0 && sock->type == SOCK_STREAM) {
+        return APR_EOF;
+    }
+
     return APR_SUCCESS;
 }
 
-apr_status_t apr_socket_sendv(apr_socket_t * sock, const struct iovec *vec,
+apr_status_t apr_socket_sendtov(apr_socket_t *sock, apr_sockaddr_t *where,
+                                apr_int32_t flags, const struct iovec *vec,
+                                apr_int32_t nvec, apr_size_t *len)
+{
+    *len = vec[0].iov_len;
+    return apr_socket_sendto(sock, where, flags, vec[0].iov_base, len);
+}
+
+apr_status_t apr_socket_sendv(apr_socket_t *sock, const struct iovec *vec,
                               apr_int32_t nvec, apr_size_t *len)
 {
 #ifdef HAVE_WRITEV
Only in httpd-2.2.6/srclib/apr/network_io/unix: sendrecv.c.orig
Only in httpd-2.2.6/srclib/apr/network_io/unix: sendrecv.c.rej
Only in httpd-2.2.6/srclib/apr-util: aprutil-socket_bucket_udp.patch
diff -r -U3 httpd-2.2.6-orig/srclib/apr-util/buckets/apr_buckets_socket.c httpd-2.2.6/srclib/apr-util/buckets/apr_buckets_socket.c
--- httpd-2.2.6-orig/srclib/apr-util/buckets/apr_buckets_socket.c	2005-02-04 22:45:35.000000000 +0200
+++ httpd-2.2.6/srclib/apr-util/buckets/apr_buckets_socket.c	2007-09-23 12:06:15.000000000 +0200
@@ -23,6 +23,8 @@
     char *buf;
     apr_status_t rv;
     apr_interval_time_t timeout;
+    apr_sockaddr_t *peerptr, peer;
+    int sd_type;
 
     if (block == APR_NONBLOCK_READ) {
         apr_socket_timeout_get(p, &timeout);
@@ -33,7 +35,18 @@
     *len = APR_BUCKET_BUFF_SIZE;
     buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */
 
-    rv = apr_socket_recv(p, buf, len);
+    apr_socket_type_get(p, &sd_type);
+    if (sd_type == SOCK_STREAM) {
+        rv = apr_socket_recv(p, buf, len);    
+    } else {
+        /* Is socket connected? */
+        if (apr_socket_addr_get(&peerptr, APR_REMOTE, p) != APR_SUCCESS) {
+            rv = apr_socket_recv(p, buf, len);    
+        } else {
+            /* Caller is responsible for detecting peer on his own if needed */
+            rv = apr_socket_recvfrom(&peer, p, 0, buf, len);
+        }
+    }
 
     if (block == APR_NONBLOCK_READ) {
         apr_socket_timeout_set(p, timeout);
Only in httpd-2.2.6/srclib/apr-util: config.nice

Mail converted by mhonarc 2.6.15
This archive provided courtesy of JSW4.NET, Internet Hosting Services for Small Business.