--- build-tree-apache.orig/apache_1.3.34/src/include/ap_config.h 2008-10-02 06:51:14.000000000 -0500 +++ build-tree-apache/apache_1.3.34/src/include/ap_config.h 2008-10-02 06:17:54.000000000 -0500 @@ -963,6 +963,7 @@ #include #include #include +#include #define NET_SIZE_T size_t #define NEED_HASHBANG_EMUL #define NONBLOCK_WHEN_MULTI_LISTEN @@ -1086,6 +1087,7 @@ #endif #if !defined(WIN32) && !defined(NETWARE) #include +#include #ifdef HAVE_SYS_SELECT_H #include #endif /* HAVE_SYS_SELECT_H */ --- build-tree-apache.orig/apache_1.3.34/src/include/httpd.h 2008-10-02 06:51:15.000000000 -0500 +++ build-tree-apache/apache_1.3.34/src/include/httpd.h 2008-10-02 06:18:32.000000000 -0500 @@ -974,9 +974,21 @@ }; /* These are more like real hosts than virtual hosts */ +enum listen_addr_type { + LISTEN_ADDR_INET, + LISTEN_ADDR_UNIX +}; + struct listen_rec { listen_rec *next; - struct sockaddr_in local_addr; /* local IP address and port */ + + union { + struct sockaddr_in in; /* INET local IP address and port */ + struct sockaddr_un un; /* UNIX domain socket path */ + } local_addr; + + enum listen_addr_type addr_type; + int fd; int used; /* Only used during restart */ /* more stuff here, like which protocol is bound to the port */ --- build-tree-apache.orig/apache_1.3.34/src/main/http_config.c 2008-10-02 06:51:15.000000000 -0500 +++ build-tree-apache/apache_1.3.34/src/main/http_config.c 2008-10-02 05:25:48.000000000 -0500 @@ -1636,10 +1636,11 @@ } /* allocate a default listener */ new = ap_pcalloc(p, sizeof(listen_rec)); - new->local_addr.sin_family = AF_INET; - new->local_addr.sin_addr = ap_bind_address; + new->addr_type = LISTEN_ADDR_INET; + new->local_addr.in.sin_family = AF_INET; + new->local_addr.in.sin_addr = ap_bind_address; /* Buck ugly cast to get around terniary op bug in some (MS) compilers */ - new->local_addr.sin_port = htons((unsigned short)(s->port ? s->port + new->local_addr.in.sin_port = htons((unsigned short)(s->port ? s->port : DEFAULT_HTTP_PORT)); new->fd = -1; new->used = 0; --- build-tree-apache.orig/apache_1.3.34/src/main/http_core.c 2008-10-02 06:51:15.000000000 -0500 +++ build-tree-apache/apache_1.3.34/src/main/http_core.c 2008-10-02 05:30:58.000000000 -0500 @@ -2697,37 +2697,51 @@ return err; } - ports = strchr(ips, ':'); - if (ports != NULL) { - if (ports == ips) { - return "Missing IP address"; - } - else if (ports[1] == '\0') { - return "Address must end in :"; - } - *(ports++) = '\0'; - } - else { - ports = ips; - } + if(ips[0] == '/') { + /* UNIX domain socket listener */ - new=ap_pcalloc(cmd->pool, sizeof(listen_rec)); - new->local_addr.sin_family = AF_INET; - if (ports == ips) { /* no address */ - new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - } - else { - new->local_addr.sin_addr.s_addr = ap_get_virthost_addr(ips, NULL); - } - errno = 0; /* clear errno before calling strtol */ - port = ap_strtol(ports, &endptr, 10); - if (errno /* some sort of error */ - || (endptr && *endptr) /* make sure no trailing characters */ - || port < 1 || port > 65535) /* underflow/overflow */ - { - return "Missing, invalid, or non-numeric port"; + new=ap_pcalloc(cmd->pool, sizeof(listen_rec)); + new->addr_type = LISTEN_ADDR_UNIX; + new->local_addr.un.sun_family = AF_LOCAL; + ap_snprintf(new->local_addr.un.sun_path, sizeof new->local_addr.un.sun_path, "%s", ips); + + } else { + /* TCP listener address */ + + ports = strchr(ips, ':'); + if (ports != NULL) { + if (ports == ips) { + return "Missing IP address"; + } + else if (ports[1] == '\0') { + return "Address must end in :"; + } + *(ports++) = '\0'; + } + else { + ports = ips; + } + + new=ap_pcalloc(cmd->pool, sizeof(listen_rec)); + new->addr_type = LISTEN_ADDR_INET; + new->local_addr.in.sin_family = AF_INET; + if (ports == ips) { /* no address */ + new->local_addr.in.sin_addr.s_addr = htonl(INADDR_ANY); + } + else { + new->local_addr.in.sin_addr.s_addr = ap_get_virthost_addr(ips, NULL); + } + errno = 0; /* clear errno before calling strtol */ + port = ap_strtol(ports, &endptr, 10); + if (errno /* some sort of error */ + || (endptr && *endptr) /* make sure no trailing characters */ + || port < 1 || port > 65535) /* underflow/overflow */ + { + return "Missing, invalid, or non-numeric port"; + } + new->local_addr.in.sin_port = htons((unsigned short)port); } - new->local_addr.sin_port = htons((unsigned short)port); + new->fd = -1; new->used = 0; new->next = ap_listeners; --- build-tree-apache.orig/apache_1.3.34/src/main/http_main.c 2008-10-02 06:51:15.000000000 -0500 +++ build-tree-apache/apache_1.3.34/src/main/http_main.c 2008-10-02 06:47:11.000000000 -0500 @@ -3793,7 +3793,8 @@ #define sock_disable_nagle(s, c) /* NOOP */ #endif -static int make_sock(pool *p, const struct sockaddr_in *server) + +static int make_sock_in(pool *p, const struct sockaddr_in *server) { int s; int one = 1; @@ -3809,7 +3810,7 @@ ap_block_alarms(); if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, - "make_sock: failed to get a socket for %s", addr); + "make_sock_in: failed to get a socket for %s", addr); ap_unblock_alarms(); exit(1); @@ -3848,7 +3849,7 @@ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) { #ifndef _OSD_POSIX ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, - "make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr); + "make_sock_in: for %s, setsockopt: (SO_REUSEADDR)", addr); closesocket(s); ap_unblock_alarms(); exit(1); @@ -3858,7 +3859,7 @@ #if defined(SO_KEEPALIVE) && !defined(MPE) if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(int)) < 0) { ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, - "make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr); + "make_sock_in: for %s, setsockopt: (SO_KEEPALIVE)", addr); closesocket(s); ap_unblock_alarms(); @@ -3893,7 +3894,7 @@ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *) &server_conf->send_buffer_size, sizeof(int)) < 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, - "make_sock: failed to set SendBufferSize for %s, " + "make_sock_in: failed to set SendBufferSize for %s, " "using default", addr); /* not a fatal error */ } @@ -3908,7 +3909,7 @@ if (bind(s, (struct sockaddr *) server, sizeof(struct sockaddr_in)) == -1) { ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, - "make_sock: could not bind to %s", addr); + "make_sock_in: could not bind to %s", addr); #ifdef MPE if (ntohs(server->sin_port) < 1024) GETUSERMODE(); @@ -3925,7 +3926,7 @@ if (listen(s, ap_listenbacklog) == -1) { ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "make_sock: unable to listen for connections on %s", addr); + "make_sock_in: unable to listen for connections on %s", addr); closesocket(s); ap_unblock_alarms(); exit(1); @@ -3955,7 +3956,7 @@ "socket option SO_ACCEPTFILTER unkown on this machine. Continuing."); } else { ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_INFO, server_conf, - "make_sock: for %s, setsockopt: (SO_ACCEPTFILTER)", addr); + "make_sock_in: for %s, setsockopt: (SO_ACCEPTFILTER)", addr); } } } @@ -3972,7 +3973,7 @@ /* protect various fd_sets */ if (s >= FD_SETSIZE) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL, - "make_sock: problem listening on %s, filedescriptor (%u) " + "make_sock_in: problem listening on %s, filedescriptor (%u) " "larger than FD_SETSIZE (%u) " "found, you probably need to rebuild Apache with a " "larger FD_SETSIZE", addr, s, FD_SETSIZE); @@ -3985,6 +3986,103 @@ } +/* based loosely on make_sock_in() above which was originally make_sock() */ +/* note that we don't try to do all the socket tuning that make_sock_in() + * does, because that has to be done by the real listener (httpx) */ +static int make_sock_un(pool *p, const struct sockaddr_un *server) +{ + int s; + char addr[512]; + mode_t oldmask; + + ap_snprintf(addr, sizeof(addr), "UNIX path: %s", server->sun_path); + + ap_block_alarms(); + if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) { + ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, + "make_sock_un: failed to get a socket for %s", addr); + + ap_unblock_alarms(); + exit(1); + } + + /* Solaris (probably versions 2.4, 2.5, and 2.5.1 with various levels + * of tcp patches) has some really weird bugs where if you dup the + * socket now it breaks things across SIGHUP restarts. It'll either + * be unable to bind, or it won't respond. + */ +#if defined (SOLARIS2) && SOLARIS2 < 260 +#define WORKAROUND_SOLARIS_BUG +#endif + + /* PR#1282 Unixware 1.x appears to have the same problem as solaris */ +#if defined (UW) && UW < 200 +#define WORKAROUND_SOLARIS_BUG +#endif + + /* PR#1973 NCR SVR4 systems appear to have the same problem */ +#if defined (MPRAS) +#define WORKAROUND_SOLARIS_BUG +#endif + +#ifndef WORKAROUND_SOLARIS_BUG +#ifndef BEOS /* this won't work for BeOS sockets!! */ + s = ap_slack(s, AP_SLACK_HIGH); +#endif + + ap_note_cleanups_for_socket_ex(p, s, 1); /* arrange to close on exec or restart */ +#ifdef TPF + os_note_additional_cleanups(p, s); +#endif /* TPF */ +#endif + + unlink(server->sun_path); + + oldmask = umask(S_IROTH); /* make sure socket is writable by other */ + if (bind(s, (struct sockaddr *) server, sizeof(struct sockaddr_un)) == -1) { + ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, + "make_sock_un: could not bind to %s", addr); + + umask(oldmask); + closesocket(s); + ap_unblock_alarms(); + exit(1); + } + umask(oldmask); + + if (listen(s, ap_listenbacklog) == -1) { + ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, + "make_sock_in: unable to listen for connections on %s", addr); + closesocket(s); + ap_unblock_alarms(); + exit(1); + } + +#ifdef WORKAROUND_SOLARIS_BUG + s = ap_slack(s, AP_SLACK_HIGH); + + ap_note_cleanups_for_socket_ex(p, s, 1); /* arrange to close on exec or restart */ +#endif + ap_unblock_alarms(); + +#ifdef CHECK_FD_SETSIZE + /* protect various fd_sets */ + if (s >= FD_SETSIZE) { + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL, + "make_sock_in: problem listening on %s, filedescriptor (%u) " + "larger than FD_SETSIZE (%u) " + "found, you probably need to rebuild Apache with a " + "larger FD_SETSIZE", addr, s, FD_SETSIZE); + closesocket(s); + exit(1); + } +#endif + + return s; +} + + + /* * During a restart we keep track of the old listeners here, so that we * can re-use the sockets. We have to do this because we won't be able @@ -4134,7 +4228,19 @@ for (;;) { fd = find_listener(lr); if (fd < 0) { - fd = make_sock(p, &lr->local_addr); + switch(lr->addr_type) { + case LISTEN_ADDR_INET: + fd = make_sock_in(p, &lr->local_addr.in); + break; + + case LISTEN_ADDR_UNIX: + fd = make_sock_un(p, &lr->local_addr.un); + break; + + default: + /* impossible */ + break; + } } else { ap_note_cleanups_for_socket_ex(p, fd, 1); @@ -4494,7 +4600,7 @@ NET_SIZE_T clen; struct sockaddr sa_server; struct sockaddr sa_client; - listen_rec *lr; + listen_rec *lr = ap_listeners; /* All of initialization is a critical section, we don't care if we're * told to HUP or USR1 before we're done initializing. For example, @@ -4691,8 +4797,62 @@ } } - if (csd >= 0) + if (csd >= 0) { + if(lr->addr_type == LISTEN_ADDR_UNIX) { + /* if this listener is a unix domain socket, we need to + * receive the passed socket descriptor. */ + struct msghdr msg; + struct iovec iov[1]; + ssize_t n; + char b; + + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(int))]; + } control_un; + struct cmsghdr *cmptr; + + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); + msg.msg_name = NULL; + msg.msg_namelen = 0; + iov[0].iov_base = &b; + iov[0].iov_len = 1; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + n = recvmsg(csd, &msg, 0); + if(n <= 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, + "accept UNIX: giving up."); + clean_child_exit(APEXIT_CHILDFATAL); + } + + if((cmptr = CMSG_FIRSTHDR(&msg)) != NULL && + cmptr->cmsg_len == CMSG_LEN(sizeof(int))) { + if(cmptr->cmsg_level != SOL_SOCKET) { + ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, + "accept UNIX: giving up."); + clean_child_exit(APEXIT_CHILDFATAL); + } + if(cmptr->cmsg_type != SCM_RIGHTS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, + "accept UNIX: giving up."); + clean_child_exit(APEXIT_CHILDFATAL); + } + close(csd); + csd = *((int *)CMSG_DATA(cmptr)); + clen = sizeof(sa_client); + getpeername(csd, &sa_client, &clen); + } else { + ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, + "accept UNIX: giving up."); + clean_child_exit(APEXIT_CHILDFATAL); + } + } + break; /* We have a socket ready for reading */ + } else { /* Our old behaviour here was to continue after accept() @@ -6620,8 +6780,20 @@ printf(" Listening on port(s):"); lr = ap_listeners; do { - printf(" %d", ntohs(lr->local_addr.sin_port)); - lr = lr->next; + switch(lr->addr_type) { + case LISTEN_ADDR_INET: + printf(" %d", ntohs(lr->local_addr.in.sin_port)); + break; + + case LISTEN_ADDR_INET: + printf(" %s", lr->local_addr.un.sun_path); + break; + + default: + /* impossible */ + break; + } + lr = lr->next; } while(lr && lr != ap_listeners); /* Display dynamic modules loaded */