1 |
nmav |
1.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 |
nmav |
1.2 |
/* $Id: poll.c,v 1.1 2002/10/21 18:46:26 nmav Exp $*/ |
25 |
nmav |
1.1 |
|
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 |
nmav |
1.2 |
void* select_loop(void* _params) |
36 |
nmav |
1.1 |
{ |
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 |
nmav |
1.2 |
int ssl_server_pfd = -1; |
42 |
nmav |
1.1 |
|
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 |
nmav |
1.2 |
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 |
nmav |
1.1 |
} |
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 |
|
|
timeout = (params->request_ready ? 0 : |
71 |
|
|
(params->request_block ? |
72 |
|
|
(ka_timeout ? ka_timeout * 1000 : |
73 |
|
|
REQUEST_TIMEOUT * 1000) : -1)); |
74 |
|
|
|
75 |
|
|
if (poll(params->pfds, params->pfd_len, timeout) == -1) { |
76 |
|
|
if (errno == EINTR) |
77 |
|
|
continue; /* while(1) */ |
78 |
|
|
} |
79 |
|
|
|
80 |
|
|
params->pfd_len = 0; |
81 |
nmav |
1.2 |
if (!params->sigterm_flag) { |
82 |
|
|
if (params->pfds[server_pfd].revents & POLLIN) |
83 |
|
|
params->server_s[0].pending_requests = 1; |
84 |
|
|
if (params->pfds[ssl_server_pfd].revents & POLLIN) |
85 |
|
|
params->server_s[1].pending_requests = 1; |
86 |
nmav |
1.1 |
} |
87 |
|
|
|
88 |
|
|
/* go through blocked and unblock them if possible */ |
89 |
|
|
/* also resets params->pfd_len and pfd to known blocked */ |
90 |
nmav |
1.2 |
if (params->request_block) { |
91 |
nmav |
1.1 |
update_blocked(params, pfd1[other]); |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
/* swap pfd */ |
95 |
|
|
params->pfds = pfd1[other]; |
96 |
|
|
temp = other; |
97 |
|
|
other = which; |
98 |
|
|
which = temp; |
99 |
|
|
|
100 |
|
|
/* process any active requests */ |
101 |
|
|
if (params->server_s[0].socket != -1) process_requests(params, ¶ms->server_s[0]); |
102 |
|
|
#ifdef ENABLE_SSL |
103 |
|
|
if (params->server_s[1].socket != -1) process_requests(params, ¶ms->server_s[1]); |
104 |
|
|
#endif |
105 |
|
|
} |
106 |
|
|
} |
107 |
|
|
|
108 |
|
|
/* |
109 |
|
|
* Name: update_blocked |
110 |
|
|
* |
111 |
|
|
* Description: iterate through the blocked requests, checking whether |
112 |
|
|
* that file descriptor has been set by select. Update the fd_set to |
113 |
|
|
* reflect current status. |
114 |
|
|
* |
115 |
|
|
* Here, we need to do some things: |
116 |
|
|
* - keepalive timeouts simply close |
117 |
|
|
* (this is special:: a keepalive timeout is a timeout where |
118 |
|
|
* keepalive is active but nothing has been read yet) |
119 |
|
|
* - regular timeouts close + error |
120 |
|
|
* - stuff in buffer and fd ready? write it out |
121 |
|
|
* - fd ready for other actions? do them |
122 |
|
|
*/ |
123 |
|
|
|
124 |
|
|
void update_blocked(server_params* params, struct pollfd pfd1[]) |
125 |
|
|
{ |
126 |
|
|
request *current, *next = NULL; |
127 |
|
|
time_t time_since; |
128 |
|
|
|
129 |
nmav |
1.2 |
for (current = params->request_block; current; current = next) { |
130 |
nmav |
1.1 |
time_since = current_time - current->time_last; |
131 |
|
|
next = current->next; |
132 |
|
|
|
133 |
|
|
// FIXME:: the first below has the chance of leaking memory! |
134 |
|
|
// (setting status to DEAD not DONE....) |
135 |
|
|
/* hmm, what if we are in "the middle" of a request and not |
136 |
|
|
* just waiting for a new one... perhaps check to see if anything |
137 |
|
|
* has been read via header position, etc... */ |
138 |
|
|
if (current->kacount < ka_max && /* we *are* in a keepalive */ |
139 |
|
|
(time_since >= ka_timeout) && /* ka timeout has passsed */ |
140 |
|
|
!current->logline) { /* haven't read anything yet */ |
141 |
|
|
current->status = DEAD; /* connection keepalive timed out */ |
142 |
|
|
ready_request( params, current); |
143 |
|
|
continue; |
144 |
|
|
} else if (time_since > REQUEST_TIMEOUT) { |
145 |
|
|
log_error_doc(current); |
146 |
|
|
fputs("connection timed out\n", stderr); |
147 |
|
|
current->status = DEAD; |
148 |
|
|
ready_request( params, current); |
149 |
|
|
continue; |
150 |
|
|
} |
151 |
|
|
|
152 |
|
|
if (params->pfds[current->pollfd_id].revents) { |
153 |
|
|
ready_request( params, current); |
154 |
|
|
} else { /* still blocked */ |
155 |
|
|
pfd1[params->pfd_len].fd = params->pfds[current->pollfd_id].fd; |
156 |
|
|
pfd1[params->pfd_len].events = params->pfds[current->pollfd_id].events; |
157 |
|
|
current->pollfd_id = params->pfd_len++; |
158 |
|
|
} |
159 |
|
|
} |
160 |
|
|
} |
161 |
|
|
|
162 |
|
|
#endif /* USE_POLL */ |