1 
2 /*
3  * Copyright (C) Igor Sysoev
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 #define ngx_http_upstream_tries(p) ((p)->number                               \
14                                     + ((p)->next ? (p)->next->number : 0))
15 
16 
17 static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
18     ngx_http_upstream_rr_peer_data_t *rrp);
19 
20 #if (NGX_HTTP_SSL)
21 
22 static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
23     void *data);
24 static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
25     void *data);
26 
27 #endif
28 
29 
30 ngx_int_t
ngx_http_upstream_init_round_robin(ngx_conf_t * cf,ngx_http_upstream_srv_conf_t * us)31 ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
32     ngx_http_upstream_srv_conf_t *us)
33 {
34     ngx_url_t                      u;
35     ngx_uint_t                     i, j, n, w;
36     ngx_http_upstream_server_t    *server;
37     ngx_http_upstream_rr_peer_t   *peer, **peerp;
38     ngx_http_upstream_rr_peers_t  *peers, *backup;
39 
40     us->peer.init = ngx_http_upstream_init_round_robin_peer;
41 
42     if (us->servers) {
43         server = us->servers->elts;
44 
45         n = 0;
46         w = 0;
47 
48         for (i = 0; i < us->servers->nelts; i++) {
49             if (server[i].backup) {
50                 continue;
51             }
52 
53             n += server[i].naddrs;
54             w += server[i].naddrs * server[i].weight;
55         }
56 
57         if (n == 0) {
58             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
59                           "no servers in upstream \"%V\" in %s:%ui",
60                           &us->host, us->file_name, us->line);
61             return NGX_ERROR;
62         }
63 
64         peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
65         if (peers == NULL) {
66             return NGX_ERROR;
67         }
68 
69         peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
70         if (peer == NULL) {
71             return NGX_ERROR;
72         }
73 
74         peers->single = (n == 1);
75         peers->number = n;
76         peers->weighted = (w != n);
77         peers->total_weight = w;
78         peers->name = &us->host;
79 
80         n = 0;
81         peerp = &peers->peer;
82 
83         for (i = 0; i < us->servers->nelts; i++) {
84             if (server[i].backup) {
85                 continue;
86             }
87 
88             for (j = 0; j < server[i].naddrs; j++) {
89                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
90                 peer[n].socklen = server[i].addrs[j].socklen;
91                 peer[n].name = server[i].addrs[j].name;
92                 peer[n].weight = server[i].weight;
93                 peer[n].effective_weight = server[i].weight;
94                 peer[n].current_weight = 0;
95                 peer[n].max_conns = server[i].max_conns;
96                 peer[n].max_fails = server[i].max_fails;
97                 peer[n].fail_timeout = server[i].fail_timeout;
98                 peer[n].down = server[i].down;
99                 peer[n].server = server[i].name;
100 
101                 *peerp = &peer[n];
102                 peerp = &peer[n].next;
103                 n++;
104             }
105         }
106 
107         us->peer.data = peers;
108 
109         /* backup servers */
110 
111         n = 0;
112         w = 0;
113 
114         for (i = 0; i < us->servers->nelts; i++) {
115             if (!server[i].backup) {
116                 continue;
117             }
118 
119             n += server[i].naddrs;
120             w += server[i].naddrs * server[i].weight;
121         }
122 
123         if (n == 0) {
124             return NGX_OK;
125         }
126 
127         backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
128         if (backup == NULL) {
129             return NGX_ERROR;
130         }
131 
132         peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
133         if (peer == NULL) {
134             return NGX_ERROR;
135         }
136 
137         peers->single = 0;
138         backup->single = 0;
139         backup->number = n;
140         backup->weighted = (w != n);
141         backup->total_weight = w;
142         backup->name = &us->host;
143 
144         n = 0;
145         peerp = &backup->peer;
146 
147         for (i = 0; i < us->servers->nelts; i++) {
148             if (!server[i].backup) {
149                 continue;
150             }
151 
152             for (j = 0; j < server[i].naddrs; j++) {
153                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
154                 peer[n].socklen = server[i].addrs[j].socklen;
155                 peer[n].name = server[i].addrs[j].name;
156                 peer[n].weight = server[i].weight;
157                 peer[n].effective_weight = server[i].weight;
158                 peer[n].current_weight = 0;
159                 peer[n].max_conns = server[i].max_conns;
160                 peer[n].max_fails = server[i].max_fails;
161                 peer[n].fail_timeout = server[i].fail_timeout;
162                 peer[n].down = server[i].down;
163                 peer[n].server = server[i].name;
164 
165                 *peerp = &peer[n];
166                 peerp = &peer[n].next;
167                 n++;
168             }
169         }
170 
171         peers->next = backup;
172 
173         return NGX_OK;
174     }
175 
176 
177     /* an upstream implicitly defined by proxy_pass, etc. */
178 
179     if (us->port == 0) {
180         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
181                       "no port in upstream \"%V\" in %s:%ui",
182                       &us->host, us->file_name, us->line);
183         return NGX_ERROR;
184     }
185 
186     ngx_memzero(&u, sizeof(ngx_url_t));
187 
188     u.host = us->host;
189     u.port = us->port;
190 
191     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
192         if (u.err) {
193             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
194                           "%s in upstream \"%V\" in %s:%ui",
195                           u.err, &us->host, us->file_name, us->line);
196         }
197 
198         return NGX_ERROR;
199     }
200 
201     n = u.naddrs;
202 
203     peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
204     if (peers == NULL) {
205         return NGX_ERROR;
206     }
207 
208     peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
209     if (peer == NULL) {
210         return NGX_ERROR;
211     }
212 
213     peers->single = (n == 1);
214     peers->number = n;
215     peers->weighted = 0;
216     peers->total_weight = n;
217     peers->name = &us->host;
218 
219     peerp = &peers->peer;
220 
221     for (i = 0; i < u.naddrs; i++) {
222         peer[i].sockaddr = u.addrs[i].sockaddr;
223         peer[i].socklen = u.addrs[i].socklen;
224         peer[i].name = u.addrs[i].name;
225         peer[i].weight = 1;
226         peer[i].effective_weight = 1;
227         peer[i].current_weight = 0;
228         peer[i].max_conns = 0;
229         peer[i].max_fails = 1;
230         peer[i].fail_timeout = 10;
231         *peerp = &peer[i];
232         peerp = &peer[i].next;
233     }
234 
235     us->peer.data = peers;
236 
237     /* implicitly defined upstream has no backup servers */
238 
239     return NGX_OK;
240 }
241 
242 
243 ngx_int_t
ngx_http_upstream_init_round_robin_peer(ngx_http_request_t * r,ngx_http_upstream_srv_conf_t * us)244 ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
245     ngx_http_upstream_srv_conf_t *us)
246 {
247     ngx_uint_t                         n;
248     ngx_http_upstream_rr_peer_data_t  *rrp;
249 
250     rrp = r->upstream->peer.data;
251 
252     if (rrp == NULL) {
253         rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
254         if (rrp == NULL) {
255             return NGX_ERROR;
256         }
257 
258         r->upstream->peer.data = rrp;
259     }
260 
261     rrp->peers = us->peer.data;
262     rrp->current = NULL;
263     rrp->config = 0;
264 
265     n = rrp->peers->number;
266 
267     if (rrp->peers->next && rrp->peers->next->number > n) {
268         n = rrp->peers->next->number;
269     }
270 
271     if (n <= 8 * sizeof(uintptr_t)) {
272         rrp->tried = &rrp->data;
273         rrp->data = 0;
274 
275     } else {
276         n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
277 
278         rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
279         if (rrp->tried == NULL) {
280             return NGX_ERROR;
281         }
282     }
283 
284     r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
285     r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
286     r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
287 #if (NGX_HTTP_SSL)
288     r->upstream->peer.set_session =
289                                ngx_http_upstream_set_round_robin_peer_session;
290     r->upstream->peer.save_session =
291                                ngx_http_upstream_save_round_robin_peer_session;
292 #endif
293 
294     return NGX_OK;
295 }
296 
297 
298 ngx_int_t
ngx_http_upstream_create_round_robin_peer(ngx_http_request_t * r,ngx_http_upstream_resolved_t * ur)299 ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
300     ngx_http_upstream_resolved_t *ur)
301 {
302     u_char                            *p;
303     size_t                             len;
304     socklen_t                          socklen;
305     ngx_uint_t                         i, n;
306     struct sockaddr                   *sockaddr;
307     ngx_http_upstream_rr_peer_t       *peer, **peerp;
308     ngx_http_upstream_rr_peers_t      *peers;
309     ngx_http_upstream_rr_peer_data_t  *rrp;
310 
311     rrp = r->upstream->peer.data;
312 
313     if (rrp == NULL) {
314         rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
315         if (rrp == NULL) {
316             return NGX_ERROR;
317         }
318 
319         r->upstream->peer.data = rrp;
320     }
321 
322     peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t));
323     if (peers == NULL) {
324         return NGX_ERROR;
325     }
326 
327     peer = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peer_t)
328                                 * ur->naddrs);
329     if (peer == NULL) {
330         return NGX_ERROR;
331     }
332 
333     peers->single = (ur->naddrs == 1);
334     peers->number = ur->naddrs;
335     peers->name = &ur->host;
336 
337     if (ur->sockaddr) {
338         peer[0].sockaddr = ur->sockaddr;
339         peer[0].socklen = ur->socklen;
340         peer[0].name = ur->name.data ? ur->name : ur->host;
341         peer[0].weight = 1;
342         peer[0].effective_weight = 1;
343         peer[0].current_weight = 0;
344         peer[0].max_conns = 0;
345         peer[0].max_fails = 1;
346         peer[0].fail_timeout = 10;
347         peers->peer = peer;
348 
349     } else {
350         peerp = &peers->peer;
351 
352         for (i = 0; i < ur->naddrs; i++) {
353 
354             socklen = ur->addrs[i].socklen;
355 
356             sockaddr = ngx_palloc(r->pool, socklen);
357             if (sockaddr == NULL) {
358                 return NGX_ERROR;
359             }
360 
361             ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
362             ngx_inet_set_port(sockaddr, ur->port);
363 
364             p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
365             if (p == NULL) {
366                 return NGX_ERROR;
367             }
368 
369             len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
370 
371             peer[i].sockaddr = sockaddr;
372             peer[i].socklen = socklen;
373             peer[i].name.len = len;
374             peer[i].name.data = p;
375             peer[i].weight = 1;
376             peer[i].effective_weight = 1;
377             peer[i].current_weight = 0;
378             peer[i].max_conns = 0;
379             peer[i].max_fails = 1;
380             peer[i].fail_timeout = 10;
381             *peerp = &peer[i];
382             peerp = &peer[i].next;
383         }
384     }
385 
386     rrp->peers = peers;
387     rrp->current = NULL;
388     rrp->config = 0;
389 
390     if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
391         rrp->tried = &rrp->data;
392         rrp->data = 0;
393 
394     } else {
395         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
396                 / (8 * sizeof(uintptr_t));
397 
398         rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
399         if (rrp->tried == NULL) {
400             return NGX_ERROR;
401         }
402     }
403 
404     r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
405     r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
406     r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
407 #if (NGX_HTTP_SSL)
408     r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
409     r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
410 #endif
411 
412     return NGX_OK;
413 }
414 
415 
416 ngx_int_t
ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t * pc,void * data)417 ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
418 {
419     ngx_http_upstream_rr_peer_data_t  *rrp = data;
420 
421     ngx_int_t                      rc;
422     ngx_uint_t                     i, n;
423     ngx_http_upstream_rr_peer_t   *peer;
424     ngx_http_upstream_rr_peers_t  *peers;
425 
426     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
427                    "get rr peer, try: %ui", pc->tries);
428 
429     pc->cached = 0;
430     pc->connection = NULL;
431 
432     peers = rrp->peers;
433     ngx_http_upstream_rr_peers_wlock(peers);
434 
435     if (peers->single) {
436         peer = peers->peer;
437 
438         if (peer->down) {
439             goto failed;
440         }
441 
442         if (peer->max_conns && peer->conns >= peer->max_conns) {
443             goto failed;
444         }
445 
446         rrp->current = peer;
447 
448     } else {
449 
450         /* there are several peers */
451 
452         peer = ngx_http_upstream_get_peer(rrp);
453 
454         if (peer == NULL) {
455             goto failed;
456         }
457 
458         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
459                        "get rr peer, current: %p %i",
460                        peer, peer->current_weight);
461     }
462 
463     pc->sockaddr = peer->sockaddr;
464     pc->socklen = peer->socklen;
465     pc->name = &peer->name;
466 
467     peer->conns++;
468 
469     ngx_http_upstream_rr_peers_unlock(peers);
470 
471     return NGX_OK;
472 
473 failed:
474 
475     if (peers->next) {
476 
477         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
478 
479         rrp->peers = peers->next;
480 
481         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
482                 / (8 * sizeof(uintptr_t));
483 
484         for (i = 0; i < n; i++) {
485             rrp->tried[i] = 0;
486         }
487 
488         ngx_http_upstream_rr_peers_unlock(peers);
489 
490         rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
491 
492         if (rc != NGX_BUSY) {
493             return rc;
494         }
495 
496         ngx_http_upstream_rr_peers_wlock(peers);
497     }
498 
499     ngx_http_upstream_rr_peers_unlock(peers);
500 
501     pc->name = peers->name;
502 
503     return NGX_BUSY;
504 }
505 
506 
507 static ngx_http_upstream_rr_peer_t *
ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t * rrp)508 ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
509 {
510     time_t                        now;
511     uintptr_t                     m;
512     ngx_int_t                     total;
513     ngx_uint_t                    i, n, p;
514     ngx_http_upstream_rr_peer_t  *peer, *best;
515 
516     now = ngx_time();
517 
518     best = NULL;
519     total = 0;
520 
521 #if (NGX_SUPPRESS_WARN)
522     p = 0;
523 #endif
524 
525     for (peer = rrp->peers->peer, i = 0;
526          peer;
527          peer = peer->next, i++)
528     {
529         n = i / (8 * sizeof(uintptr_t));
530         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
531 
532         if (rrp->tried[n] & m) {
533             continue;
534         }
535 
536         if (peer->down) {
537             continue;
538         }
539 
540         if (peer->max_fails
541             && peer->fails >= peer->max_fails
542             && now - peer->checked <= peer->fail_timeout)
543         {
544             continue;
545         }
546 
547         if (peer->max_conns && peer->conns >= peer->max_conns) {
548             continue;
549         }
550 
551         peer->current_weight += peer->effective_weight;
552         total += peer->effective_weight;
553 
554         if (peer->effective_weight < peer->weight) {
555             peer->effective_weight++;
556         }
557 
558         if (best == NULL || peer->current_weight > best->current_weight) {
559             best = peer;
560             p = i;
561         }
562     }
563 
564     if (best == NULL) {
565         return NULL;
566     }
567 
568     rrp->current = best;
569 
570     n = p / (8 * sizeof(uintptr_t));
571     m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
572 
573     rrp->tried[n] |= m;
574 
575     best->current_weight -= total;
576 
577     if (now - best->checked > best->fail_timeout) {
578         best->checked = now;
579     }
580 
581     return best;
582 }
583 
584 
585 void
ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t * pc,void * data,ngx_uint_t state)586 ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
587     ngx_uint_t state)
588 {
589     ngx_http_upstream_rr_peer_data_t  *rrp = data;
590 
591     time_t                       now;
592     ngx_http_upstream_rr_peer_t  *peer;
593 
594     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
595                    "free rr peer %ui %ui", pc->tries, state);
596 
597     /* TODO: NGX_PEER_KEEPALIVE */
598 
599     peer = rrp->current;
600 
601     ngx_http_upstream_rr_peers_rlock(rrp->peers);
602     ngx_http_upstream_rr_peer_lock(rrp->peers, peer);
603 
604     if (rrp->peers->single) {
605 
606         peer->conns--;
607 
608         ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
609         ngx_http_upstream_rr_peers_unlock(rrp->peers);
610 
611         pc->tries = 0;
612         return;
613     }
614 
615     if (state & NGX_PEER_FAILED) {
616         now = ngx_time();
617 
618         peer->fails++;
619         peer->accessed = now;
620         peer->checked = now;
621 
622         if (peer->max_fails) {
623             peer->effective_weight -= peer->weight / peer->max_fails;
624 
625             if (peer->fails >= peer->max_fails) {
626                 ngx_log_error(NGX_LOG_WARN, pc->log, 0,
627                               "upstream server temporarily disabled");
628             }
629         }
630 
631         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
632                        "free rr peer failed: %p %i",
633                        peer, peer->effective_weight);
634 
635         if (peer->effective_weight < 0) {
636             peer->effective_weight = 0;
637         }
638 
639     } else {
640 
641         /* mark peer live if check passed */
642 
643         if (peer->accessed < peer->checked) {
644             peer->fails = 0;
645         }
646     }
647 
648     peer->conns--;
649 
650     ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
651     ngx_http_upstream_rr_peers_unlock(rrp->peers);
652 
653     if (pc->tries) {
654         pc->tries--;
655     }
656 }
657 
658 
659 #if (NGX_HTTP_SSL)
660 
661 ngx_int_t
ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t * pc,void * data)662 ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
663     void *data)
664 {
665     ngx_http_upstream_rr_peer_data_t  *rrp = data;
666 
667     ngx_int_t                      rc;
668     ngx_ssl_session_t             *ssl_session;
669     ngx_http_upstream_rr_peer_t   *peer;
670 #if (NGX_HTTP_UPSTREAM_ZONE)
671     int                            len;
672 #if OPENSSL_VERSION_NUMBER >= 0x0090707fL
673     const
674 #endif
675     u_char                        *p;
676     ngx_http_upstream_rr_peers_t  *peers;
677     u_char                         buf[NGX_SSL_MAX_SESSION_SIZE];
678 #endif
679 
680     peer = rrp->current;
681 
682 #if (NGX_HTTP_UPSTREAM_ZONE)
683     peers = rrp->peers;
684 
685     if (peers->shpool) {
686         ngx_http_upstream_rr_peers_rlock(peers);
687         ngx_http_upstream_rr_peer_lock(peers, peer);
688 
689         if (peer->ssl_session == NULL) {
690             ngx_http_upstream_rr_peer_unlock(peers, peer);
691             ngx_http_upstream_rr_peers_unlock(peers);
692             return NGX_OK;
693         }
694 
695         len = peer->ssl_session_len;
696 
697         ngx_memcpy(buf, peer->ssl_session, len);
698 
699         ngx_http_upstream_rr_peer_unlock(peers, peer);
700         ngx_http_upstream_rr_peers_unlock(peers);
701 
702         p = buf;
703         ssl_session = d2i_SSL_SESSION(NULL, &p, len);
704 
705         rc = ngx_ssl_set_session(pc->connection, ssl_session);
706 
707         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
708                        "set session: %p", ssl_session);
709 
710         ngx_ssl_free_session(ssl_session);
711 
712         return rc;
713     }
714 #endif
715 
716     ssl_session = peer->ssl_session;
717 
718     rc = ngx_ssl_set_session(pc->connection, ssl_session);
719 
720     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
721                    "set session: %p", ssl_session);
722 
723     return rc;
724 }
725 
726 
727 void
ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t * pc,void * data)728 ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
729     void *data)
730 {
731     ngx_http_upstream_rr_peer_data_t  *rrp = data;
732 
733     ngx_ssl_session_t             *old_ssl_session, *ssl_session;
734     ngx_http_upstream_rr_peer_t   *peer;
735 #if (NGX_HTTP_UPSTREAM_ZONE)
736     int                            len;
737     u_char                        *p;
738     ngx_http_upstream_rr_peers_t  *peers;
739     u_char                         buf[NGX_SSL_MAX_SESSION_SIZE];
740 #endif
741 
742 #if (NGX_HTTP_UPSTREAM_ZONE)
743     peers = rrp->peers;
744 
745     if (peers->shpool) {
746 
747         ssl_session = ngx_ssl_get0_session(pc->connection);
748 
749         if (ssl_session == NULL) {
750             return;
751         }
752 
753         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
754                        "save session: %p", ssl_session);
755 
756         len = i2d_SSL_SESSION(ssl_session, NULL);
757 
758         /* do not cache too big session */
759 
760         if (len > NGX_SSL_MAX_SESSION_SIZE) {
761             return;
762         }
763 
764         p = buf;
765         (void) i2d_SSL_SESSION(ssl_session, &p);
766 
767         peer = rrp->current;
768 
769         ngx_http_upstream_rr_peers_rlock(peers);
770         ngx_http_upstream_rr_peer_lock(peers, peer);
771 
772         if (len > peer->ssl_session_len) {
773             ngx_shmtx_lock(&peers->shpool->mutex);
774 
775             if (peer->ssl_session) {
776                 ngx_slab_free_locked(peers->shpool, peer->ssl_session);
777             }
778 
779             peer->ssl_session = ngx_slab_alloc_locked(peers->shpool, len);
780 
781             ngx_shmtx_unlock(&peers->shpool->mutex);
782 
783             if (peer->ssl_session == NULL) {
784                 peer->ssl_session_len = 0;
785 
786                 ngx_http_upstream_rr_peer_unlock(peers, peer);
787                 ngx_http_upstream_rr_peers_unlock(peers);
788                 return;
789             }
790 
791             peer->ssl_session_len = len;
792         }
793 
794         ngx_memcpy(peer->ssl_session, buf, len);
795 
796         ngx_http_upstream_rr_peer_unlock(peers, peer);
797         ngx_http_upstream_rr_peers_unlock(peers);
798 
799         return;
800     }
801 #endif
802 
803     ssl_session = ngx_ssl_get_session(pc->connection);
804 
805     if (ssl_session == NULL) {
806         return;
807     }
808 
809     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
810                    "save session: %p", ssl_session);
811 
812     peer = rrp->current;
813 
814     old_ssl_session = peer->ssl_session;
815     peer->ssl_session = ssl_session;
816 
817     if (old_ssl_session) {
818 
819         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
820                        "old session: %p", old_ssl_session);
821 
822         /* TODO: may block */
823 
824         ngx_ssl_free_session(old_ssl_session);
825     }
826 }
827 
828 
829 static ngx_int_t
ngx_http_upstream_empty_set_session(ngx_peer_connection_t * pc,void * data)830 ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
831 {
832     return NGX_OK;
833 }
834 
835 
836 static void
ngx_http_upstream_empty_save_session(ngx_peer_connection_t * pc,void * data)837 ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
838 {
839     return;
840 }
841 
842 #endif
843