Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_upstream_keepalive_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Maxim Dounin
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 typedef struct {
15 
18 
21 
23 
24 
25 typedef struct {
27 
29 
30  void *data;
31 
34 
35 #if (NGX_HTTP_SSL)
36  ngx_event_set_peer_session_pt original_set_session;
37  ngx_event_save_peer_session_pt original_save_session;
38 #endif
39 
41 
42 
43 typedef struct {
45 
48 
49  socklen_t socklen;
50  u_char sockaddr[NGX_SOCKADDRLEN];
51 
53 
54 
55 static ngx_int_t ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
57 static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc,
58  void *data);
59 static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc,
60  void *data, ngx_uint_t state);
61 
62 static void ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev);
63 static void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev);
64 static void ngx_http_upstream_keepalive_close(ngx_connection_t *c);
65 
66 
67 #if (NGX_HTTP_SSL)
68 static ngx_int_t ngx_http_upstream_keepalive_set_session(
69  ngx_peer_connection_t *pc, void *data);
70 static void ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc,
71  void *data);
72 #endif
73 
74 static void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf);
75 static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
76  void *conf);
77 
78 
79 static ngx_command_t ngx_http_upstream_keepalive_commands[] = {
80 
81  { ngx_string("keepalive"),
83  ngx_http_upstream_keepalive,
84  0,
85  0,
86  NULL },
87 
89 };
90 
91 
92 static ngx_http_module_t ngx_http_upstream_keepalive_module_ctx = {
93  NULL, /* preconfiguration */
94  NULL, /* postconfiguration */
95 
96  NULL, /* create main configuration */
97  NULL, /* init main configuration */
98 
99  ngx_http_upstream_keepalive_create_conf, /* create server configuration */
100  NULL, /* merge server configuration */
101 
102  NULL, /* create location configuration */
103  NULL /* merge location configuration */
104 };
105 
106 
109  &ngx_http_upstream_keepalive_module_ctx, /* module context */
110  ngx_http_upstream_keepalive_commands, /* module directives */
111  NGX_HTTP_MODULE, /* module type */
112  NULL, /* init master */
113  NULL, /* init module */
114  NULL, /* init process */
115  NULL, /* init thread */
116  NULL, /* exit thread */
117  NULL, /* exit process */
118  NULL, /* exit master */
120 };
121 
122 
123 static ngx_int_t
124 ngx_http_upstream_init_keepalive(ngx_conf_t *cf,
126 {
127  ngx_uint_t i;
130 
132  "init keepalive");
133 
135  ngx_http_upstream_keepalive_module);
136 
137  if (kcf->original_init_upstream(cf, us) != NGX_OK) {
138  return NGX_ERROR;
139  }
140 
141  kcf->original_init_peer = us->peer.init;
142 
143  us->peer.init = ngx_http_upstream_init_keepalive_peer;
144 
145  /* allocate cache items and add to free queue */
146 
147  cached = ngx_pcalloc(cf->pool,
149  if (cached == NULL) {
150  return NGX_ERROR;
151  }
152 
153  ngx_queue_init(&kcf->cache);
154  ngx_queue_init(&kcf->free);
155 
156  for (i = 0; i < kcf->max_cached; i++) {
157  ngx_queue_insert_head(&kcf->free, &cached[i].queue);
158  cached[i].conf = kcf;
159  }
160 
161  return NGX_OK;
162 }
163 
164 
165 static ngx_int_t
166 ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
168 {
171 
173  "init keepalive peer");
174 
176  ngx_http_upstream_keepalive_module);
177 
179  if (kp == NULL) {
180  return NGX_ERROR;
181  }
182 
183  if (kcf->original_init_peer(r, us) != NGX_OK) {
184  return NGX_ERROR;
185  }
186 
187  kp->conf = kcf;
188  kp->upstream = r->upstream;
189  kp->data = r->upstream->peer.data;
192 
193  r->upstream->peer.data = kp;
194  r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer;
195  r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer;
196 
197 #if (NGX_HTTP_SSL)
198  kp->original_set_session = r->upstream->peer.set_session;
199  kp->original_save_session = r->upstream->peer.save_session;
200  r->upstream->peer.set_session = ngx_http_upstream_keepalive_set_session;
201  r->upstream->peer.save_session = ngx_http_upstream_keepalive_save_session;
202 #endif
203 
204  return NGX_OK;
205 }
206 
207 
208 static ngx_int_t
209 ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data)
210 {
213 
214  ngx_int_t rc;
215  ngx_queue_t *q, *cache;
216  ngx_connection_t *c;
217 
219  "get keepalive peer");
220 
221  /* ask balancer */
222 
223  rc = kp->original_get_peer(pc, kp->data);
224 
225  if (rc != NGX_OK) {
226  return rc;
227  }
228 
229  /* search cache for suitable connection */
230 
231  cache = &kp->conf->cache;
232 
233  for (q = ngx_queue_head(cache);
234  q != ngx_queue_sentinel(cache);
235  q = ngx_queue_next(q))
236  {
238  c = item->connection;
239 
240  if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr,
241  item->socklen, pc->socklen)
242  == 0)
243  {
244  ngx_queue_remove(q);
245  ngx_queue_insert_head(&kp->conf->free, q);
246 
248  "get keepalive peer: using connection %p", c);
249 
250  c->idle = 0;
251  c->log = pc->log;
252  c->read->log = pc->log;
253  c->write->log = pc->log;
254  c->pool->log = pc->log;
255 
256  pc->connection = c;
257  pc->cached = 1;
258 
259  return NGX_DONE;
260  }
261  }
262 
263  return NGX_OK;
264 }
265 
266 
267 static void
268 ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data,
269  ngx_uint_t state)
270 {
273 
274  ngx_queue_t *q;
275  ngx_connection_t *c;
277 
279  "free keepalive peer");
280 
281  /* cache valid connections */
282 
283  u = kp->upstream;
284  c = pc->connection;
285 
286  if (state & NGX_PEER_FAILED
287  || c == NULL
288  || c->read->eof
289  || c->read->error
290  || c->read->timedout
291  || c->write->error
292  || c->write->timedout)
293  {
294  goto invalid;
295  }
296 
297  if (!u->keepalive) {
298  goto invalid;
299  }
300 
301  if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
302  goto invalid;
303  }
304 
306  "free keepalive peer: saving connection %p", c);
307 
308  if (ngx_queue_empty(&kp->conf->free)) {
309 
310  q = ngx_queue_last(&kp->conf->cache);
311  ngx_queue_remove(q);
312 
314 
315  ngx_http_upstream_keepalive_close(item->connection);
316 
317  } else {
318  q = ngx_queue_head(&kp->conf->free);
319  ngx_queue_remove(q);
320 
322  }
323 
324  item->connection = c;
325  ngx_queue_insert_head(&kp->conf->cache, q);
326 
327  pc->connection = NULL;
328 
329  if (c->read->timer_set) {
330  ngx_del_timer(c->read);
331  }
332  if (c->write->timer_set) {
333  ngx_del_timer(c->write);
334  }
335 
336  c->write->handler = ngx_http_upstream_keepalive_dummy_handler;
337  c->read->handler = ngx_http_upstream_keepalive_close_handler;
338 
339  c->data = item;
340  c->idle = 1;
341  c->log = ngx_cycle->log;
342  c->read->log = ngx_cycle->log;
343  c->write->log = ngx_cycle->log;
344  c->pool->log = ngx_cycle->log;
345 
346  item->socklen = pc->socklen;
347  ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);
348 
349  if (c->read->ready) {
350  ngx_http_upstream_keepalive_close_handler(c->read);
351  }
352 
353 invalid:
354 
355  kp->original_free_peer(pc, kp->data, state);
356 }
357 
358 
359 static void
360 ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev)
361 {
363  "keepalive dummy handler");
364 }
365 
366 
367 static void
368 ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev)
369 {
372 
373  int n;
374  char buf[1];
375  ngx_connection_t *c;
376 
378  "keepalive close handler");
379 
380  c = ev->data;
381 
382  if (c->close) {
383  goto close;
384  }
385 
386  n = recv(c->fd, buf, 1, MSG_PEEK);
387 
388  if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
389  /* stale event */
390 
391  if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
392  goto close;
393  }
394 
395  return;
396  }
397 
398 close:
399 
400  item = c->data;
401  conf = item->conf;
402 
403  ngx_http_upstream_keepalive_close(c);
404 
405  ngx_queue_remove(&item->queue);
406  ngx_queue_insert_head(&conf->free, &item->queue);
407 }
408 
409 
410 static void
411 ngx_http_upstream_keepalive_close(ngx_connection_t *c)
412 {
413 
414 #if (NGX_HTTP_SSL)
415 
416  if (c->ssl) {
417  c->ssl->no_wait_shutdown = 1;
418  c->ssl->no_send_shutdown = 1;
419 
420  if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
421  c->ssl->handler = ngx_http_upstream_keepalive_close;
422  return;
423  }
424  }
425 
426 #endif
427 
430 }
431 
432 
433 #if (NGX_HTTP_SSL)
434 
435 static ngx_int_t
436 ngx_http_upstream_keepalive_set_session(ngx_peer_connection_t *pc, void *data)
437 {
439 
440  return kp->original_set_session(pc, kp->data);
441 }
442 
443 
444 static void
445 ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc, void *data)
446 {
448 
449  kp->original_save_session(pc, kp->data);
450  return;
451 }
452 
453 #endif
454 
455 
456 static void *
457 ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf)
458 {
460 
461  conf = ngx_pcalloc(cf->pool,
463  if (conf == NULL) {
464  return NULL;
465  }
466 
467  /*
468  * set by ngx_pcalloc():
469  *
470  * conf->original_init_upstream = NULL;
471  * conf->original_init_peer = NULL;
472  */
473 
474  conf->max_cached = 1;
475 
476  return conf;
477 }
478 
479 
480 static char *
481 ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
482 {
485 
486  ngx_int_t n;
487  ngx_str_t *value;
488  ngx_uint_t i;
489 
491 
493  ngx_http_upstream_keepalive_module);
494 
495  if (kcf->original_init_upstream) {
496  return "is duplicate";
497  }
498 
500  ? uscf->peer.init_upstream
502 
503  uscf->peer.init_upstream = ngx_http_upstream_init_keepalive;
504 
505  /* read options */
506 
507  value = cf->args->elts;
508 
509  n = ngx_atoi(value[1].data, value[1].len);
510 
511  if (n == NGX_ERROR || n == 0) {
513  "invalid value \"%V\" in \"%V\" directive",
514  &value[1], &cmd->name);
515  return NGX_CONF_ERROR;
516  }
517 
518  kcf->max_cached = n;
519 
520  for (i = 2; i < cf->args->nelts; i++) {
521 
522  if (ngx_strcmp(value[i].data, "single") == 0) {
524  "the \"single\" parameter is deprecated");
525  continue;
526  }
527 
528  goto invalid;
529  }
530 
531  return NGX_CONF_OK;
532 
533 invalid:
534 
536  "invalid parameter \"%V\"", &value[i]);
537 
538  return NGX_CONF_ERROR;
539 }