Mercurial > hg > nginx-vendor-0-5
comparison src/event/ngx_event_accept.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | 4b2dafa26fe2 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <nginx.h> | |
11 | |
12 | |
13 typedef struct { | |
14 int flag; | |
15 u_char *name; | |
16 } ngx_accept_log_ctx_t; | |
17 | |
18 | |
19 static void ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log); | |
20 static size_t ngx_accept_log_error(void *data, char *buf, size_t len); | |
21 | |
22 | |
23 void ngx_event_accept(ngx_event_t *ev) | |
24 { | |
25 ngx_uint_t instance, accepted; | |
26 socklen_t len; | |
27 struct sockaddr *sa; | |
28 ngx_err_t err; | |
29 ngx_log_t *log; | |
30 ngx_pool_t *pool; | |
31 ngx_socket_t s; | |
32 ngx_event_t *rev, *wev; | |
33 ngx_connection_t *c, *ls; | |
34 ngx_event_conf_t *ecf; | |
35 ngx_accept_log_ctx_t *ctx; | |
36 | |
37 ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); | |
38 | |
39 if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { | |
40 ev->available = 1; | |
41 | |
42 } else if (!(ngx_event_flags & NGX_HAVE_KQUEUE_EVENT)) { | |
43 ev->available = ecf->multi_accept; | |
44 } | |
45 | |
46 ls = ev->data; | |
47 | |
48 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
49 "accept on %s, ready: %d", | |
50 ls->listening->addr_text.data, ev->available); | |
51 | |
52 ev->ready = 0; | |
53 accepted = 0; | |
54 pool = NULL; | |
55 | |
56 do { | |
57 | |
58 if (pool == NULL) { | |
59 | |
60 /* | |
61 * Create the pool before accept() to avoid the copying of | |
62 * the sockaddr. Although accept() can fail it is uncommon | |
63 * case and besides the pool can be got from the free pool list | |
64 */ | |
65 | |
66 if (!(pool = ngx_create_pool(ls->listening->pool_size, ev->log))) { | |
67 return; | |
68 } | |
69 } | |
70 | |
71 if (!(sa = ngx_palloc(pool, ls->listening->socklen))) { | |
72 ngx_destroy_pool(pool); | |
73 return; | |
74 } | |
75 | |
76 if (!(log = ngx_palloc(pool, sizeof(ngx_log_t)))) { | |
77 ngx_destroy_pool(pool); | |
78 return; | |
79 } | |
80 | |
81 ngx_memcpy(log, ls->log, sizeof(ngx_log_t)); | |
82 pool->log = log; | |
83 | |
84 if (!(ctx = ngx_palloc(pool, sizeof(ngx_accept_log_ctx_t)))) { | |
85 ngx_destroy_pool(pool); | |
86 return; | |
87 } | |
88 | |
89 /* -1 disables the connection number logging */ | |
90 ctx->flag = -1; | |
91 ctx->name = ls->listening->addr_text.data; | |
92 | |
93 log->data = ctx; | |
94 log->handler = ngx_accept_log_error; | |
95 | |
96 len = ls->listening->socklen; | |
97 | |
98 s = accept(ls->fd, sa, &len); | |
99 if (s == -1) { | |
100 err = ngx_socket_errno; | |
101 | |
102 if (err == NGX_EAGAIN) { | |
103 #if 0 | |
104 if (!(ngx_event_flags & NGX_USE_RTSIG_EVENT)) | |
105 { | |
106 ngx_log_error(NGX_LOG_NOTICE, log, err, | |
107 "EAGAIN after %d accepted connection(s)", | |
108 accepted); | |
109 } | |
110 #endif | |
111 | |
112 ngx_destroy_pool(pool); | |
113 return; | |
114 } | |
115 | |
116 ngx_log_error(NGX_LOG_ALERT, ev->log, err, | |
117 "accept() on %s failed", | |
118 ls->listening->addr_text.data); | |
119 | |
120 if (err == NGX_ECONNABORTED) { | |
121 if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { | |
122 ev->available--; | |
123 } | |
124 | |
125 if (ev->available) { | |
126 /* reuse the previously allocated pool */ | |
127 continue; | |
128 } | |
129 } | |
130 | |
131 ngx_destroy_pool(pool); | |
132 return; | |
133 } | |
134 | |
135 #if (NGX_STAT_STUB) | |
136 (*ngx_stat_accepted)++; | |
137 #endif | |
138 | |
139 ngx_accept_disabled = (ngx_uint_t) s + NGX_ACCEPT_THRESHOLD | |
140 - ecf->connections; | |
141 | |
142 /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */ | |
143 | |
144 if ((ngx_uint_t) s >= ecf->connections) { | |
145 | |
146 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
147 "accept() on %s returned socket #%d while " | |
148 "only %d connections was configured, " | |
149 "closing the connection", | |
150 ls->listening->addr_text.data, s, ecf->connections); | |
151 | |
152 ngx_close_accepted_socket(s, log); | |
153 ngx_destroy_pool(pool); | |
154 return; | |
155 } | |
156 | |
157 #if (NGX_STAT_STUB) | |
158 (*ngx_stat_active)++; | |
159 #endif | |
160 | |
161 /* set a blocking mode for aio and non-blocking mode for the others */ | |
162 | |
163 if (ngx_inherited_nonblocking) { | |
164 if ((ngx_event_flags & NGX_USE_AIO_EVENT)) { | |
165 if (ngx_blocking(s) == -1) { | |
166 ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | |
167 ngx_blocking_n " failed"); | |
168 | |
169 ngx_close_accepted_socket(s, log); | |
170 ngx_destroy_pool(pool); | |
171 return; | |
172 } | |
173 } | |
174 | |
175 } else { | |
176 if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) { | |
177 if (ngx_nonblocking(s) == -1) { | |
178 ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | |
179 ngx_nonblocking_n " failed"); | |
180 | |
181 ngx_close_accepted_socket(s, log); | |
182 ngx_destroy_pool(pool); | |
183 return; | |
184 } | |
185 } | |
186 } | |
187 | |
188 #if (WIN32) | |
189 /* | |
190 * Winsock assignes a socket number divisible by 4 | |
191 * so to find a connection we divide a socket number by 4. | |
192 */ | |
193 | |
194 if (s % 4) { | |
195 ngx_log_error(NGX_LOG_EMERG, ev->log, 0, | |
196 "accept() on %s returned socket #%d, " | |
197 "not divisible by 4", | |
198 ls->listening->addr_text.data, s); | |
199 exit(1); | |
200 } | |
201 | |
202 c = &ngx_cycle->connections[s / 4]; | |
203 rev = &ngx_cycle->read_events[s / 4]; | |
204 wev = &ngx_cycle->write_events[s / 4]; | |
205 #else | |
206 c = &ngx_cycle->connections[s]; | |
207 rev = &ngx_cycle->read_events[s]; | |
208 wev = &ngx_cycle->write_events[s]; | |
209 #endif | |
210 | |
211 instance = rev->instance; | |
212 | |
213 #if (NGX_THREADS) | |
214 | |
215 if (*(&c->lock)) { | |
216 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
217 "spinlock in accept, fd:%", s); | |
218 ngx_spinlock(&c->lock, 1000); | |
219 ngx_unlock(&c->lock); | |
220 } | |
221 | |
222 #endif | |
223 | |
224 ngx_memzero(rev, sizeof(ngx_event_t)); | |
225 ngx_memzero(wev, sizeof(ngx_event_t)); | |
226 ngx_memzero(c, sizeof(ngx_connection_t)); | |
227 | |
228 c->pool = pool; | |
229 | |
230 c->listening = ls->listening; | |
231 c->sockaddr = sa; | |
232 c->socklen = len; | |
233 | |
234 rev->instance = !instance; | |
235 wev->instance = !instance; | |
236 | |
237 rev->index = NGX_INVALID_INDEX; | |
238 wev->index = NGX_INVALID_INDEX; | |
239 | |
240 rev->data = c; | |
241 wev->data = c; | |
242 | |
243 c->read = rev; | |
244 c->write = wev; | |
245 | |
246 c->fd = s; | |
247 c->unexpected_eof = 1; | |
248 | |
249 wev->write = 1; | |
250 wev->ready = 1; | |
251 | |
252 if (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) { | |
253 /* epoll, rtsig, aio, iocp */ | |
254 rev->ready = 1; | |
255 } | |
256 | |
257 if (ev->deferred_accept) { | |
258 rev->ready = 1; | |
259 } | |
260 | |
261 c->ctx = ls->ctx; | |
262 c->servers = ls->servers; | |
263 | |
264 c->recv = ngx_recv; | |
265 c->send_chain = ngx_send_chain; | |
266 | |
267 c->log = log; | |
268 rev->log = log; | |
269 wev->log = log; | |
270 | |
271 /* | |
272 * TODO: MT: - atomic increment (x86: lock xadd) | |
273 * or protection by critical section or light mutex | |
274 * | |
275 * TODO: MP: - allocated in a shared memory | |
276 * - atomic increment (x86: lock xadd) | |
277 * or protection by critical section or light mutex | |
278 */ | |
279 | |
280 c->number = ngx_atomic_inc(ngx_connection_counter); | |
281 | |
282 #if (NGX_THREADS) | |
283 rev->lock = &c->lock; | |
284 wev->lock = &c->lock; | |
285 rev->own_lock = &c->lock; | |
286 wev->own_lock = &c->lock; | |
287 #endif | |
288 | |
289 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
290 "accept: fd:%d c:%d", s, c->number); | |
291 | |
292 if (c->listening->addr_ntop) { | |
293 c->addr_text.data = ngx_palloc(c->pool, | |
294 c->listening->addr_text_max_len); | |
295 if (c->addr_text.data == NULL) { | |
296 ngx_close_accepted_socket(s, log); | |
297 ngx_destroy_pool(pool); | |
298 return; | |
299 } | |
300 | |
301 c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr, | |
302 c->addr_text.data, | |
303 c->listening->addr_text_max_len); | |
304 if (c->addr_text.len == 0) { | |
305 ngx_close_accepted_socket(s, log); | |
306 ngx_destroy_pool(pool); | |
307 return; | |
308 } | |
309 } | |
310 | |
311 #if (NGX_DEBUG) | |
312 { | |
313 | |
314 uint32_t *addr; | |
315 in_addr_t i; | |
316 struct sockaddr_in *addr_in; | |
317 | |
318 addr_in = (struct sockaddr_in *) sa; | |
319 addr = ecf->debug_connection.elts; | |
320 for (i = 0; i < ecf->debug_connection.nelts; i++) { | |
321 if (addr[i] == addr_in->sin_addr.s_addr) { | |
322 log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; | |
323 break; | |
324 } | |
325 } | |
326 | |
327 } | |
328 #endif | |
329 | |
330 if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { | |
331 if (ngx_add_conn(c) == NGX_ERROR) { | |
332 ngx_close_accepted_socket(s, log); | |
333 ngx_destroy_pool(pool); | |
334 return; | |
335 } | |
336 } | |
337 | |
338 pool = NULL; | |
339 | |
340 log->data = NULL; | |
341 log->handler = NULL; | |
342 | |
343 ls->listening->handler(c); | |
344 | |
345 if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { | |
346 ev->available--; | |
347 } | |
348 | |
349 accepted++; | |
350 | |
351 } while (ev->available); | |
352 } | |
353 | |
354 | |
355 ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle) | |
356 { | |
357 if (*ngx_accept_mutex == 0 | |
358 && ngx_atomic_cmp_set(ngx_accept_mutex, 0, ngx_pid)) | |
359 { | |
360 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
361 "accept mutex locked"); | |
362 | |
363 if (!ngx_accept_mutex_held) { | |
364 if (ngx_enable_accept_events(cycle) == NGX_ERROR) { | |
365 *ngx_accept_mutex = 0; | |
366 return NGX_ERROR; | |
367 } | |
368 | |
369 ngx_accept_mutex_held = 1; | |
370 } | |
371 | |
372 return NGX_OK; | |
373 } | |
374 | |
375 if (ngx_accept_mutex_held) { | |
376 if (ngx_disable_accept_events(cycle) == NGX_ERROR) { | |
377 return NGX_ERROR; | |
378 } | |
379 | |
380 ngx_accept_mutex_held = 0; | |
381 } | |
382 | |
383 return NGX_OK; | |
384 } | |
385 | |
386 | |
387 ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) | |
388 { | |
389 ngx_uint_t i; | |
390 ngx_listening_t *s; | |
391 | |
392 s = cycle->listening.elts; | |
393 for (i = 0; i < cycle->listening.nelts; i++) { | |
394 | |
395 /* | |
396 * we do not need to handle the Winsock sockets here (divide a socket | |
397 * number by 4) because this function would never called | |
398 * in the Winsock environment | |
399 */ | |
400 | |
401 if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { | |
402 if (ngx_add_conn(&cycle->connections[s[i].fd]) == NGX_ERROR) { | |
403 return NGX_ERROR; | |
404 } | |
405 | |
406 } else { | |
407 if (ngx_add_event(&cycle->read_events[s[i].fd], NGX_READ_EVENT, 0) | |
408 == NGX_ERROR) | |
409 { | |
410 return NGX_ERROR; | |
411 } | |
412 } | |
413 } | |
414 | |
415 return NGX_OK; | |
416 } | |
417 | |
418 | |
419 ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle) | |
420 { | |
421 ngx_uint_t i; | |
422 ngx_listening_t *s; | |
423 | |
424 s = cycle->listening.elts; | |
425 for (i = 0; i < cycle->listening.nelts; i++) { | |
426 | |
427 /* | |
428 * we do not need to handle the Winsock sockets here (divide a socket | |
429 * number by 4) because this function would never called | |
430 * in the Winsock environment | |
431 */ | |
432 | |
433 if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { | |
434 if (!cycle->connections[s[i].fd].read->active) { | |
435 continue; | |
436 } | |
437 | |
438 if (ngx_del_conn(&cycle->connections[s[i].fd], NGX_DISABLE_EVENT) | |
439 == NGX_ERROR) | |
440 { | |
441 return NGX_ERROR; | |
442 } | |
443 | |
444 } else { | |
445 if (!cycle->read_events[s[i].fd].active) { | |
446 continue; | |
447 } | |
448 | |
449 if (ngx_del_event(&cycle->read_events[s[i].fd], NGX_READ_EVENT, | |
450 NGX_DISABLE_EVENT) == NGX_ERROR) | |
451 { | |
452 return NGX_ERROR; | |
453 } | |
454 } | |
455 } | |
456 | |
457 return NGX_OK; | |
458 } | |
459 | |
460 | |
461 static void ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log) | |
462 { | |
463 if (ngx_close_socket(s) == -1) { | |
464 ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | |
465 ngx_close_socket_n " failed"); | |
466 } | |
467 } | |
468 | |
469 | |
470 static size_t ngx_accept_log_error(void *data, char *buf, size_t len) | |
471 { | |
472 ngx_accept_log_ctx_t *ctx = data; | |
473 | |
474 return ngx_snprintf(buf, len, " while accept() on %s", ctx->name); | |
475 } |