]>
Commit | Line | Data |
---|---|---|
cdd4e85e ER |
1 | diff -rp -U 5 libevent-1.4.14-stable/event.c libevent-1.4.14-stable-fb/event.c |
2 | --- libevent-1.4.14-stable/event.c 2010-06-07 14:40:35.000000000 -0700 | |
3 | +++ libevent-1.4.14-stable-fb/event.c 2010-06-18 16:30:57.000000000 -0700 | |
4 | @@ -136,14 +136,16 @@ detect_monotonic(void) | |
5 | } | |
6 | ||
7 | static int | |
8 | gettime(struct event_base *base, struct timeval *tp) | |
9 | { | |
10 | +/* | |
11 | if (base->tv_cache.tv_sec) { | |
12 | *tp = base->tv_cache; | |
13 | return (0); | |
14 | } | |
15 | +*/ | |
16 | ||
17 | #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) | |
18 | if (use_monotonic) { | |
19 | struct timespec ts; | |
20 | ||
21 | @@ -479,11 +481,11 @@ event_base_loop(struct event_base *base, | |
22 | struct timeval tv; | |
23 | struct timeval *tv_p; | |
24 | int res, done; | |
25 | ||
26 | /* clear time cache */ | |
27 | - base->tv_cache.tv_sec = 0; | |
28 | + /* base->tv_cache.tv_sec = 0; */ | |
29 | ||
30 | if (base->sig.ev_signal_added) | |
31 | evsignal_base = base; | |
32 | done = 0; | |
33 | while (!done) { | |
34 | @@ -531,17 +533,17 @@ event_base_loop(struct event_base *base, | |
35 | ||
36 | /* update last old time */ | |
37 | gettime(base, &base->event_tv); | |
38 | ||
39 | /* clear time cache */ | |
40 | - base->tv_cache.tv_sec = 0; | |
41 | + /* base->tv_cache.tv_sec = 0; */ | |
42 | ||
43 | res = evsel->dispatch(base, evbase, tv_p); | |
44 | ||
45 | if (res == -1) | |
46 | return (-1); | |
47 | - gettime(base, &base->tv_cache); | |
48 | + /* gettime(base, &base->tv_cache); */ | |
49 | ||
50 | timeout_process(base); | |
51 | ||
52 | if (base->event_count_active) { | |
53 | event_process_active(base); | |
54 | @@ -550,11 +552,11 @@ event_base_loop(struct event_base *base, | |
55 | } else if (flags & EVLOOP_NONBLOCK) | |
56 | done = 1; | |
57 | } | |
58 | ||
59 | /* clear time cache */ | |
60 | - base->tv_cache.tv_sec = 0; | |
61 | + /* base->tv_cache.tv_sec = 0; */ | |
62 | ||
63 | event_debug(("%s: asked to terminate loop.", __func__)); | |
64 | return (0); | |
65 | } | |
66 | ||
67 | Only in libevent-1.4.14-stable-fb: event.c.orig | |
68 | diff -rp -U 5 libevent-1.4.14-stable/evhttp.h libevent-1.4.14-stable-fb/evhttp.h | |
69 | --- libevent-1.4.14-stable/evhttp.h 2010-06-07 14:40:35.000000000 -0700 | |
70 | +++ libevent-1.4.14-stable-fb/evhttp.h 2010-06-18 16:36:24.000000000 -0700 | |
71 | @@ -79,16 +79,54 @@ struct evhttp *evhttp_new(struct event_b | |
72 | * to multiple different ports. | |
73 | * | |
74 | * @param http a pointer to an evhttp object | |
75 | * @param address a string containing the IP address to listen(2) on | |
76 | * @param port the port number to listen on | |
77 | - * @return a newly allocated evhttp struct | |
78 | + * @return 0 on success, -1 on error | |
79 | * @see evhttp_free() | |
80 | */ | |
81 | int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port); | |
82 | ||
83 | /** | |
84 | + * Binds an HTTP server on the specified address and port, using backlog. | |
85 | + * | |
86 | + * Can be called multiple times to bind the same http server | |
87 | + * to multiple different ports. | |
88 | + * | |
89 | + * @param http a pointer to an evhttp object | |
90 | + * @param address a string containing the IP address to listen(2) on | |
91 | + * @param port the port number to listen on | |
92 | + * @param backlog the backlog value for listen(2) | |
93 | + * @return 0 on success, -1 on error | |
94 | + * @see evhttp_free() | |
95 | + */ | |
96 | +int evhttp_bind_socket_backlog(struct evhttp *http, const char *address, u_short port, int backlog); | |
97 | + | |
98 | +/** | |
99 | + * Like evhttp_bind_socket(), but returns the socket file descriptor. | |
100 | + * | |
101 | + * @param http a pointer to an evhttp object | |
102 | + * @param address a string containing the IP address to listen(2) on | |
103 | + * @param port the port number to listen on | |
104 | + * @return Socket file descriptor on success, -1 on failure | |
105 | + * @see evhttp_bind_socket() | |
106 | + */ | |
107 | +int evhttp_bind_socket_with_fd(struct evhttp *http, const char *address, u_short port); | |
108 | + | |
109 | +/** | |
110 | + * Like evhttp_bind_socket(), but returns the socket file descriptor. | |
111 | + * | |
112 | + * @param http a pointer to an evhttp object | |
113 | + * @param address a string containing the IP address to listen(2) on | |
114 | + * @param port the port number to listen on | |
115 | + * @param backlog the backlog value for listen(2) | |
116 | + * @return Socket file descriptor on success, -1 on failure | |
117 | + * @see evhttp_bind_socket() | |
118 | + */ | |
119 | +int evhttp_bind_socket_backlog_fd(struct evhttp *http, const char *address, u_short port, int backlog); | |
120 | + | |
121 | +/** | |
122 | * Makes an HTTP server accept connections on the specified socket | |
123 | * | |
124 | * This may be useful to create a socket and then fork multiple instances | |
125 | * of an http server, or when a socket has been communicated via file | |
126 | * descriptor passing in situations where an http servers does not have | |
127 | @@ -103,10 +141,25 @@ int evhttp_bind_socket(struct evhttp *ht | |
128 | * @see evhttp_free(), evhttp_bind_socket() | |
129 | */ | |
130 | int evhttp_accept_socket(struct evhttp *http, int fd); | |
131 | ||
132 | /** | |
133 | + * Makes an HTTP server stop accepting connections on the specified socket | |
134 | + * | |
135 | + * This may be useful when a socket has been sent via file descriptor passing | |
136 | + * and is no longer needed by the current process. | |
137 | + * | |
138 | + * This function does not close the socket. | |
139 | + * | |
140 | + * @param http a pointer to an evhttp object | |
141 | + * @param fd a socket fd that is currently accepting connections | |
142 | + * @return 0 on success, -1 on failure. | |
143 | + * @see evhttp_accept_socket() | |
144 | + */ | |
145 | +int evhttp_del_accept_socket(struct evhttp *http, int fd); | |
146 | + | |
147 | +/** | |
148 | * Free the previously created HTTP server. | |
149 | * | |
150 | * Works only if no requests are currently being served. | |
151 | * | |
152 | * @param http the evhttp server object to be freed | |
153 | @@ -132,10 +185,25 @@ void evhttp_set_gencb(struct evhttp *, | |
154 | * @param http an evhttp object | |
155 | * @param timeout_in_secs the timeout, in seconds | |
156 | */ | |
157 | void evhttp_set_timeout(struct evhttp *, int timeout_in_secs); | |
158 | ||
159 | +/** | |
160 | + * Limit the number of simultaneous connections via this http instance. | |
161 | + * | |
162 | + * @param http an evhttp object | |
163 | + * @param nlimit the maximum number of connections, zero is unlimited | |
164 | + */ | |
165 | +int evhttp_set_connection_limit(struct evhttp *http, int nlimit); | |
166 | + | |
167 | +/** | |
168 | + * Return the maximum number of connections allowed for this instance. | |
169 | + * | |
170 | + * @param http an evhttp object | |
171 | + */ | |
172 | +int evhttp_get_connection_limit(struct evhttp *http); | |
173 | + | |
174 | /* Request/Response functionality */ | |
175 | ||
176 | /** | |
177 | * Send an HTML error message to the client. | |
178 | * | |
179 | @@ -155,10 +223,23 @@ void evhttp_send_error(struct evhttp_req | |
180 | * @param databuf the body of the response | |
181 | */ | |
182 | void evhttp_send_reply(struct evhttp_request *req, int code, | |
183 | const char *reason, struct evbuffer *databuf); | |
184 | ||
185 | +/** | |
186 | + * Send an HTML reply synchronously as much as possible by calling _begin(). | |
187 | + * Great for a worker thread to send the reply immediately without queuing up | |
188 | + * events back to the loop. Call _end() to send the rest of the packet from | |
189 | + * event loop. | |
190 | + * | |
191 | + * When _begin() returns needs to be fed into _end() as the 1st parameter | |
192 | + * "nwritten". | |
193 | + */ | |
194 | +int evhttp_send_reply_sync_begin(struct evhttp_request *req, int code, | |
195 | + const char *reason, struct evbuffer *databuf); | |
196 | +void evhttp_send_reply_sync_end(int nwritten, struct evhttp_request *req); | |
197 | + | |
198 | /* Low-level response interface, for streaming/chunked replies */ | |
199 | void evhttp_send_reply_start(struct evhttp_request *, int, const char *); | |
200 | void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *); | |
201 | void evhttp_send_reply_end(struct evhttp_request *); | |
202 | ||
203 | @@ -208,10 +289,11 @@ struct { | |
204 | char *remote_host; | |
205 | u_short remote_port; | |
206 | ||
207 | enum evhttp_request_kind kind; | |
208 | enum evhttp_cmd_type type; | |
209 | + char *ext_method; /* webdav methods, for example */ | |
210 | ||
211 | char *uri; /* uri after HTTP request was parsed */ | |
212 | ||
213 | char major; /* HTTP Major number */ | |
214 | char minor; /* HTTP Minor number */ | |
215 | @@ -222,10 +304,12 @@ struct { | |
216 | struct evbuffer *input_buffer; /* read data */ | |
217 | ev_int64_t ntoread; | |
218 | int chunked:1, /* a chunked request */ | |
219 | userdone:1; /* the user has sent all data */ | |
220 | ||
221 | + int referenced; | |
222 | + | |
223 | struct evbuffer *output_buffer; /* outgoing post or data */ | |
224 | ||
225 | /* Callback */ | |
226 | void (*cb)(struct evhttp_request *, void *); | |
227 | void *cb_arg; | |
228 | diff -rp -U 5 libevent-1.4.14-stable/http-internal.h libevent-1.4.14-stable-fb/http-internal.h | |
229 | --- libevent-1.4.14-stable/http-internal.h 2010-06-07 14:40:35.000000000 -0700 | |
230 | +++ libevent-1.4.14-stable-fb/http-internal.h 2010-06-18 16:30:57.000000000 -0700 | |
231 | @@ -114,10 +114,13 @@ struct evhttp { | |
232 | TAILQ_HEAD(boundq, evhttp_bound_socket) sockets; | |
233 | ||
234 | TAILQ_HEAD(httpcbq, evhttp_cb) callbacks; | |
235 | struct evconq connections; | |
236 | ||
237 | + int connection_count; | |
238 | + int connection_limit; | |
239 | + | |
240 | int timeout; | |
241 | ||
242 | void (*gencb)(struct evhttp_request *req, void *); | |
243 | void *gencbarg; | |
244 | ||
245 | diff -rp -U 5 libevent-1.4.14-stable/http.c libevent-1.4.14-stable-fb/http.c | |
246 | --- libevent-1.4.14-stable/http.c 2010-06-07 14:40:35.000000000 -0700 | |
247 | +++ libevent-1.4.14-stable-fb/http.c 2010-06-18 16:35:23.000000000 -0700 | |
248 | @@ -217,10 +217,17 @@ static int evhttp_decode_uri_internal(co | |
249 | char *ret, int always_decode_plus); | |
250 | ||
251 | void evhttp_read(int, short, void *); | |
252 | void evhttp_write(int, short, void *); | |
253 | ||
254 | + | |
255 | +void evhttp_server_drop_connection(struct evhttp_connection *evcon); | |
256 | +void evhttp_server_add_connection(struct evhttp *http, | |
257 | + struct evhttp_connection *evcon); | |
258 | +void evhttp_pause(struct evhttp *http); | |
259 | +void evhttp_resume(struct evhttp *http); | |
260 | + | |
261 | #ifndef HAVE_STRSEP | |
262 | /* strsep replacement for platforms that lack it. Only works if | |
263 | * del is one character long. */ | |
264 | static char * | |
265 | strsep(char **s, const char *del) | |
266 | @@ -476,21 +483,19 @@ evhttp_make_header_response(struct evhtt | |
267 | */ | |
268 | if (req->minor == 0 && is_keepalive) | |
269 | evhttp_add_header(req->output_headers, | |
270 | "Connection", "keep-alive"); | |
271 | ||
272 | - if (req->minor == 1 || is_keepalive) { | |
273 | /* | |
274 | * we need to add the content length if the | |
275 | * user did not give it, this is required for | |
276 | * persistent connections to work. | |
277 | */ | |
278 | evhttp_maybe_add_content_length_header( | |
279 | req->output_headers, | |
280 | (long)EVBUFFER_LENGTH(req->output_buffer)); | |
281 | } | |
282 | - } | |
283 | ||
284 | /* Potentially add headers for unidentified content. */ | |
285 | if (EVBUFFER_LENGTH(req->output_buffer)) { | |
286 | if (evhttp_find_header(req->output_headers, | |
287 | "Content-Type") == NULL) { | |
288 | @@ -685,18 +690,18 @@ evhttp_connection_fail(struct evhttp_con | |
289 | ||
290 | void | |
291 | evhttp_write(int fd, short what, void *arg) | |
292 | { | |
293 | struct evhttp_connection *evcon = arg; | |
294 | - int n; | |
295 | ||
296 | if (what == EV_TIMEOUT) { | |
297 | evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); | |
298 | return; | |
299 | } | |
300 | ||
301 | - n = evbuffer_write(evcon->output_buffer, fd); | |
302 | + if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) { | |
303 | + int n = evbuffer_write(evcon->output_buffer, fd); | |
304 | if (n == -1) { | |
305 | event_debug(("%s: evbuffer_write", __func__)); | |
306 | evhttp_connection_fail(evcon, EVCON_HTTP_EOF); | |
307 | return; | |
308 | } | |
309 | @@ -704,10 +709,11 @@ evhttp_write(int fd, short what, void *a | |
310 | if (n == 0) { | |
311 | event_debug(("%s: write nothing", __func__)); | |
312 | evhttp_connection_fail(evcon, EVCON_HTTP_EOF); | |
313 | return; | |
314 | } | |
315 | + } | |
316 | ||
317 | if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) { | |
318 | evhttp_add_event(&evcon->ev, | |
319 | evcon->timeout, HTTP_WRITE_TIMEOUT); | |
320 | return; | |
321 | @@ -1010,15 +1016,13 @@ evhttp_connection_free(struct evhttp_con | |
322 | */ | |
323 | while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) { | |
324 | TAILQ_REMOVE(&evcon->requests, req, next); | |
325 | evhttp_request_free(req); | |
326 | } | |
327 | - | |
328 | - if (evcon->http_server != NULL) { | |
329 | - struct evhttp *http = evcon->http_server; | |
330 | - TAILQ_REMOVE(&http->connections, evcon, next); | |
331 | - } | |
332 | + | |
333 | + if (evcon->http_server != NULL) | |
334 | + evhttp_server_drop_connection(evcon); | |
335 | ||
336 | if (event_initialized(&evcon->close_ev)) | |
337 | event_del(&evcon->close_ev); | |
338 | ||
339 | if (event_initialized(&evcon->ev)) | |
340 | @@ -1099,14 +1103,20 @@ evhttp_connection_reset(struct evhttp_co | |
341 | EVUTIL_CLOSESOCKET(evcon->fd); | |
342 | evcon->fd = -1; | |
343 | } | |
344 | evcon->state = EVCON_DISCONNECTED; | |
345 | ||
346 | - evbuffer_drain(evcon->input_buffer, | |
347 | - EVBUFFER_LENGTH(evcon->input_buffer)); | |
348 | - evbuffer_drain(evcon->output_buffer, | |
349 | - EVBUFFER_LENGTH(evcon->output_buffer)); | |
350 | + /* | |
351 | + * These can grow quite large if processing a large photo or video | |
352 | + * upload/download. Instead of keeping the buffers around, just | |
353 | + * free and allocate new. | |
354 | + */ | |
355 | + evbuffer_free(evcon->input_buffer); | |
356 | + evcon->input_buffer = evbuffer_new(); | |
357 | + | |
358 | + evbuffer_free(evcon->output_buffer); | |
359 | + evcon->output_buffer = evbuffer_new(); | |
360 | } | |
361 | ||
362 | static void | |
363 | evhttp_detect_close_cb(int fd, short what, void *arg) | |
364 | { | |
365 | @@ -1276,23 +1286,56 @@ evhttp_parse_request_line(struct evhttp_ | |
366 | /* Parse the request line */ | |
367 | method = strsep(&line, " "); | |
368 | if (line == NULL) | |
369 | return (-1); | |
370 | uri = strsep(&line, " "); | |
371 | - if (line == NULL) | |
372 | - return (-1); | |
373 | + if (line == NULL) { | |
374 | + version = "HTTP/1.0"; | |
375 | + } else { | |
376 | version = strsep(&line, " "); | |
377 | if (line != NULL) | |
378 | return (-1); | |
379 | + } | |
380 | ||
381 | /* First line */ | |
382 | + req->ext_method = NULL; | |
383 | if (strcmp(method, "GET") == 0) { | |
384 | req->type = EVHTTP_REQ_GET; | |
385 | } else if (strcmp(method, "POST") == 0) { | |
386 | req->type = EVHTTP_REQ_POST; | |
387 | } else if (strcmp(method, "HEAD") == 0) { | |
388 | req->type = EVHTTP_REQ_HEAD; | |
389 | + } else if (strcmp(method, "OPTIONS") == 0) { | |
390 | + req->type = EVHTTP_REQ_POST; | |
391 | + req->ext_method = "OPTIONS"; | |
392 | + } else if (strcmp(method, "REPORT") == 0) { | |
393 | + req->type = EVHTTP_REQ_POST; | |
394 | + req->ext_method = "REPORT"; | |
395 | + } else if (strcmp(method, "PROPFIND") == 0) { | |
396 | + req->type = EVHTTP_REQ_POST; | |
397 | + req->ext_method = "PROPFIND"; | |
398 | + } else if (strcmp(method, "PROPPATH") == 0) { | |
399 | + req->type = EVHTTP_REQ_POST; | |
400 | + req->ext_method = "PROPPATH"; | |
401 | + } else if (strcmp(method, "MKCOL") == 0) { | |
402 | + req->type = EVHTTP_REQ_POST; | |
403 | + req->ext_method = "MKCOL"; | |
404 | + } else if (strcmp(method, "MKCALENDAR") == 0) { | |
405 | + req->type = EVHTTP_REQ_POST; | |
406 | + req->ext_method = "MKCALENDAR"; | |
407 | + } else if (strcmp(method, "PUT") == 0) { | |
408 | + req->type = EVHTTP_REQ_POST; | |
409 | + req->ext_method = "PUT"; | |
410 | + } else if (strcmp(method, "DELETE") == 0) { | |
411 | + req->type = EVHTTP_REQ_POST; | |
412 | + req->ext_method = "DELETE"; | |
413 | + } else if (strcmp(method, "LOCK") == 0) { | |
414 | + req->type = EVHTTP_REQ_POST; | |
415 | + req->ext_method = "LOCK"; | |
416 | + } else if (strcmp(method, "UNLOCK") == 0) { | |
417 | + req->type = EVHTTP_REQ_POST; | |
418 | + req->ext_method = "UNLOCK"; | |
419 | } else { | |
420 | event_debug(("%s: bad method %s on request %p from %s", | |
421 | __func__, method, req, req->remote_host)); | |
422 | return (-1); | |
423 | } | |
424 | @@ -1961,14 +2004,48 @@ evhttp_send_reply(struct evhttp_request | |
425 | evhttp_response_code(req, code, reason); | |
426 | ||
427 | evhttp_send(req, databuf); | |
428 | } | |
429 | ||
430 | +int | |
431 | +evhttp_send_reply_sync_begin(struct evhttp_request *req, int code, | |
432 | + const char *reason, struct evbuffer *databuf) { | |
433 | + evhttp_response_code(req, code, reason); | |
434 | + struct evhttp_connection *evcon = req->evcon; | |
435 | + | |
436 | + assert(TAILQ_FIRST(&evcon->requests) == req); | |
437 | + | |
438 | + /* xxx: not sure if we really should expose the data buffer this way */ | |
439 | + if (databuf != NULL) | |
440 | + evbuffer_add_buffer(req->output_buffer, databuf); | |
441 | + | |
442 | + /* Adds headers to the response */ | |
443 | + evhttp_make_header(evcon, req); | |
444 | + | |
445 | + return evbuffer_write(evcon->output_buffer, evcon->fd); | |
446 | +} | |
447 | + | |
448 | +void | |
449 | +evhttp_send_reply_sync_end(int nwritten, struct evhttp_request *req) { | |
450 | + struct evhttp_connection *evcon = req->evcon; | |
451 | + | |
452 | + if (nwritten <= 0) { | |
453 | + evhttp_connection_fail(evcon, EVCON_HTTP_EOF); | |
454 | + } else if (EVBUFFER_LENGTH(evcon->output_buffer) == 0) { | |
455 | + evhttp_send_done(evcon, NULL); | |
456 | + } else { | |
457 | + evhttp_write_buffer(evcon, evhttp_send_done, NULL); | |
458 | + } | |
459 | +} | |
460 | + | |
461 | + | |
462 | void | |
463 | evhttp_send_reply_start(struct evhttp_request *req, int code, | |
464 | const char *reason) | |
465 | { | |
466 | + req->referenced = 1; | |
467 | + | |
468 | evhttp_response_code(req, code, reason); | |
469 | if (req->major == 1 && req->minor == 1) { | |
470 | /* use chunked encoding for HTTP/1.1 */ | |
471 | evhttp_add_header(req->output_headers, "Transfer-Encoding", | |
472 | "chunked"); | |
473 | @@ -1984,10 +2061,12 @@ evhttp_send_reply_chunk(struct evhttp_re | |
474 | struct evhttp_connection *evcon = req->evcon; | |
475 | ||
476 | if (evcon == NULL) | |
477 | return; | |
478 | ||
479 | + if (req->referenced < 0) return; | |
480 | + | |
481 | if (req->chunked) { | |
482 | evbuffer_add_printf(evcon->output_buffer, "%x\r\n", | |
483 | (unsigned)EVBUFFER_LENGTH(databuf)); | |
484 | } | |
485 | evbuffer_add_buffer(evcon->output_buffer, databuf); | |
486 | @@ -2005,11 +2084,18 @@ evhttp_send_reply_end(struct evhttp_requ | |
487 | if (evcon == NULL) { | |
488 | evhttp_request_free(req); | |
489 | return; | |
490 | } | |
491 | ||
492 | - /* we expect no more calls form the user on this request */ | |
493 | + if (req->referenced < 0) { | |
494 | + req->referenced = 0; | |
495 | + evhttp_request_free(req); | |
496 | + return; | |
497 | + } | |
498 | + req->referenced = 0; | |
499 | + | |
500 | + /* we expect no more calls form the user on this request */ | |
501 | req->userdone = 1; | |
502 | ||
503 | if (req->chunked) { | |
504 | evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5); | |
505 | evhttp_write_buffer(req->evcon, evhttp_send_done, NULL); | |
506 | @@ -2291,33 +2377,63 @@ accept_socket(int fd, short what, void * | |
507 | ||
508 | evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen); | |
509 | } | |
510 | ||
511 | int | |
512 | -evhttp_bind_socket(struct evhttp *http, const char *address, u_short port) | |
513 | +evhttp_bind_socket_backlog_fd(struct evhttp *http, const char *address, | |
514 | + u_short port, int backlog) | |
515 | { | |
516 | int fd; | |
517 | int res; | |
518 | ||
519 | if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1) | |
520 | return (-1); | |
521 | ||
522 | - if (listen(fd, 128) == -1) { | |
523 | + if (listen(fd, backlog) == -1) { | |
524 | event_warn("%s: listen", __func__); | |
525 | EVUTIL_CLOSESOCKET(fd); | |
526 | return (-1); | |
527 | } | |
528 | ||
529 | res = evhttp_accept_socket(http, fd); | |
530 | ||
531 | - if (res != -1) | |
532 | + if (res != -1) { | |
533 | event_debug(("Bound to port %d - Awaiting connections ... ", | |
534 | port)); | |
535 | + return (fd); | |
536 | + } | |
537 | ||
538 | return (res); | |
539 | } | |
540 | ||
541 | +static int | |
542 | +mask_fd(int fd) | |
543 | +{ | |
544 | + return fd > 0 ? 0 : fd; | |
545 | +} | |
546 | + | |
547 | +int | |
548 | +evhttp_bind_socket(struct evhttp *http, const char *address, u_short port) | |
549 | +{ | |
550 | + return mask_fd(evhttp_bind_socket_backlog_fd(http, address, port, 128)); | |
551 | +} | |
552 | + | |
553 | +int | |
554 | +evhttp_bind_socket_with_fd(struct evhttp *http, const char *address, | |
555 | + u_short port) | |
556 | +{ | |
557 | + return evhttp_bind_socket_backlog_fd(http, address, port, 128); | |
558 | +} | |
559 | + | |
560 | +int | |
561 | +evhttp_bind_socket_backlog(struct evhttp *http, const char *address, | |
562 | + u_short port, int backlog) | |
563 | +{ | |
564 | + return mask_fd( | |
565 | + evhttp_bind_socket_backlog_fd(http, address, port, backlog)); | |
566 | +} | |
567 | + | |
568 | int | |
569 | evhttp_accept_socket(struct evhttp *http, int fd) | |
570 | { | |
571 | struct evhttp_bound_socket *bound; | |
572 | struct event *ev; | |
573 | @@ -2343,10 +2459,29 @@ evhttp_accept_socket(struct evhttp *http | |
574 | TAILQ_INSERT_TAIL(&http->sockets, bound, next); | |
575 | ||
576 | return (0); | |
577 | } | |
578 | ||
579 | +int | |
580 | +evhttp_del_accept_socket(struct evhttp *http, int fd) | |
581 | +{ | |
582 | + struct evhttp_bound_socket *bound; | |
583 | + TAILQ_FOREACH(bound, &http->sockets, next) { | |
584 | + if (bound->bind_ev.ev_fd == fd) | |
585 | + break; | |
586 | + } | |
587 | + | |
588 | + if (bound == NULL) | |
589 | + return (-1); | |
590 | + | |
591 | + TAILQ_REMOVE(&http->sockets, bound, next); | |
592 | + event_del(&bound->bind_ev); | |
593 | + free(bound); | |
594 | + | |
595 | + return (0); | |
596 | +} | |
597 | + | |
598 | static struct evhttp* | |
599 | evhttp_new_object(void) | |
600 | { | |
601 | struct evhttp *http = NULL; | |
602 | ||
603 | @@ -2525,10 +2660,15 @@ evhttp_request_new(void (*cb)(struct evh | |
604 | } | |
605 | ||
606 | void | |
607 | evhttp_request_free(struct evhttp_request *req) | |
608 | { | |
609 | + if (req->referenced) { | |
610 | + req->referenced = -1; | |
611 | + return; | |
612 | + } | |
613 | + | |
614 | if (req->remote_host != NULL) | |
615 | free(req->remote_host); | |
616 | if (req->uri != NULL) | |
617 | free(req->uri); | |
618 | if (req->response_code_line != NULL) | |
619 | @@ -2655,17 +2795,76 @@ evhttp_get_request(struct evhttp *http, | |
620 | ||
621 | /* | |
622 | * if we want to accept more than one request on a connection, | |
623 | * we need to know which http server it belongs to. | |
624 | */ | |
625 | - evcon->http_server = http; | |
626 | - TAILQ_INSERT_TAIL(&http->connections, evcon, next); | |
627 | + | |
628 | + evhttp_server_add_connection(http, evcon); | |
629 | ||
630 | if (evhttp_associate_new_request_with_connection(evcon) == -1) | |
631 | evhttp_connection_free(evcon); | |
632 | } | |
633 | ||
634 | +void | |
635 | +evhttp_pause(struct evhttp *http) | |
636 | +{ | |
637 | + struct evhttp_bound_socket *bound; | |
638 | + TAILQ_FOREACH(bound, &http->sockets, next) { | |
639 | + event_del(&bound->bind_ev); | |
640 | + } | |
641 | +} | |
642 | + | |
643 | +void | |
644 | +evhttp_resume(struct evhttp *http) | |
645 | +{ | |
646 | + struct evhttp_bound_socket *bound; | |
647 | + TAILQ_FOREACH(bound, &http->sockets, next) { | |
648 | + event_add(&bound->bind_ev, 0); | |
649 | + } | |
650 | +} | |
651 | + | |
652 | +int | |
653 | +evhttp_get_connection_limit(struct evhttp *http) | |
654 | +{ | |
655 | + return http->connection_limit; | |
656 | +} | |
657 | + | |
658 | +int | |
659 | +evhttp_set_connection_limit(struct evhttp *http, int nlimit) | |
660 | +{ | |
661 | + int olimit = http->connection_limit; | |
662 | + http->connection_limit = nlimit; | |
663 | + return olimit; | |
664 | +} | |
665 | + | |
666 | +void | |
667 | +evhttp_server_add_connection(struct evhttp *http, | |
668 | + struct evhttp_connection *evcon) | |
669 | +{ | |
670 | + evcon->http_server = http; | |
671 | + TAILQ_INSERT_TAIL(&http->connections, evcon, next); | |
672 | + | |
673 | + http->connection_count++; | |
674 | + if (http->connection_limit > 0 | |
675 | + && http->connection_count >= http->connection_limit) | |
676 | + { | |
677 | + evhttp_pause(http); | |
678 | + } | |
679 | +} | |
680 | + | |
681 | +void | |
682 | +evhttp_server_drop_connection(struct evhttp_connection *evcon) | |
683 | +{ | |
684 | + struct evhttp *http = evcon->http_server; | |
685 | + TAILQ_REMOVE(&http->connections, evcon, next); | |
686 | + http->connection_count--; | |
687 | + if (http->connection_limit > 0 | |
688 | + && http->connection_count < http->connection_limit) | |
689 | + { | |
690 | + evhttp_resume(http); | |
691 | + } | |
692 | +} | |
693 | ||
694 | /* | |
695 | * Network helper functions that we do not want to export to the rest of | |
696 | * the world. | |
697 | */ | |
698 |