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