Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Maxim Dounin
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 typedef struct {
0014     ngx_uint_t                         max_cached;
0015 
0016     ngx_queue_t                        cache;
0017     ngx_queue_t                        free;
0018 
0019     ngx_http_upstream_init_pt          original_init_upstream;
0020     ngx_http_upstream_init_peer_pt     original_init_peer;
0021 
0022 } ngx_http_upstream_keepalive_srv_conf_t;
0023 
0024 
0025 typedef struct {
0026     ngx_http_upstream_keepalive_srv_conf_t  *conf;
0027 
0028     ngx_queue_t                        queue;
0029     ngx_connection_t                  *connection;
0030 
0031     socklen_t                          socklen;
0032     ngx_sockaddr_t                     sockaddr;
0033 
0034 } ngx_http_upstream_keepalive_cache_t;
0035 
0036 
0037 typedef struct {
0038     ngx_http_upstream_keepalive_srv_conf_t  *conf;
0039 
0040     ngx_http_upstream_t               *upstream;
0041 
0042     void                              *data;
0043 
0044     ngx_event_get_peer_pt              original_get_peer;
0045     ngx_event_free_peer_pt             original_free_peer;
0046 
0047 #if (NGX_HTTP_SSL)
0048     ngx_event_set_peer_session_pt      original_set_session;
0049     ngx_event_save_peer_session_pt     original_save_session;
0050 #endif
0051 
0052 } ngx_http_upstream_keepalive_peer_data_t;
0053 
0054 
0055 static ngx_int_t ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
0056     ngx_http_upstream_srv_conf_t *us);
0057 static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc,
0058     void *data);
0059 static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc,
0060     void *data, ngx_uint_t state);
0061 
0062 static void ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev);
0063 static void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev);
0064 static void ngx_http_upstream_keepalive_close(ngx_connection_t *c);
0065 
0066 #if (NGX_HTTP_SSL)
0067 static ngx_int_t ngx_http_upstream_keepalive_set_session(
0068     ngx_peer_connection_t *pc, void *data);
0069 static void ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc,
0070     void *data);
0071 #endif
0072 
0073 static void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf);
0074 static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
0075     void *conf);
0076 
0077 
0078 static ngx_command_t  ngx_http_upstream_keepalive_commands[] = {
0079 
0080     { ngx_string("keepalive"),
0081       NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
0082       ngx_http_upstream_keepalive,
0083       NGX_HTTP_SRV_CONF_OFFSET,
0084       0,
0085       NULL },
0086 
0087       ngx_null_command
0088 };
0089 
0090 
0091 static ngx_http_module_t  ngx_http_upstream_keepalive_module_ctx = {
0092     NULL,                                  /* preconfiguration */
0093     NULL,                                  /* postconfiguration */
0094 
0095     NULL,                                  /* create main configuration */
0096     NULL,                                  /* init main configuration */
0097 
0098     ngx_http_upstream_keepalive_create_conf, /* create server configuration */
0099     NULL,                                  /* merge server configuration */
0100 
0101     NULL,                                  /* create location configuration */
0102     NULL                                   /* merge location configuration */
0103 };
0104 
0105 
0106 ngx_module_t  ngx_http_upstream_keepalive_module = {
0107     NGX_MODULE_V1,
0108     &ngx_http_upstream_keepalive_module_ctx, /* module context */
0109     ngx_http_upstream_keepalive_commands,    /* module directives */
0110     NGX_HTTP_MODULE,                       /* module type */
0111     NULL,                                  /* init master */
0112     NULL,                                  /* init module */
0113     NULL,                                  /* init process */
0114     NULL,                                  /* init thread */
0115     NULL,                                  /* exit thread */
0116     NULL,                                  /* exit process */
0117     NULL,                                  /* exit master */
0118     NGX_MODULE_V1_PADDING
0119 };
0120 
0121 
0122 static ngx_int_t
0123 ngx_http_upstream_init_keepalive(ngx_conf_t *cf,
0124     ngx_http_upstream_srv_conf_t *us)
0125 {
0126     ngx_uint_t                               i;
0127     ngx_http_upstream_keepalive_srv_conf_t  *kcf;
0128     ngx_http_upstream_keepalive_cache_t     *cached;
0129 
0130     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
0131                    "init keepalive");
0132 
0133     kcf = ngx_http_conf_upstream_srv_conf(us,
0134                                           ngx_http_upstream_keepalive_module);
0135 
0136     if (kcf->original_init_upstream(cf, us) != NGX_OK) {
0137         return NGX_ERROR;
0138     }
0139 
0140     kcf->original_init_peer = us->peer.init;
0141 
0142     us->peer.init = ngx_http_upstream_init_keepalive_peer;
0143 
0144     /* allocate cache items and add to free queue */
0145 
0146     cached = ngx_pcalloc(cf->pool,
0147                 sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached);
0148     if (cached == NULL) {
0149         return NGX_ERROR;
0150     }
0151 
0152     ngx_queue_init(&kcf->cache);
0153     ngx_queue_init(&kcf->free);
0154 
0155     for (i = 0; i < kcf->max_cached; i++) {
0156         ngx_queue_insert_head(&kcf->free, &cached[i].queue);
0157         cached[i].conf = kcf;
0158     }
0159 
0160     return NGX_OK;
0161 }
0162 
0163 
0164 static ngx_int_t
0165 ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
0166     ngx_http_upstream_srv_conf_t *us)
0167 {
0168     ngx_http_upstream_keepalive_peer_data_t  *kp;
0169     ngx_http_upstream_keepalive_srv_conf_t   *kcf;
0170 
0171     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0172                    "init keepalive peer");
0173 
0174     kcf = ngx_http_conf_upstream_srv_conf(us,
0175                                           ngx_http_upstream_keepalive_module);
0176 
0177     kp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_keepalive_peer_data_t));
0178     if (kp == NULL) {
0179         return NGX_ERROR;
0180     }
0181 
0182     if (kcf->original_init_peer(r, us) != NGX_OK) {
0183         return NGX_ERROR;
0184     }
0185 
0186     kp->conf = kcf;
0187     kp->upstream = r->upstream;
0188     kp->data = r->upstream->peer.data;
0189     kp->original_get_peer = r->upstream->peer.get;
0190     kp->original_free_peer = r->upstream->peer.free;
0191 
0192     r->upstream->peer.data = kp;
0193     r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer;
0194     r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer;
0195 
0196 #if (NGX_HTTP_SSL)
0197     kp->original_set_session = r->upstream->peer.set_session;
0198     kp->original_save_session = r->upstream->peer.save_session;
0199     r->upstream->peer.set_session = ngx_http_upstream_keepalive_set_session;
0200     r->upstream->peer.save_session = ngx_http_upstream_keepalive_save_session;
0201 #endif
0202 
0203     return NGX_OK;
0204 }
0205 
0206 
0207 static ngx_int_t
0208 ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data)
0209 {
0210     ngx_http_upstream_keepalive_peer_data_t  *kp = data;
0211     ngx_http_upstream_keepalive_cache_t      *item;
0212 
0213     ngx_int_t          rc;
0214     ngx_queue_t       *q, *cache;
0215     ngx_connection_t  *c;
0216 
0217     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0218                    "get keepalive peer");
0219 
0220     /* ask balancer */
0221 
0222     rc = kp->original_get_peer(pc, kp->data);
0223 
0224     if (rc != NGX_OK) {
0225         return rc;
0226     }
0227 
0228     /* search cache for suitable connection */
0229 
0230     cache = &kp->conf->cache;
0231 
0232     for (q = ngx_queue_head(cache);
0233          q != ngx_queue_sentinel(cache);
0234          q = ngx_queue_next(q))
0235     {
0236         item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
0237         c = item->connection;
0238 
0239         if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr,
0240                          item->socklen, pc->socklen)
0241             == 0)
0242         {
0243             ngx_queue_remove(q);
0244             ngx_queue_insert_head(&kp->conf->free, q);
0245 
0246             goto found;
0247         }
0248     }
0249 
0250     return NGX_OK;
0251 
0252 found:
0253 
0254     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0255                    "get keepalive peer: using connection %p", c);
0256 
0257     c->idle = 0;
0258     c->sent = 0;
0259     c->log = pc->log;
0260     c->read->log = pc->log;
0261     c->write->log = pc->log;
0262     c->pool->log = pc->log;
0263 
0264     pc->connection = c;
0265     pc->cached = 1;
0266 
0267     return NGX_DONE;
0268 }
0269 
0270 
0271 static void
0272 ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data,
0273     ngx_uint_t state)
0274 {
0275     ngx_http_upstream_keepalive_peer_data_t  *kp = data;
0276     ngx_http_upstream_keepalive_cache_t      *item;
0277 
0278     ngx_queue_t          *q;
0279     ngx_connection_t     *c;
0280     ngx_http_upstream_t  *u;
0281 
0282     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0283                    "free keepalive peer");
0284 
0285     /* cache valid connections */
0286 
0287     u = kp->upstream;
0288     c = pc->connection;
0289 
0290     if (state & NGX_PEER_FAILED
0291         || c == NULL
0292         || c->read->eof
0293         || c->read->error
0294         || c->read->timedout
0295         || c->write->error
0296         || c->write->timedout)
0297     {
0298         goto invalid;
0299     }
0300 
0301     if (!u->keepalive) {
0302         goto invalid;
0303     }
0304 
0305     if (!u->request_body_sent) {
0306         goto invalid;
0307     }
0308 
0309     if (ngx_terminate || ngx_exiting) {
0310         goto invalid;
0311     }
0312 
0313     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
0314         goto invalid;
0315     }
0316 
0317     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0318                    "free keepalive peer: saving connection %p", c);
0319 
0320     if (ngx_queue_empty(&kp->conf->free)) {
0321 
0322         q = ngx_queue_last(&kp->conf->cache);
0323         ngx_queue_remove(q);
0324 
0325         item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
0326 
0327         ngx_http_upstream_keepalive_close(item->connection);
0328 
0329     } else {
0330         q = ngx_queue_head(&kp->conf->free);
0331         ngx_queue_remove(q);
0332 
0333         item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
0334     }
0335 
0336     ngx_queue_insert_head(&kp->conf->cache, q);
0337 
0338     item->connection = c;
0339 
0340     pc->connection = NULL;
0341 
0342     if (c->read->timer_set) {
0343         ngx_del_timer(c->read);
0344     }
0345     if (c->write->timer_set) {
0346         ngx_del_timer(c->write);
0347     }
0348 
0349     c->write->handler = ngx_http_upstream_keepalive_dummy_handler;
0350     c->read->handler = ngx_http_upstream_keepalive_close_handler;
0351 
0352     c->data = item;
0353     c->idle = 1;
0354     c->log = ngx_cycle->log;
0355     c->read->log = ngx_cycle->log;
0356     c->write->log = ngx_cycle->log;
0357     c->pool->log = ngx_cycle->log;
0358 
0359     item->socklen = pc->socklen;
0360     ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);
0361 
0362     if (c->read->ready) {
0363         ngx_http_upstream_keepalive_close_handler(c->read);
0364     }
0365 
0366 invalid:
0367 
0368     kp->original_free_peer(pc, kp->data, state);
0369 }
0370 
0371 
0372 static void
0373 ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev)
0374 {
0375     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
0376                    "keepalive dummy handler");
0377 }
0378 
0379 
0380 static void
0381 ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev)
0382 {
0383     ngx_http_upstream_keepalive_srv_conf_t  *conf;
0384     ngx_http_upstream_keepalive_cache_t     *item;
0385 
0386     int                n;
0387     char               buf[1];
0388     ngx_connection_t  *c;
0389 
0390     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
0391                    "keepalive close handler");
0392 
0393     c = ev->data;
0394 
0395     if (c->close) {
0396         goto close;
0397     }
0398 
0399     n = recv(c->fd, buf, 1, MSG_PEEK);
0400 
0401     if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
0402         ev->ready = 0;
0403 
0404         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
0405             goto close;
0406         }
0407 
0408         return;
0409     }
0410 
0411 close:
0412 
0413     item = c->data;
0414     conf = item->conf;
0415 
0416     ngx_http_upstream_keepalive_close(c);
0417 
0418     ngx_queue_remove(&item->queue);
0419     ngx_queue_insert_head(&conf->free, &item->queue);
0420 }
0421 
0422 
0423 static void
0424 ngx_http_upstream_keepalive_close(ngx_connection_t *c)
0425 {
0426 
0427 #if (NGX_HTTP_SSL)
0428 
0429     if (c->ssl) {
0430         c->ssl->no_wait_shutdown = 1;
0431         c->ssl->no_send_shutdown = 1;
0432 
0433         if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
0434             c->ssl->handler = ngx_http_upstream_keepalive_close;
0435             return;
0436         }
0437     }
0438 
0439 #endif
0440 
0441     ngx_destroy_pool(c->pool);
0442     ngx_close_connection(c);
0443 }
0444 
0445 
0446 #if (NGX_HTTP_SSL)
0447 
0448 static ngx_int_t
0449 ngx_http_upstream_keepalive_set_session(ngx_peer_connection_t *pc, void *data)
0450 {
0451     ngx_http_upstream_keepalive_peer_data_t  *kp = data;
0452 
0453     return kp->original_set_session(pc, kp->data);
0454 }
0455 
0456 
0457 static void
0458 ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc, void *data)
0459 {
0460     ngx_http_upstream_keepalive_peer_data_t  *kp = data;
0461 
0462     kp->original_save_session(pc, kp->data);
0463     return;
0464 }
0465 
0466 #endif
0467 
0468 
0469 static void *
0470 ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf)
0471 {
0472     ngx_http_upstream_keepalive_srv_conf_t  *conf;
0473 
0474     conf = ngx_pcalloc(cf->pool,
0475                        sizeof(ngx_http_upstream_keepalive_srv_conf_t));
0476     if (conf == NULL) {
0477         return NULL;
0478     }
0479 
0480     /*
0481      * set by ngx_pcalloc():
0482      *
0483      *     conf->original_init_upstream = NULL;
0484      *     conf->original_init_peer = NULL;
0485      *     conf->max_cached = 0;
0486      */
0487 
0488     return conf;
0489 }
0490 
0491 
0492 static char *
0493 ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0494 {
0495     ngx_http_upstream_srv_conf_t            *uscf;
0496     ngx_http_upstream_keepalive_srv_conf_t  *kcf = conf;
0497 
0498     ngx_int_t    n;
0499     ngx_str_t   *value;
0500 
0501     if (kcf->max_cached) {
0502         return "is duplicate";
0503     }
0504 
0505     /* read options */
0506 
0507     value = cf->args->elts;
0508 
0509     n = ngx_atoi(value[1].data, value[1].len);
0510 
0511     if (n == NGX_ERROR || n == 0) {
0512         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0513                            "invalid value \"%V\" in \"%V\" directive",
0514                            &value[1], &cmd->name);
0515         return NGX_CONF_ERROR;
0516     }
0517 
0518     kcf->max_cached = n;
0519 
0520     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
0521 
0522     kcf->original_init_upstream = uscf->peer.init_upstream
0523                                   ? uscf->peer.init_upstream
0524                                   : ngx_http_upstream_init_round_robin;
0525 
0526     uscf->peer.init_upstream = ngx_http_upstream_init_keepalive;
0527 
0528     return NGX_CONF_OK;
0529 }