Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
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 #define ngx_http_upstream_tries(p) ((p)->number                               \
0014                                     + ((p)->next ? (p)->next->number : 0))
0015 
0016 
0017 static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
0018     ngx_http_upstream_rr_peer_data_t *rrp);
0019 
0020 #if (NGX_HTTP_SSL)
0021 
0022 static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
0023     void *data);
0024 static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
0025     void *data);
0026 
0027 #endif
0028 
0029 
0030 ngx_int_t
0031 ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
0032     ngx_http_upstream_srv_conf_t *us)
0033 {
0034     ngx_url_t                      u;
0035     ngx_uint_t                     i, j, n, w;
0036     ngx_http_upstream_server_t    *server;
0037     ngx_http_upstream_rr_peer_t   *peer, **peerp;
0038     ngx_http_upstream_rr_peers_t  *peers, *backup;
0039 
0040     us->peer.init = ngx_http_upstream_init_round_robin_peer;
0041 
0042     if (us->servers) {
0043         server = us->servers->elts;
0044 
0045         n = 0;
0046         w = 0;
0047 
0048         for (i = 0; i < us->servers->nelts; i++) {
0049             if (server[i].backup) {
0050                 continue;
0051             }
0052 
0053             n += server[i].naddrs;
0054             w += server[i].naddrs * server[i].weight;
0055         }
0056 
0057         if (n == 0) {
0058             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
0059                           "no servers in upstream \"%V\" in %s:%ui",
0060                           &us->host, us->file_name, us->line);
0061             return NGX_ERROR;
0062         }
0063 
0064         peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
0065         if (peers == NULL) {
0066             return NGX_ERROR;
0067         }
0068 
0069         peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
0070         if (peer == NULL) {
0071             return NGX_ERROR;
0072         }
0073 
0074         peers->single = (n == 1);
0075         peers->number = n;
0076         peers->weighted = (w != n);
0077         peers->total_weight = w;
0078         peers->name = &us->host;
0079 
0080         n = 0;
0081         peerp = &peers->peer;
0082 
0083         for (i = 0; i < us->servers->nelts; i++) {
0084             if (server[i].backup) {
0085                 continue;
0086             }
0087 
0088             for (j = 0; j < server[i].naddrs; j++) {
0089                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
0090                 peer[n].socklen = server[i].addrs[j].socklen;
0091                 peer[n].name = server[i].addrs[j].name;
0092                 peer[n].weight = server[i].weight;
0093                 peer[n].effective_weight = server[i].weight;
0094                 peer[n].current_weight = 0;
0095                 peer[n].max_conns = server[i].max_conns;
0096                 peer[n].max_fails = server[i].max_fails;
0097                 peer[n].fail_timeout = server[i].fail_timeout;
0098                 peer[n].down = server[i].down;
0099                 peer[n].server = server[i].name;
0100 
0101                 *peerp = &peer[n];
0102                 peerp = &peer[n].next;
0103                 n++;
0104             }
0105         }
0106 
0107         us->peer.data = peers;
0108 
0109         /* backup servers */
0110 
0111         n = 0;
0112         w = 0;
0113 
0114         for (i = 0; i < us->servers->nelts; i++) {
0115             if (!server[i].backup) {
0116                 continue;
0117             }
0118 
0119             n += server[i].naddrs;
0120             w += server[i].naddrs * server[i].weight;
0121         }
0122 
0123         if (n == 0) {
0124             return NGX_OK;
0125         }
0126 
0127         backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
0128         if (backup == NULL) {
0129             return NGX_ERROR;
0130         }
0131 
0132         peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
0133         if (peer == NULL) {
0134             return NGX_ERROR;
0135         }
0136 
0137         peers->single = 0;
0138         backup->single = 0;
0139         backup->number = n;
0140         backup->weighted = (w != n);
0141         backup->total_weight = w;
0142         backup->name = &us->host;
0143 
0144         n = 0;
0145         peerp = &backup->peer;
0146 
0147         for (i = 0; i < us->servers->nelts; i++) {
0148             if (!server[i].backup) {
0149                 continue;
0150             }
0151 
0152             for (j = 0; j < server[i].naddrs; j++) {
0153                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
0154                 peer[n].socklen = server[i].addrs[j].socklen;
0155                 peer[n].name = server[i].addrs[j].name;
0156                 peer[n].weight = server[i].weight;
0157                 peer[n].effective_weight = server[i].weight;
0158                 peer[n].current_weight = 0;
0159                 peer[n].max_conns = server[i].max_conns;
0160                 peer[n].max_fails = server[i].max_fails;
0161                 peer[n].fail_timeout = server[i].fail_timeout;
0162                 peer[n].down = server[i].down;
0163                 peer[n].server = server[i].name;
0164 
0165                 *peerp = &peer[n];
0166                 peerp = &peer[n].next;
0167                 n++;
0168             }
0169         }
0170 
0171         peers->next = backup;
0172 
0173         return NGX_OK;
0174     }
0175 
0176 
0177     /* an upstream implicitly defined by proxy_pass, etc. */
0178 
0179     if (us->port == 0) {
0180         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
0181                       "no port in upstream \"%V\" in %s:%ui",
0182                       &us->host, us->file_name, us->line);
0183         return NGX_ERROR;
0184     }
0185 
0186     ngx_memzero(&u, sizeof(ngx_url_t));
0187 
0188     u.host = us->host;
0189     u.port = us->port;
0190 
0191     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
0192         if (u.err) {
0193             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
0194                           "%s in upstream \"%V\" in %s:%ui",
0195                           u.err, &us->host, us->file_name, us->line);
0196         }
0197 
0198         return NGX_ERROR;
0199     }
0200 
0201     n = u.naddrs;
0202 
0203     peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
0204     if (peers == NULL) {
0205         return NGX_ERROR;
0206     }
0207 
0208     peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
0209     if (peer == NULL) {
0210         return NGX_ERROR;
0211     }
0212 
0213     peers->single = (n == 1);
0214     peers->number = n;
0215     peers->weighted = 0;
0216     peers->total_weight = n;
0217     peers->name = &us->host;
0218 
0219     peerp = &peers->peer;
0220 
0221     for (i = 0; i < u.naddrs; i++) {
0222         peer[i].sockaddr = u.addrs[i].sockaddr;
0223         peer[i].socklen = u.addrs[i].socklen;
0224         peer[i].name = u.addrs[i].name;
0225         peer[i].weight = 1;
0226         peer[i].effective_weight = 1;
0227         peer[i].current_weight = 0;
0228         peer[i].max_conns = 0;
0229         peer[i].max_fails = 1;
0230         peer[i].fail_timeout = 10;
0231         *peerp = &peer[i];
0232         peerp = &peer[i].next;
0233     }
0234 
0235     us->peer.data = peers;
0236 
0237     /* implicitly defined upstream has no backup servers */
0238 
0239     return NGX_OK;
0240 }
0241 
0242 
0243 ngx_int_t
0244 ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
0245     ngx_http_upstream_srv_conf_t *us)
0246 {
0247     ngx_uint_t                         n;
0248     ngx_http_upstream_rr_peer_data_t  *rrp;
0249 
0250     rrp = r->upstream->peer.data;
0251 
0252     if (rrp == NULL) {
0253         rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
0254         if (rrp == NULL) {
0255             return NGX_ERROR;
0256         }
0257 
0258         r->upstream->peer.data = rrp;
0259     }
0260 
0261     rrp->peers = us->peer.data;
0262     rrp->current = NULL;
0263     rrp->config = 0;
0264 
0265     n = rrp->peers->number;
0266 
0267     if (rrp->peers->next && rrp->peers->next->number > n) {
0268         n = rrp->peers->next->number;
0269     }
0270 
0271     if (n <= 8 * sizeof(uintptr_t)) {
0272         rrp->tried = &rrp->data;
0273         rrp->data = 0;
0274 
0275     } else {
0276         n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
0277 
0278         rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
0279         if (rrp->tried == NULL) {
0280             return NGX_ERROR;
0281         }
0282     }
0283 
0284     r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
0285     r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
0286     r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
0287 #if (NGX_HTTP_SSL)
0288     r->upstream->peer.set_session =
0289                                ngx_http_upstream_set_round_robin_peer_session;
0290     r->upstream->peer.save_session =
0291                                ngx_http_upstream_save_round_robin_peer_session;
0292 #endif
0293 
0294     return NGX_OK;
0295 }
0296 
0297 
0298 ngx_int_t
0299 ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
0300     ngx_http_upstream_resolved_t *ur)
0301 {
0302     u_char                            *p;
0303     size_t                             len;
0304     socklen_t                          socklen;
0305     ngx_uint_t                         i, n;
0306     struct sockaddr                   *sockaddr;
0307     ngx_http_upstream_rr_peer_t       *peer, **peerp;
0308     ngx_http_upstream_rr_peers_t      *peers;
0309     ngx_http_upstream_rr_peer_data_t  *rrp;
0310 
0311     rrp = r->upstream->peer.data;
0312 
0313     if (rrp == NULL) {
0314         rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
0315         if (rrp == NULL) {
0316             return NGX_ERROR;
0317         }
0318 
0319         r->upstream->peer.data = rrp;
0320     }
0321 
0322     peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t));
0323     if (peers == NULL) {
0324         return NGX_ERROR;
0325     }
0326 
0327     peer = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peer_t)
0328                                 * ur->naddrs);
0329     if (peer == NULL) {
0330         return NGX_ERROR;
0331     }
0332 
0333     peers->single = (ur->naddrs == 1);
0334     peers->number = ur->naddrs;
0335     peers->name = &ur->host;
0336 
0337     if (ur->sockaddr) {
0338         peer[0].sockaddr = ur->sockaddr;
0339         peer[0].socklen = ur->socklen;
0340         peer[0].name = ur->name.data ? ur->name : ur->host;
0341         peer[0].weight = 1;
0342         peer[0].effective_weight = 1;
0343         peer[0].current_weight = 0;
0344         peer[0].max_conns = 0;
0345         peer[0].max_fails = 1;
0346         peer[0].fail_timeout = 10;
0347         peers->peer = peer;
0348 
0349     } else {
0350         peerp = &peers->peer;
0351 
0352         for (i = 0; i < ur->naddrs; i++) {
0353 
0354             socklen = ur->addrs[i].socklen;
0355 
0356             sockaddr = ngx_palloc(r->pool, socklen);
0357             if (sockaddr == NULL) {
0358                 return NGX_ERROR;
0359             }
0360 
0361             ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
0362             ngx_inet_set_port(sockaddr, ur->port);
0363 
0364             p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
0365             if (p == NULL) {
0366                 return NGX_ERROR;
0367             }
0368 
0369             len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
0370 
0371             peer[i].sockaddr = sockaddr;
0372             peer[i].socklen = socklen;
0373             peer[i].name.len = len;
0374             peer[i].name.data = p;
0375             peer[i].weight = 1;
0376             peer[i].effective_weight = 1;
0377             peer[i].current_weight = 0;
0378             peer[i].max_conns = 0;
0379             peer[i].max_fails = 1;
0380             peer[i].fail_timeout = 10;
0381             *peerp = &peer[i];
0382             peerp = &peer[i].next;
0383         }
0384     }
0385 
0386     rrp->peers = peers;
0387     rrp->current = NULL;
0388     rrp->config = 0;
0389 
0390     if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
0391         rrp->tried = &rrp->data;
0392         rrp->data = 0;
0393 
0394     } else {
0395         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
0396                 / (8 * sizeof(uintptr_t));
0397 
0398         rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
0399         if (rrp->tried == NULL) {
0400             return NGX_ERROR;
0401         }
0402     }
0403 
0404     r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
0405     r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
0406     r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
0407 #if (NGX_HTTP_SSL)
0408     r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
0409     r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
0410 #endif
0411 
0412     return NGX_OK;
0413 }
0414 
0415 
0416 ngx_int_t
0417 ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
0418 {
0419     ngx_http_upstream_rr_peer_data_t  *rrp = data;
0420 
0421     ngx_int_t                      rc;
0422     ngx_uint_t                     i, n;
0423     ngx_http_upstream_rr_peer_t   *peer;
0424     ngx_http_upstream_rr_peers_t  *peers;
0425 
0426     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0427                    "get rr peer, try: %ui", pc->tries);
0428 
0429     pc->cached = 0;
0430     pc->connection = NULL;
0431 
0432     peers = rrp->peers;
0433     ngx_http_upstream_rr_peers_wlock(peers);
0434 
0435     if (peers->single) {
0436         peer = peers->peer;
0437 
0438         if (peer->down) {
0439             goto failed;
0440         }
0441 
0442         if (peer->max_conns && peer->conns >= peer->max_conns) {
0443             goto failed;
0444         }
0445 
0446         rrp->current = peer;
0447 
0448     } else {
0449 
0450         /* there are several peers */
0451 
0452         peer = ngx_http_upstream_get_peer(rrp);
0453 
0454         if (peer == NULL) {
0455             goto failed;
0456         }
0457 
0458         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0459                        "get rr peer, current: %p %i",
0460                        peer, peer->current_weight);
0461     }
0462 
0463     pc->sockaddr = peer->sockaddr;
0464     pc->socklen = peer->socklen;
0465     pc->name = &peer->name;
0466 
0467     peer->conns++;
0468 
0469     ngx_http_upstream_rr_peers_unlock(peers);
0470 
0471     return NGX_OK;
0472 
0473 failed:
0474 
0475     if (peers->next) {
0476 
0477         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
0478 
0479         rrp->peers = peers->next;
0480 
0481         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
0482                 / (8 * sizeof(uintptr_t));
0483 
0484         for (i = 0; i < n; i++) {
0485             rrp->tried[i] = 0;
0486         }
0487 
0488         ngx_http_upstream_rr_peers_unlock(peers);
0489 
0490         rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
0491 
0492         if (rc != NGX_BUSY) {
0493             return rc;
0494         }
0495 
0496         ngx_http_upstream_rr_peers_wlock(peers);
0497     }
0498 
0499     ngx_http_upstream_rr_peers_unlock(peers);
0500 
0501     pc->name = peers->name;
0502 
0503     return NGX_BUSY;
0504 }
0505 
0506 
0507 static ngx_http_upstream_rr_peer_t *
0508 ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
0509 {
0510     time_t                        now;
0511     uintptr_t                     m;
0512     ngx_int_t                     total;
0513     ngx_uint_t                    i, n, p;
0514     ngx_http_upstream_rr_peer_t  *peer, *best;
0515 
0516     now = ngx_time();
0517 
0518     best = NULL;
0519     total = 0;
0520 
0521 #if (NGX_SUPPRESS_WARN)
0522     p = 0;
0523 #endif
0524 
0525     for (peer = rrp->peers->peer, i = 0;
0526          peer;
0527          peer = peer->next, i++)
0528     {
0529         n = i / (8 * sizeof(uintptr_t));
0530         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
0531 
0532         if (rrp->tried[n] & m) {
0533             continue;
0534         }
0535 
0536         if (peer->down) {
0537             continue;
0538         }
0539 
0540         if (peer->max_fails
0541             && peer->fails >= peer->max_fails
0542             && now - peer->checked <= peer->fail_timeout)
0543         {
0544             continue;
0545         }
0546 
0547         if (peer->max_conns && peer->conns >= peer->max_conns) {
0548             continue;
0549         }
0550 
0551         peer->current_weight += peer->effective_weight;
0552         total += peer->effective_weight;
0553 
0554         if (peer->effective_weight < peer->weight) {
0555             peer->effective_weight++;
0556         }
0557 
0558         if (best == NULL || peer->current_weight > best->current_weight) {
0559             best = peer;
0560             p = i;
0561         }
0562     }
0563 
0564     if (best == NULL) {
0565         return NULL;
0566     }
0567 
0568     rrp->current = best;
0569 
0570     n = p / (8 * sizeof(uintptr_t));
0571     m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
0572 
0573     rrp->tried[n] |= m;
0574 
0575     best->current_weight -= total;
0576 
0577     if (now - best->checked > best->fail_timeout) {
0578         best->checked = now;
0579     }
0580 
0581     return best;
0582 }
0583 
0584 
0585 void
0586 ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
0587     ngx_uint_t state)
0588 {
0589     ngx_http_upstream_rr_peer_data_t  *rrp = data;
0590 
0591     time_t                       now;
0592     ngx_http_upstream_rr_peer_t  *peer;
0593 
0594     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0595                    "free rr peer %ui %ui", pc->tries, state);
0596 
0597     /* TODO: NGX_PEER_KEEPALIVE */
0598 
0599     peer = rrp->current;
0600 
0601     ngx_http_upstream_rr_peers_rlock(rrp->peers);
0602     ngx_http_upstream_rr_peer_lock(rrp->peers, peer);
0603 
0604     if (rrp->peers->single) {
0605 
0606         peer->conns--;
0607 
0608         ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
0609         ngx_http_upstream_rr_peers_unlock(rrp->peers);
0610 
0611         pc->tries = 0;
0612         return;
0613     }
0614 
0615     if (state & NGX_PEER_FAILED) {
0616         now = ngx_time();
0617 
0618         peer->fails++;
0619         peer->accessed = now;
0620         peer->checked = now;
0621 
0622         if (peer->max_fails) {
0623             peer->effective_weight -= peer->weight / peer->max_fails;
0624 
0625             if (peer->fails >= peer->max_fails) {
0626                 ngx_log_error(NGX_LOG_WARN, pc->log, 0,
0627                               "upstream server temporarily disabled");
0628             }
0629         }
0630 
0631         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0632                        "free rr peer failed: %p %i",
0633                        peer, peer->effective_weight);
0634 
0635         if (peer->effective_weight < 0) {
0636             peer->effective_weight = 0;
0637         }
0638 
0639     } else {
0640 
0641         /* mark peer live if check passed */
0642 
0643         if (peer->accessed < peer->checked) {
0644             peer->fails = 0;
0645         }
0646     }
0647 
0648     peer->conns--;
0649 
0650     ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
0651     ngx_http_upstream_rr_peers_unlock(rrp->peers);
0652 
0653     if (pc->tries) {
0654         pc->tries--;
0655     }
0656 }
0657 
0658 
0659 #if (NGX_HTTP_SSL)
0660 
0661 ngx_int_t
0662 ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
0663     void *data)
0664 {
0665     ngx_http_upstream_rr_peer_data_t  *rrp = data;
0666 
0667     ngx_int_t                      rc;
0668     ngx_ssl_session_t             *ssl_session;
0669     ngx_http_upstream_rr_peer_t   *peer;
0670 #if (NGX_HTTP_UPSTREAM_ZONE)
0671     int                            len;
0672 #if OPENSSL_VERSION_NUMBER >= 0x0090707fL
0673     const
0674 #endif
0675     u_char                        *p;
0676     ngx_http_upstream_rr_peers_t  *peers;
0677     u_char                         buf[NGX_SSL_MAX_SESSION_SIZE];
0678 #endif
0679 
0680     peer = rrp->current;
0681 
0682 #if (NGX_HTTP_UPSTREAM_ZONE)
0683     peers = rrp->peers;
0684 
0685     if (peers->shpool) {
0686         ngx_http_upstream_rr_peers_rlock(peers);
0687         ngx_http_upstream_rr_peer_lock(peers, peer);
0688 
0689         if (peer->ssl_session == NULL) {
0690             ngx_http_upstream_rr_peer_unlock(peers, peer);
0691             ngx_http_upstream_rr_peers_unlock(peers);
0692             return NGX_OK;
0693         }
0694 
0695         len = peer->ssl_session_len;
0696 
0697         ngx_memcpy(buf, peer->ssl_session, len);
0698 
0699         ngx_http_upstream_rr_peer_unlock(peers, peer);
0700         ngx_http_upstream_rr_peers_unlock(peers);
0701 
0702         p = buf;
0703         ssl_session = d2i_SSL_SESSION(NULL, &p, len);
0704 
0705         rc = ngx_ssl_set_session(pc->connection, ssl_session);
0706 
0707         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0708                        "set session: %p", ssl_session);
0709 
0710         ngx_ssl_free_session(ssl_session);
0711 
0712         return rc;
0713     }
0714 #endif
0715 
0716     ssl_session = peer->ssl_session;
0717 
0718     rc = ngx_ssl_set_session(pc->connection, ssl_session);
0719 
0720     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0721                    "set session: %p", ssl_session);
0722 
0723     return rc;
0724 }
0725 
0726 
0727 void
0728 ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
0729     void *data)
0730 {
0731     ngx_http_upstream_rr_peer_data_t  *rrp = data;
0732 
0733     ngx_ssl_session_t             *old_ssl_session, *ssl_session;
0734     ngx_http_upstream_rr_peer_t   *peer;
0735 #if (NGX_HTTP_UPSTREAM_ZONE)
0736     int                            len;
0737     u_char                        *p;
0738     ngx_http_upstream_rr_peers_t  *peers;
0739     u_char                         buf[NGX_SSL_MAX_SESSION_SIZE];
0740 #endif
0741 
0742 #if (NGX_HTTP_UPSTREAM_ZONE)
0743     peers = rrp->peers;
0744 
0745     if (peers->shpool) {
0746 
0747         ssl_session = ngx_ssl_get0_session(pc->connection);
0748 
0749         if (ssl_session == NULL) {
0750             return;
0751         }
0752 
0753         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0754                        "save session: %p", ssl_session);
0755 
0756         len = i2d_SSL_SESSION(ssl_session, NULL);
0757 
0758         /* do not cache too big session */
0759 
0760         if (len > NGX_SSL_MAX_SESSION_SIZE) {
0761             return;
0762         }
0763 
0764         p = buf;
0765         (void) i2d_SSL_SESSION(ssl_session, &p);
0766 
0767         peer = rrp->current;
0768 
0769         ngx_http_upstream_rr_peers_rlock(peers);
0770         ngx_http_upstream_rr_peer_lock(peers, peer);
0771 
0772         if (len > peer->ssl_session_len) {
0773             ngx_shmtx_lock(&peers->shpool->mutex);
0774 
0775             if (peer->ssl_session) {
0776                 ngx_slab_free_locked(peers->shpool, peer->ssl_session);
0777             }
0778 
0779             peer->ssl_session = ngx_slab_alloc_locked(peers->shpool, len);
0780 
0781             ngx_shmtx_unlock(&peers->shpool->mutex);
0782 
0783             if (peer->ssl_session == NULL) {
0784                 peer->ssl_session_len = 0;
0785 
0786                 ngx_http_upstream_rr_peer_unlock(peers, peer);
0787                 ngx_http_upstream_rr_peers_unlock(peers);
0788                 return;
0789             }
0790 
0791             peer->ssl_session_len = len;
0792         }
0793 
0794         ngx_memcpy(peer->ssl_session, buf, len);
0795 
0796         ngx_http_upstream_rr_peer_unlock(peers, peer);
0797         ngx_http_upstream_rr_peers_unlock(peers);
0798 
0799         return;
0800     }
0801 #endif
0802 
0803     ssl_session = ngx_ssl_get_session(pc->connection);
0804 
0805     if (ssl_session == NULL) {
0806         return;
0807     }
0808 
0809     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0810                    "save session: %p", ssl_session);
0811 
0812     peer = rrp->current;
0813 
0814     old_ssl_session = peer->ssl_session;
0815     peer->ssl_session = ssl_session;
0816 
0817     if (old_ssl_session) {
0818 
0819         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
0820                        "old session: %p", old_ssl_session);
0821 
0822         /* TODO: may block */
0823 
0824         ngx_ssl_free_session(old_ssl_session);
0825     }
0826 }
0827 
0828 
0829 static ngx_int_t
0830 ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
0831 {
0832     return NGX_OK;
0833 }
0834 
0835 
0836 static void
0837 ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
0838 {
0839     return;
0840 }
0841 
0842 #endif