After taking my own advice on Sunday, I reworked everything I'd done for
UDP support and focused on allowing the core I/O filters to work with
non-connected sockets.  I'm happy to report that I've come up with a
working prototype for prefork that doesn't require substantial amounts
of mucking with the MPM code.  It requires patches to APR (to add a
apr_socket_sendtov function, needed by the core output filter) and
APR-Util to support apr_socket_readfrom in socket buckets that aren't
connected).  Both of these patches would be useful in APR/APR-Util
regardles (although the APR patch still requires work for win32, beos
and netware - I suppose I'll tackle at least win32 [which I'm familiar
with] later today and we'll see about the others).  As such, I've added
these both to bugzilla to
https://issues.apache.org/bugzilla/show_bug.cgi?id=43309 and
https://issues.apache.org/bugzilla/show_bug.cgi?id=43302, respectively.

To go through what I've done in the main patch (for those who want an
idea of what they're looking at):

* Export ap_alloc_listner and take socket type/protocol as arguments
* In core_create_conn, if the remote_addr of the socket can't be
detected from the socket, try to run recvfrom in PEEK mode to get the
peer address
* Core input filters run as-is (patch to apr-util does everything)
* Core output filter tries (in init) to see if socket is connected.  If
not, it turns of a new flag, connected, in ctx which is ultimately used
to decide whether to pass data to apr_socket_sendv or apr_socket_sendtov
* Additionally, disable SENDFILE for non-stream sockets
* Create ListenUDP config directive to create UDP listeners
* Alter all MPMs to only call lr->accept_func if it's defined
* In prefork, re-create the pollset in every iteration of child_main.
Hack the use of lr->active to add a flag (value 2) for in-use UDP sockets

Index: buckets/apr_buckets_socket.c
===================================================================
--- buckets/apr_buckets_socket.c        (revision 572605)
+++ buckets/apr_buckets_socket.c        (working copy)
@@ -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);

Index: include/ap_listen.h
===================================================================
--- include/ap_listen.h (revision 565699)
+++ include/ap_listen.h (working copy)
@@ -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, \
Index: include/httpd.h
===================================================================
--- include/httpd.h     (revision 565699)
+++ include/httpd.h     (working copy)
@@ -1224,6 +1224,7 @@
     apr_bucket_brigade *buffered_bb;
     apr_size_t bytes_in;
     apr_size_t bytes_written;
+    int connected;
 } core_output_filter_ctx_t;
  
 typedef struct core_filter_ctx {
Index: server/core.c
===================================================================
--- server/core.c       (revision 565699)
+++ server/core.c       (working copy)
@@ -3778,6 +3778,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;
@@ -3797,16 +3798,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;
 
@@ -3828,6 +3851,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
@@ -3838,13 +3862,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
 
Index: server/core_filters.c
===================================================================
--- server/core_filters.c       (revision 565699)
+++ server/core_filters.c       (working copy)
@@ -311,6 +311,7 @@
                                       int make_a_copy, conn_rec *c);
 
 static apr_status_t send_brigade_nonblocking(apr_socket_t *s,
+                                             int connected,
                                              apr_bucket_brigade *bb,
                                              apr_size_t *bytes_written,
                                              conn_rec *c);
@@ -318,11 +319,13 @@
 static void remove_empty_buckets(apr_bucket_brigade *bb);
 
 static apr_status_t send_brigade_blocking(apr_socket_t *s,
+                                          int connected,
                                           apr_bucket_brigade *bb,
                                           apr_size_t *bytes_written,
                                           conn_rec *c);
 
 static apr_status_t writev_nonblocking(apr_socket_t *s,
+                                       int connected,
                                        struct iovec *vec, apr_size_t nvec,
                                        apr_bucket_brigade *bb,
                                        apr_size_t *cumulative_bytes_written,
@@ -360,12 +363,23 @@
 
     if (ctx == NULL) {
         apr_status_t rv;
+        int sd_type;
         ctx = apr_pcalloc(c->pool, sizeof(*ctx));
+        ctx->connected = 1;
         net->out_ctx = (core_output_filter_ctx_t *)ctx;
         rv = apr_socket_opt_set(net->client_socket, APR_SO_NONBLOCK, 1);
         if (rv != APR_SUCCESS) {
             return rv;
         }
+        /* 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 (new_bb != NULL) {
@@ -419,7 +433,8 @@
      */
 
     if (new_bb == NULL) {
-        apr_status_t rv = send_brigade_nonblocking(net->client_socket, bb,
+        apr_status_t rv = send_brigade_nonblocking(net->client_socket,
+                                                   ctx->connected, bb,
                                                    &(ctx->bytes_written), c);
         if (APR_STATUS_IS_EAGAIN(rv)) {
             rv = APR_SUCCESS;
@@ -439,7 +454,8 @@
         next = APR_BUCKET_NEXT(bucket);
         if (APR_BUCKET_IS_FLUSH(bucket)) {
             apr_bucket_brigade *remainder = apr_brigade_split(bb, next);
-            apr_status_t rv = send_brigade_blocking(net->client_socket, bb,
+            apr_status_t rv = send_brigade_blocking(net->client_socket,
+                                                    ctx->connected, bb,
                                                     &(ctx->bytes_written), c);
             if (rv != APR_SUCCESS) {
                 /* The client has aborted the connection */
@@ -475,7 +491,8 @@
         /* ### Writing the entire brigade may be excessive; we really just
          * ### need to send enough data to be under THRESHOLD_MAX_BUFFER.
          */
-        apr_status_t rv = send_brigade_blocking(net->client_socket, bb,
+        apr_status_t rv = send_brigade_blocking(net->client_socket,
+                                                ctx->connected, bb,
                                                 &(ctx->bytes_written), c);
         if (rv != APR_SUCCESS) {
             /* The client has aborted the connection */
@@ -484,7 +501,8 @@
         }
     }
     else if (bytes_in_brigade >= THRESHOLD_MIN_WRITE) {
-        apr_status_t rv = send_brigade_nonblocking(net->client_socket, bb,
+        apr_status_t rv = send_brigade_nonblocking(net->client_socket,
+                                                   ctx->connected, bb,
                                                    &(ctx->bytes_written), c);
         if ((rv != APR_SUCCESS) && (!APR_STATUS_IS_EAGAIN(rv))) {
             /* The client has aborted the connection */
@@ -535,12 +553,14 @@
 #endif
 
 static apr_status_t send_brigade_nonblocking(apr_socket_t *s,
+                                             int connected,
                                              apr_bucket_brigade *bb,
                                              apr_size_t *bytes_written,
                                              conn_rec *c)
 {
     apr_bucket *bucket, *next;
     apr_status_t rv;
+    int type;
     struct iovec vec[MAX_IOVEC_TO_WRITE];
     apr_size_t nvec = 0;
 
@@ -552,7 +572,12 @@
         int did_sendfile = 0;
         next = APR_BUCKET_NEXT(bucket);
 #if APR_HAS_SENDFILE
-        if (APR_BUCKET_IS_FILE(bucket)) {
+        /** Don't even bother with sendfile if we're not dealing with a
+         *  SOCK_STREAM socket
+         */
+        if (APR_BUCKET_IS_FILE(bucket) &&
+            ((apr_socket_type_get(s, &type) == APR_SUCCESS) && 
+             (type == SOCK_STREAM))) {
             apr_bucket_file *file_bucket = (apr_bucket_file *)(bucket->data);
             apr_file_t *fd = file_bucket->fd;
             /* Use sendfile to send this file unless:
@@ -566,7 +591,8 @@
                 did_sendfile = 1;
                 if (nvec > 0) {
                     (void)apr_socket_opt_set(s, APR_TCP_NOPUSH, 1);
-                    rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, 
c);
+                    rv = writev_nonblocking(s, connected, vec, nvec, bb,
+                                            bytes_written, c);
                     nvec = 0;
                     if (rv != APR_SUCCESS) {
                         (void)apr_socket_opt_set(s, APR_TCP_NOPUSH, 0);
@@ -597,7 +623,9 @@
             vec[nvec].iov_len = length;
             nvec++;
             if (nvec == MAX_IOVEC_TO_WRITE) {
-                rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
+                
+                rv = writev_nonblocking(s, connected, vec, nvec, bb,
+                                        bytes_written, c);
                 nvec = 0;
                 if (rv != APR_SUCCESS) {
                     return rv;
@@ -608,7 +636,7 @@
     }
 
     if (nvec > 0) {
-        rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
+        rv = writev_nonblocking(s, connected, vec, nvec, bb, bytes_written, c);
         if (rv != APR_SUCCESS) {
             return rv;
         }
@@ -630,6 +658,7 @@
 }
 
 static apr_status_t send_brigade_blocking(apr_socket_t *s,
+                                          int connected,
                                           apr_bucket_brigade *bb,
                                           apr_size_t *bytes_written,
                                           conn_rec *c)
@@ -638,7 +667,7 @@
 
     rv = APR_SUCCESS;
     while (!APR_BRIGADE_EMPTY(bb)) {
-        rv = send_brigade_nonblocking(s, bb, bytes_written, c);
+        rv = send_brigade_nonblocking(s, connected, bb, bytes_written, c);
         if (rv != APR_SUCCESS) {
             if (APR_STATUS_IS_EAGAIN(rv)) {
                 /* Wait until we can send more data */
@@ -665,6 +694,7 @@
 }
 
 static apr_status_t writev_nonblocking(apr_socket_t *s,
+                                       int connected,
                                        struct iovec *vec, apr_size_t nvec,
                                        apr_bucket_brigade *bb,
                                        apr_size_t *cumulative_bytes_written,
@@ -690,7 +720,12 @@
     offset = 0;
     while (bytes_written < bytes_to_write) {
         apr_size_t n = 0;
-        rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
+        if (connected) {
+            rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
+        } else {
+            rv = apr_socket_sendtov(s, c->remote_addr, 0, vec + offset,
+                                    nvec - offset, &n);
+        }
         if (n > 0) {
             bytes_written += n;
             for (i = offset; i < nvec; ) {
Index: server/listen.c
===================================================================
--- server/listen.c     (revision 565699)
+++ server/listen.c     (working copy)
@@ -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) {
@@ -225,10 +236,13 @@
         }
 #else
 #ifdef APR_TCP_DEFER_ACCEPT
-        rv = apr_socket_opt_set(s, APR_TCP_DEFER_ACCEPT, 30);
-        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");
+        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, 30);
+            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,9 +648,57 @@
         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,
                                                      void *dummy,
                                                      const char *arg)
Index: server/mpm/experimental/event/event.c
===================================================================
--- server/mpm/experimental/event/event.c       (revision 565699)
+++ server/mpm/experimental/event/event.c       (working copy)
@@ -1019,7 +1019,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
Index: server/mpm/experimental/leader/leader.c
===================================================================
--- server/mpm/experimental/leader/leader.c     (revision 565699)
+++ server/mpm/experimental/leader/leader.c     (working copy)
@@ -786,7 +786,9 @@
         }
     got_fd:
         if (!workers_may_exit) {
-            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);
 
@@ -1996,3 +1998,4 @@
     leader_hooks                /* register_hooks */
 };
 
+
Index: server/mpm/experimental/perchild/perchild.c
===================================================================
--- server/mpm/experimental/perchild/perchild.c (revision 565699)
+++ server/mpm/experimental/perchild/perchild.c (working copy)
@@ -736,7 +736,9 @@
         }
     got_fd:
         if (!workers_may_exit) {
-            rv = lr->accept_func(&csd, lr, ptrans);
+            rv = APR_SUCCESS;
+            if (lr->accept_func)
+                rv = lr->accept_func(&csd, lr, ptrans);
             if (rv == APR_EGENERAL) {
                 /* E[NM]FILE, ENOMEM, etc */
                 workers_may_exit = 1;
@@ -2049,3 +2051,4 @@
     perchild_hooks              /* register_hooks */
 };
 
+
Index: server/mpm/experimental/threadpool/threadpool.c
===================================================================
--- server/mpm/experimental/threadpool/threadpool.c     (revision 565699)
+++ server/mpm/experimental/threadpool/threadpool.c     (working copy)
@@ -855,7 +855,9 @@
             }
         }
         if (!listener_may_exit) {
-            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);
 
@@ -2250,3 +2252,4 @@
     threadpool_hooks            /* register_hooks */
 };
 
+
Index: server/mpm/prefork/prefork.c
===================================================================
--- server/mpm/prefork/prefork.c        (revision 565699)
+++ server/mpm/prefork/prefork.c        (working copy)
@@ -450,6 +450,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
@@ -491,24 +492,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);
@@ -540,6 +523,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;
@@ -598,8 +609,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) {
@@ -618,7 +645,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
@@ -636,6 +665,9 @@
              */
             die_now = 1;
         }
+
+        /** Unlock socket, if needed.  No need to lock this */
+        lr->active = 1;
     }
     clean_child_exit(0);
 }
Index: server/mpm/worker/worker.c
===================================================================
--- server/mpm/worker/worker.c  (revision 565699)
+++ server/mpm/worker/worker.c  (working copy)
@@ -737,7 +737,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);
 
@@ -2340,3 +2342,4 @@
     worker_hooks                /* register_hooks */
 };
 
+
Index: server/mpm_common.c
===================================================================
--- server/mpm_common.c (revision 565699)
+++ server/mpm_common.c (working copy)
@@ -480,6 +480,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) {
@@ -643,6 +650,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);
@@ -651,7 +665,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");

Index: include/apr_network_io.h
===================================================================
--- include/apr_network_io.h    (revision 572605)
+++ include/apr_network_io.h    (working copy)
@@ -508,6 +508,33 @@
                                             apr_size_t *len);
 
 /**
+ * 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);
+
+/**
  * Read data from a socket.  On success, the address of the peer from
  * which the data was sent is copied into the @param from parameter,
  * and the @param len parameter is updated to give the number of bytes
 
Index: network_io/unix/sendrecv.c
===================================================================
--- network_io/unix/sendrecv.c  (revision 572605)
+++ network_io/unix/sendrecv.c  (working copy)
@@ -184,7 +184,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

Reply via email to