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.