Annotation of embedaddon/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c, revision 1.1.1.1

1.1       misho       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 {
                     14:     ngx_uint_t                         max_cached;
                     15: 
                     16:     ngx_queue_t                        cache;
                     17:     ngx_queue_t                        free;
                     18: 
                     19:     ngx_http_upstream_init_pt          original_init_upstream;
                     20:     ngx_http_upstream_init_peer_pt     original_init_peer;
                     21: 
                     22: } ngx_http_upstream_keepalive_srv_conf_t;
                     23: 
                     24: 
                     25: typedef struct {
                     26:     ngx_http_upstream_keepalive_srv_conf_t  *conf;
                     27: 
                     28:     ngx_http_upstream_t               *upstream;
                     29: 
                     30:     void                              *data;
                     31: 
                     32:     ngx_event_get_peer_pt              original_get_peer;
                     33:     ngx_event_free_peer_pt             original_free_peer;
                     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: 
                     40: } ngx_http_upstream_keepalive_peer_data_t;
                     41: 
                     42: 
                     43: typedef struct {
                     44:     ngx_http_upstream_keepalive_srv_conf_t  *conf;
                     45: 
                     46:     ngx_queue_t                        queue;
                     47:     ngx_connection_t                  *connection;
                     48: 
                     49:     socklen_t                          socklen;
                     50:     u_char                             sockaddr[NGX_SOCKADDRLEN];
                     51: 
                     52: } ngx_http_upstream_keepalive_cache_t;
                     53: 
                     54: 
                     55: static ngx_int_t ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
                     56:     ngx_http_upstream_srv_conf_t *us);
                     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"),
                     82:       NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,
                     83:       ngx_http_upstream_keepalive,
                     84:       0,
                     85:       0,
                     86:       NULL },
                     87: 
                     88:       ngx_null_command
                     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: 
                    107: ngx_module_t  ngx_http_upstream_keepalive_module = {
                    108:     NGX_MODULE_V1,
                    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 */
                    119:     NGX_MODULE_V1_PADDING
                    120: };
                    121: 
                    122: 
                    123: static ngx_int_t
                    124: ngx_http_upstream_init_keepalive(ngx_conf_t *cf,
                    125:     ngx_http_upstream_srv_conf_t *us)
                    126: {
                    127:     ngx_uint_t                               i;
                    128:     ngx_http_upstream_keepalive_srv_conf_t  *kcf;
                    129:     ngx_http_upstream_keepalive_cache_t     *cached;
                    130: 
                    131:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                    132:                    "init keepalive");
                    133: 
                    134:     kcf = ngx_http_conf_upstream_srv_conf(us,
                    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,
                    148:                 sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached);
                    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,
                    167:     ngx_http_upstream_srv_conf_t *us)
                    168: {
                    169:     ngx_http_upstream_keepalive_peer_data_t  *kp;
                    170:     ngx_http_upstream_keepalive_srv_conf_t   *kcf;
                    171: 
                    172:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    173:                    "init keepalive peer");
                    174: 
                    175:     kcf = ngx_http_conf_upstream_srv_conf(us,
                    176:                                           ngx_http_upstream_keepalive_module);
                    177: 
                    178:     kp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_keepalive_peer_data_t));
                    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;
                    190:     kp->original_get_peer = r->upstream->peer.get;
                    191:     kp->original_free_peer = r->upstream->peer.free;
                    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: {
                    211:     ngx_http_upstream_keepalive_peer_data_t  *kp = data;
                    212:     ngx_http_upstream_keepalive_cache_t      *item;
                    213: 
                    214:     ngx_int_t          rc;
                    215:     ngx_queue_t       *q, *cache;
                    216:     ngx_connection_t  *c;
                    217: 
                    218:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                    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:     {
                    237:         item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
                    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: 
                    247:             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                    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: {
                    271:     ngx_http_upstream_keepalive_peer_data_t  *kp = data;
                    272:     ngx_http_upstream_keepalive_cache_t      *item;
                    273: 
                    274:     ngx_queue_t          *q;
                    275:     ngx_connection_t     *c;
                    276:     ngx_http_upstream_t  *u;
                    277: 
                    278:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                    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: 
                    305:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                    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: 
                    313:         item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
                    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: 
                    321:         item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
                    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: {
                    362:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
                    363:                    "keepalive dummy handler");
                    364: }
                    365: 
                    366: 
                    367: static void
                    368: ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev)
                    369: {
                    370:     ngx_http_upstream_keepalive_srv_conf_t  *conf;
                    371:     ngx_http_upstream_keepalive_cache_t     *item;
                    372: 
                    373:     int                n;
                    374:     char               buf[1];
                    375:     ngx_connection_t  *c;
                    376: 
                    377:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
                    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: 
                    428:     ngx_destroy_pool(c->pool);
                    429:     ngx_close_connection(c);
                    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: {
                    438:     ngx_http_upstream_keepalive_peer_data_t  *kp = data;
                    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: {
                    447:     ngx_http_upstream_keepalive_peer_data_t  *kp = data;
                    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: {
                    459:     ngx_http_upstream_keepalive_srv_conf_t  *conf;
                    460: 
                    461:     conf = ngx_pcalloc(cf->pool,
                    462:                        sizeof(ngx_http_upstream_keepalive_srv_conf_t));
                    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: {
                    483:     ngx_http_upstream_srv_conf_t            *uscf;
                    484:     ngx_http_upstream_keepalive_srv_conf_t  *kcf;
                    485: 
                    486:     ngx_int_t    n;
                    487:     ngx_str_t   *value;
                    488:     ngx_uint_t   i;
                    489: 
                    490:     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
                    491: 
                    492:     kcf = ngx_http_conf_upstream_srv_conf(uscf,
                    493:                                           ngx_http_upstream_keepalive_module);
                    494: 
                    495:     if (kcf->original_init_upstream) {
                    496:         return "is duplicate";
                    497:     }
                    498: 
                    499:     kcf->original_init_upstream = uscf->peer.init_upstream
                    500:                                   ? uscf->peer.init_upstream
                    501:                                   : ngx_http_upstream_init_round_robin;
                    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) {
                    512:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 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) {
                    523:             ngx_conf_log_error(NGX_LOG_WARN, cf, 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: 
                    535:     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    536:                        "invalid parameter \"%V\"", &value[i]);
                    537: 
                    538:     return NGX_CONF_ERROR;
                    539: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>