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
17static 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
22static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
23    void *data);
24static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
25    void *data);
26
27#endif
28
29
30ngx_int_t
31ngx_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
243ngx_int_t
244ngx_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
298ngx_int_t
299ngx_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
416ngx_int_t
417ngx_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
473failed:
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
507static ngx_http_upstream_rr_peer_t *
508ngx_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
585void
586ngx_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
661ngx_int_t
662ngx_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
727void
728ngx_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 = SSL_get0_session(pc->connection->ssl->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
829static ngx_int_t
830ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
831{
832    return NGX_OK;
833}
834
835
836static void
837ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
838{
839    return;
840}
841
842#endif
843