dgaudet 98/02/14 04:17:30
Modified: src CHANGES
src/main http_main.c
Log:
Deal gracefully with unexpected accept() and select() errors in the
child_main() loop. This was built based on data from a bunch of PRs,
and data from the new-httpd archives, nh.9603 and nh.9701 in particular.
I've actually been running with the extra errno tests for linux for
the past 6 or 7 months. Without them there is a LOT of spam in the
error log on a linux box, compared to none on a solaris box on the
same segment.
PR: 1747, 1107, 588, 1787
Revision Changes Path
1.631 +7 -0 apache-1.3/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/CHANGES,v
retrieving revision 1.630
retrieving revision 1.631
diff -u -r1.630 -r1.631
--- CHANGES 1998/02/14 10:54:39 1.630
+++ CHANGES 1998/02/14 12:17:26 1.631
@@ -1,5 +1,12 @@
Changes with Apache 1.3b6
+ *) Various errors from select() and accept() in child_main() would
+ result in an infinite loop. It seems these two tickle kernel
+ or library bugs occasionally, and result in log spammage and
+ a generally bad scene. Now the child exits immediately,
+ which seems to be a good workaround.
+ [Dean Gaudet] PR#1747, 1107, 588, 1787
+
*) Cleaned up some race conditions in unix child_main during
initialization. [Dean Gaudet]
1.289 +62 -15 apache-1.3/src/main/http_main.c
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/http_main.c,v
retrieving revision 1.288
retrieving revision 1.289
diff -u -r1.288 -r1.289
--- http_main.c 1998/02/14 10:54:41 1.288
+++ http_main.c 1998/02/14 12:17:28 1.289
@@ -3032,14 +3032,14 @@
srv = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, NULL);
if (srv < 0 && errno != EINTR) {
-#ifdef LINUX
- if (errno == EFAULT) {
- aplog_error(APLOG_MARK, APLOG_ERR, server_conf,
- "select: (listen) fatal, child exiting");
- clean_child_exit(1);
- }
-#endif
+ /* Single Unix documents select as returning errnos
+ * EBADF, EINTR, and EINVAL... and in none of those
+ * cases does it make sense to continue. In fact
+ * on Linux 2.0.x we seem to end up with EFAULT
+ * occasionally, and we'd loop forever due to it.
+ */
aplog_error(APLOG_MARK, APLOG_ERR, server_conf, "select:
(listen)");
+ clean_child_exit(1);
}
if (srv <= 0)
@@ -3075,15 +3075,62 @@
break; /* We have a socket ready for reading */
else {
-#if defined(EPROTO) && defined(ECONNABORTED)
- if ((errno != EPROTO) && (errno != ECONNABORTED))
-#elif defined(EPROTO)
- if (errno != EPROTO)
-#elif defined(ECONNABORTED)
- if (errno != ECONNABORTED)
+ /* 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 (errno) {
+#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. But we don't deal with that.
+ */
+ 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
- aplog_error(APLOG_MARK, APLOG_ERR, server_conf,
- "accept: (client socket)");
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH:
+#endif
+ break;
+
+ default:
+ aplog_error(APLOG_MARK, APLOG_ERR, server_conf,
+ "accept: (client socket)");
+ clean_child_exit(1);
+ }
}
/* go around again, safe to die */