Annotation of embedaddon/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c, revision 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>