summaryrefslogtreecommitdiff
path: root/polux/application/boa/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'polux/application/boa/src/select.c')
-rw-r--r--polux/application/boa/src/select.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/polux/application/boa/src/select.c b/polux/application/boa/src/select.c
new file mode 100644
index 0000000000..cf3776f990
--- /dev/null
+++ b/polux/application/boa/src/select.c
@@ -0,0 +1,238 @@
+/*
+ * Boa, an http server
+ * Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
+ * Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com>
+ * Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
+ * Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* $Id: select.c,v 1.1.1.1 2006/06/16 09:48:03 fleury Exp $*/
+
+/* algorithm:
+ * handle any signals
+ * if we still want to accept new connections, add the server to the
+ * list.
+ * if there are any blocked requests or the we are still accepting new
+ * connections, determine appropriate timeout and select, then move
+ * blocked requests back into the active list.
+ * handle active connections
+ * repeat
+ */
+
+
+
+#include "boa.h"
+
+static void fdset_update(void);
+fd_set block_read_fdset;
+fd_set block_write_fdset;
+int max_fd = 0;
+
+void loop(int server_s)
+{
+ FD_ZERO(BOA_READ);
+ FD_ZERO(BOA_WRITE);
+
+ max_fd = -1;
+
+ while (1) {
+ /* handle signals here */
+ if (sighup_flag)
+ sighup_run();
+ if (sigchld_flag)
+ sigchld_run();
+ if (sigalrm_flag)
+ sigalrm_run();
+
+ if (sigterm_flag) {
+ /* sigterm_flag:
+ * 1. caught, unprocessed.
+ * 2. caught, stage 1 processed
+ */
+ if (sigterm_flag == 1) {
+ sigterm_stage1_run();
+ BOA_FD_CLR(req, server_s, BOA_READ);
+ close(server_s);
+ /* make sure the server isn't in the block list */
+ server_s = -1;
+ }
+ if (sigterm_flag == 2 && !request_ready && !request_block) {
+ sigterm_stage2_run(); /* terminal */
+ }
+ } else {
+ if (total_connections > max_connections) {
+ /* FIXME: for poll we don't subtract 20. why? */
+ BOA_FD_CLR(req, server_s, BOA_READ);
+ } else {
+ BOA_FD_SET(req, server_s, BOA_READ); /* server always set */
+ }
+ }
+
+ pending_requests = 0;
+ /* max_fd is > 0 when something is blocked */
+
+ if (max_fd) {
+ struct timeval req_timeout; /* timeval for select */
+
+ req_timeout.tv_sec = (request_ready ? 0 : default_timeout);
+ req_timeout.tv_usec = 0l; /* reset timeout */
+
+ if (select(max_fd + 1, BOA_READ,
+ BOA_WRITE, NULL,
+ (request_ready || request_block ?
+ &req_timeout : NULL)) == -1) {
+ /* what is the appropriate thing to do here on EBADF */
+ if (errno == EINTR)
+ continue; /* while(1) */
+ else if (errno != EBADF) {
+ DIE("select");
+ }
+ }
+ /* FIXME: optimize for when select returns 0 (timeout).
+ * Thus avoiding many operations in fdset_update
+ * and others.
+ */
+ if (!sigterm_flag && FD_ISSET(server_s, BOA_READ)) {
+ pending_requests = 1;
+ }
+ time(&current_time); /* for "new" requests if we've been in
+ * select too long */
+ /* if we skip this section (for example, if max_fd == 0),
+ * then we aren't listening anyway, so we can't accept
+ * new conns. Don't worry about it.
+ */
+ }
+
+ /* reset max_fd */
+ max_fd = -1;
+
+ if (request_block) {
+ /* move selected req's from request_block to request_ready */
+ fdset_update();
+ }
+
+ /* any blocked req's move from request_ready to request_block */
+ if (pending_requests || request_ready) {
+ process_requests(server_s);
+ }
+ }
+}
+
+/*
+ * Name: fdset_update
+ *
+ * Description: iterate through the blocked requests, checking whether
+ * that file descriptor has been set by select. Update the fd_set to
+ * reflect current status.
+ *
+ * Here, we need to do some things:
+ * - keepalive timeouts simply close
+ * (this is special:: a keepalive timeout is a timeout where
+ keepalive is active but nothing has been read yet)
+ * - regular timeouts close + error
+ * - stuff in buffer and fd ready? write it out
+ * - fd ready for other actions? do them
+ */
+
+static void fdset_update(void)
+{
+ request *current, *next;
+
+ time(&current_time);
+ for (current = request_block; current; current = next) {
+ time_t time_since = current_time - current->time_last;
+ next = current->next;
+
+ /* hmm, what if we are in "the middle" of a request and not
+ * just waiting for a new one... perhaps check to see if anything
+ * has been read via header position, etc... */
+ if (current->kacount < ka_max && /* we *are* in a keepalive */
+ (time_since >= ka_timeout) && /* ka timeout */
+ !current->logline) { /* haven't read anything yet */
+ log_error_doc(current);
+ fputs("connection timed out\n", stderr);
+ current->status = TIMED_OUT; /* connection timed out */
+ } else if (time_since > REQUEST_TIMEOUT) {
+ log_error_doc(current);
+ fputs("connection timed out\n", stderr);
+ current->status = TIMED_OUT; /* connection timed out */
+ }
+ if (current->buffer_end && /* there is data to write */
+ current->status < DONE) {
+ if (FD_ISSET(current->fd, BOA_WRITE))
+ ready_request(current);
+ else {
+ BOA_FD_SET(current, current->fd, BOA_WRITE);
+ }
+ } else {
+ switch (current->status) {
+ case IOSHUFFLE:
+#ifndef HAVE_SENDFILE
+ if (current->buffer_end - current->buffer_start == 0) {
+ if (FD_ISSET(current->data_fd, BOA_READ))
+ ready_request(current);
+ break;
+ }
+#endif
+ case WRITE:
+ case PIPE_WRITE:
+ if (FD_ISSET(current->fd, BOA_WRITE))
+ ready_request(current);
+ else {
+ BOA_FD_SET(current, current->fd, BOA_WRITE);
+ }
+ break;
+ case BODY_WRITE:
+ if (FD_ISSET(current->post_data_fd, BOA_WRITE))
+ ready_request(current);
+ else {
+ BOA_FD_SET(current, current->post_data_fd,
+ BOA_WRITE);
+ }
+ break;
+ case PIPE_READ:
+ if (FD_ISSET(current->data_fd, BOA_READ))
+ ready_request(current);
+ else {
+ BOA_FD_SET(current, current->data_fd,
+ BOA_READ);
+ }
+ break;
+ case DONE:
+ if (FD_ISSET(current->fd, BOA_WRITE))
+ ready_request(current);
+ else {
+ BOA_FD_SET(current, current->fd, BOA_WRITE);
+ }
+ break;
+ case TIMED_OUT:
+ case DEAD:
+ ready_request(current);
+ break;
+ default:
+ if (FD_ISSET(current->fd, BOA_READ))
+ ready_request(current);
+ else {
+ BOA_FD_SET(current, current->fd, BOA_READ);
+ }
+ break;
+ }
+ }
+ current = next;
+ }
+}