summaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
authorRyan Bloom <rbb@apache.org>2001-11-13 23:42:38 +0100
committerRyan Bloom <rbb@apache.org>2001-11-13 23:42:38 +0100
commit91aa6046003482482ff7028ca3ca9b62cdcdf1aa (patch)
tree7d1fe5c342be91bcc04b8c2cc59a31832caeb50c /os
parentUpdated NetWare project file. Now builds many of the external modules (diff)
downloadapache2-91aa6046003482482ff7028ca3ca9b62cdcdf1aa.tar.xz
apache2-91aa6046003482482ff7028ca3ca9b62cdcdf1aa.zip
Allow modules that add sockets to the ap_listeners list to
define the function that should be used to accept on that socket. Each MPM can define their own function to use for the accept function with the MPM_ACCEPT_FUNC macro. This also abstracts out all of the Unix accept error handling logic, which has become out of synch across Unix MPMs. The code flow is much easier now for different transports: 1) During pre-config, post-config or while parsing the config file, add a socket to the ap_listeners list, making sure to define an accept function at the same time. 2) MPMs find the correct listener, and call the accept function that was defined in step 1. 3) That accept function returns a void pointer, which is passed to the create_connection hook. 4) create_connection adds the correct low-level filters. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@91916 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'os')
-rw-r--r--os/unix/unixd.c123
-rw-r--r--os/unix/unixd.h2
2 files changed, 125 insertions, 0 deletions
diff --git a/os/unix/unixd.c b/os/unix/unixd.c
index e705988191..673a1cfd9b 100644
--- a/os/unix/unixd.c
+++ b/os/unix/unixd.c
@@ -441,3 +441,126 @@ AP_DECLARE(apr_status_t) unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex)
return APR_SUCCESS;
}
+AP_DECLARE(apr_status_t) unixd_accept(void **accepted, ap_listen_rec *lr,
+ apr_pool_t *ptrans)
+{
+ apr_socket_t *csd;
+ apr_status_t status;
+ int sockdes;
+
+ status = apr_accept(&csd, lr->sd, ptrans);
+ if (status == APR_SUCCESS) {
+ *accepted = csd;
+ apr_os_sock_get(&sockdes, csd);
+ if (sockdes >= FD_SETSIZE) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL,
+ "new file descriptor %d is too large; you probably need "
+ "to rebuild Apache with a larger FD_SETSIZE "
+ "(currently %d)",
+ sockdes, FD_SETSIZE);
+ apr_socket_close(csd);
+ return APR_EINTR;
+ }
+#ifdef TPF
+ if (sockdes == 0) { /* 0 is invalid socket for TPF */
+ return APR_EINTR;
+ }
+#endif
+ return status;
+ }
+
+ if (APR_STATUS_IS_EINTR(status)) {
+ return status;
+ }
+ /* Our old behaviour here was to continue after accept()
+ * errors. But this leads us into lots of troubles
+ * because most of the errors are quite fatal. For
+ * example, EMFILE can be caused by slow descriptor
+ * leaks (say in a 3rd party module, or libc). It's
+ * foolish for us to continue after an EMFILE. We also
+ * seem to tickle kernel bugs on some platforms which
+ * lead to never-ending loops here. So it seems best
+ * to just exit in most cases.
+ */
+ switch (status) {
+#ifdef EPROTO
+ /* EPROTO on certain older kernels really means
+ * ECONNABORTED, so we need to ignore it for them.
+ * See discussion in new-httpd archives nh.9701
+ * search for EPROTO.
+ *
+ * Also see nh.9603, search for EPROTO:
+ * There is potentially a bug in Solaris 2.x x<6,
+ * and other boxes that implement tcp sockets in
+ * userland (i.e. on top of STREAMS). On these
+ * systems, EPROTO can actually result in a fatal
+ * loop. See PR#981 for example. It's hard to
+ * handle both uses of EPROTO.
+ */
+ case EPROTO:
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED:
+#endif
+ /* Linux generates the rest of these, other tcp
+ * stacks (i.e. bsd) tend to hide them behind
+ * getsockopt() interfaces. They occur when
+ * the net goes sour or the client disconnects
+ * after the three-way handshake has been done
+ * in the kernel but before userland has picked
+ * up the socket.
+ */
+#ifdef ECONNRESET
+ case ECONNRESET:
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT:
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH:
+#endif
+ break;
+#ifdef ENETDOWN
+ case ENETDOWN:
+ /*
+ * When the network layer has been shut down, there
+ * is not much use in simply exiting: the parent
+ * would simply re-create us (and we'd fail again).
+ * Use the CHILDFATAL code to tear the server down.
+ * @@@ Martin's idea for possible improvement:
+ * A different approach would be to define
+ * a new APEXIT_NETDOWN exit code, the reception
+ * of which would make the parent shutdown all
+ * children, then idle-loop until it detected that
+ * the network is up again, and restart the children.
+ * Ben Hyde noted that temporary ENETDOWN situations
+ * occur in mobile IP.
+ */
+ ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
+ "apr_accept: giving up.");
+ return APR_EGENERAL;
+#endif /*ENETDOWN*/
+
+#ifdef TPF
+ case EINACT:
+ ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
+ "offload device inactive");
+ return APR_EGENERAL;
+ break;
+ default:
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ap_server_conf,
+ "select/accept error (%d)", status);
+ return APR_EGENERAL;
+#else
+ default:
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf,
+ "apr_accept: (client socket)");
+ return APR_EGENERAL;
+#endif
+ }
+ return status;
+}
+
diff --git a/os/unix/unixd.h b/os/unix/unixd.h
index 35adbc147e..ef906feca4 100644
--- a/os/unix/unixd.h
+++ b/os/unix/unixd.h
@@ -61,6 +61,7 @@
#include "httpd.h"
#include "http_config.h"
+#include "ap_listen.h"
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -120,6 +121,7 @@ AP_DECLARE(void) unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit,
#endif
AP_DECLARE(apr_status_t) unixd_set_lock_perms(apr_lock_t *lock);
AP_DECLARE(apr_status_t) unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex);
+AP_DECLARE(apr_status_t) unixd_accept(void **accepted, ap_listen_rec *lr, apr_pool_t *ptrans);
#ifdef HAVE_KILLPG
#define unixd_killpg(x, y) (killpg ((x), (y)))