1 |
/* |
2 |
* Boa, an http server |
3 |
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com> |
4 |
* Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com> |
5 |
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org> |
6 |
* Some changes Copyright (C) 1996-2000 Jon Nelson <jnelson@boa.org> |
7 |
* |
8 |
* This program is free software; you can redistribute it and/or modify |
9 |
* it under the terms of the GNU General Public License as published by |
10 |
* the Free Software Foundation; either version 1, or (at your option) |
11 |
* any later version. |
12 |
* |
13 |
* This program is distributed in the hope that it will be useful, |
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
* GNU General Public License for more details. |
17 |
* |
18 |
* You should have received a copy of the GNU General Public License |
19 |
* along with this program; if not, write to the Free Software |
20 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 |
* |
22 |
*/ |
23 |
|
24 |
/* $Id: poll.c,v 1.2.2.2 2003/01/09 14:54:02 nmav Exp $*/ |
25 |
|
26 |
#include "boa.h" |
27 |
#include "loop_signals.h" |
28 |
|
29 |
#ifdef USE_POLL |
30 |
|
31 |
int pending_requests; |
32 |
|
33 |
void update_blocked(server_params* params, struct pollfd pfd1[]); |
34 |
|
35 |
void* select_loop(void* _params) |
36 |
{ |
37 |
server_params* params = _params; |
38 |
struct pollfd pfd1[2][MAX_FD]; |
39 |
short which = 0, other = 1, temp; |
40 |
int server_pfd = -1; |
41 |
int ssl_server_pfd = -1; |
42 |
|
43 |
params->pfds = pfd1[which]; |
44 |
params->pfd_len = 0; |
45 |
|
46 |
while (1) { |
47 |
int timeout; |
48 |
|
49 |
handle_signals( params); |
50 |
|
51 |
if (!params->sigterm_flag) { |
52 |
if (params->server_s[0].socket != -1) { |
53 |
server_pfd = params->pfd_len++; |
54 |
params->pfds[server_pfd].fd = params->server_s[0].socket; |
55 |
params->pfds[server_pfd].events = POLLIN | POLLPRI; |
56 |
} |
57 |
if (params->server_s[1].socket != -1) { |
58 |
ssl_server_pfd = params->pfd_len++; |
59 |
params->pfds[ssl_server_pfd].fd = params->server_s[1].socket; |
60 |
params->pfds[ssl_server_pfd].events = POLLIN | POLLPRI; |
61 |
} |
62 |
} |
63 |
|
64 |
/* If there are any requests ready, the timeout is 0. |
65 |
* If not, and there are any requests blocking, the |
66 |
* timeout is ka_timeout ? ka_timeout * 1000, otherwise |
67 |
* REQUEST_TIMEOUT * 1000. |
68 |
* -1 means forever |
69 |
*/ |
70 |
SET_TIMEOUT( timeout, 1000, -1); |
71 |
|
72 |
if (poll(params->pfds, params->pfd_len, timeout) == -1) { |
73 |
if (errno == EINTR) |
74 |
continue; /* while(1) */ |
75 |
} |
76 |
|
77 |
params->pfd_len = 0; |
78 |
if (!params->sigterm_flag) { |
79 |
if (params->pfds[server_pfd].revents & POLLIN) |
80 |
params->server_s[0].pending_requests = 1; |
81 |
if (params->pfds[ssl_server_pfd].revents & POLLIN) |
82 |
params->server_s[1].pending_requests = 1; |
83 |
} |
84 |
|
85 |
/* go through blocked and unblock them if possible */ |
86 |
/* also resets params->pfd_len and pfd to known blocked */ |
87 |
if (params->request_block) { |
88 |
update_blocked(params, pfd1[other]); |
89 |
} |
90 |
|
91 |
/* swap pfd */ |
92 |
params->pfds = pfd1[other]; |
93 |
temp = other; |
94 |
other = which; |
95 |
which = temp; |
96 |
|
97 |
/* process any active requests */ |
98 |
if (params->server_s[0].socket != -1) process_requests(params, ¶ms->server_s[0]); |
99 |
#ifdef ENABLE_SSL |
100 |
if (params->server_s[1].socket != -1) process_requests(params, ¶ms->server_s[1]); |
101 |
#endif |
102 |
} |
103 |
|
104 |
return NULL; |
105 |
} |
106 |
|
107 |
/* |
108 |
* Name: update_blocked |
109 |
* |
110 |
* Description: iterate through the blocked requests, checking whether |
111 |
* that file descriptor has been set by select. Update the fd_set to |
112 |
* reflect current status. |
113 |
* |
114 |
* Here, we need to do some things: |
115 |
* - keepalive timeouts simply close |
116 |
* (this is special:: a keepalive timeout is a timeout where |
117 |
* keepalive is active but nothing has been read yet) |
118 |
* - regular timeouts close + error |
119 |
* - stuff in buffer and fd ready? write it out |
120 |
* - fd ready for other actions? do them |
121 |
*/ |
122 |
|
123 |
void update_blocked(server_params* params, struct pollfd pfd1[]) |
124 |
{ |
125 |
request *current, *next = NULL; |
126 |
time_t time_since; |
127 |
|
128 |
for (current = params->request_block; current; current = next) { |
129 |
time_since = current_time - current->time_last; |
130 |
next = current->next; |
131 |
|
132 |
// FIXME:: the first below has the chance of leaking memory! |
133 |
// (setting status to DEAD not DONE....) |
134 |
/* hmm, what if we are in "the middle" of a request and not |
135 |
* just waiting for a new one... perhaps check to see if anything |
136 |
* has been read via header position, etc... */ |
137 |
if (current->kacount < ka_max && /* we *are* in a keepalive */ |
138 |
(time_since >= ka_timeout) && /* ka timeout has passsed */ |
139 |
!current->logline) { /* haven't read anything yet */ |
140 |
current->status = DEAD; /* connection keepalive timed out */ |
141 |
ready_request( params, current); |
142 |
continue; |
143 |
} else if (time_since > REQUEST_TIMEOUT) { |
144 |
log_error_doc(current); |
145 |
fprintf(stderr, "connection timed out (%d secs)\n", (int)time_since); |
146 |
current->status = DEAD; |
147 |
ready_request( params, current); |
148 |
continue; |
149 |
} |
150 |
|
151 |
if (params->pfds[current->pollfd_id].revents) { |
152 |
ready_request( params, current); |
153 |
} else { /* still blocked */ |
154 |
pfd1[params->pfd_len].fd = params->pfds[current->pollfd_id].fd; |
155 |
pfd1[params->pfd_len].events = params->pfds[current->pollfd_id].events; |
156 |
current->pollfd_id = params->pfd_len++; |
157 |
} |
158 |
} |
159 |
} |
160 |
|
161 |
#endif /* USE_POLL */ |