src/stream/ngx_stream_upstream_round_robin.c - nginx source code

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_stream.h>


  8. #define ngx_stream_upstream_tries(p) ((p)->tries                              \
  9.                                       + ((p)->next ? (p)->next->tries : 0))


  10. static ngx_stream_upstream_rr_peer_t *ngx_stream_upstream_get_peer(
  11.     ngx_stream_upstream_rr_peer_data_t *rrp);
  12. static void ngx_stream_upstream_notify_round_robin_peer(
  13.     ngx_peer_connection_t *pc, void *data, ngx_uint_t state);

  14. #if (NGX_STREAM_SSL)

  15. static ngx_int_t ngx_stream_upstream_set_round_robin_peer_session(
  16.     ngx_peer_connection_t *pc, void *data);
  17. static void ngx_stream_upstream_save_round_robin_peer_session(
  18.     ngx_peer_connection_t *pc, void *data);
  19. static ngx_int_t ngx_stream_upstream_empty_set_session(
  20.     ngx_peer_connection_t *pc, void *data);
  21. static void ngx_stream_upstream_empty_save_session(ngx_peer_connection_t *pc,
  22.     void *data);

  23. #endif


  24. ngx_int_t
  25. ngx_stream_upstream_init_round_robin(ngx_conf_t *cf,
  26.     ngx_stream_upstream_srv_conf_t *us)
  27. {
  28.     ngx_url_t                        u;
  29.     ngx_uint_t                       i, j, n, r, w, t;
  30.     ngx_stream_upstream_server_t    *server;
  31.     ngx_stream_upstream_rr_peer_t   *peer, **peerp;
  32.     ngx_stream_upstream_rr_peers_t  *peers, *backup;
  33. #if (NGX_STREAM_UPSTREAM_ZONE)
  34.     ngx_uint_t                       resolve;
  35.     ngx_stream_core_srv_conf_t      *cscf;
  36.     ngx_stream_upstream_rr_peer_t  **rpeerp;
  37. #endif

  38.     us->peer.init = ngx_stream_upstream_init_round_robin_peer;

  39.     if (us->servers) {
  40.         server = us->servers->elts;

  41.         n = 0;
  42.         r = 0;
  43.         w = 0;
  44.         t = 0;

  45. #if (NGX_STREAM_UPSTREAM_ZONE)
  46.         resolve = 0;
  47. #endif

  48.         for (i = 0; i < us->servers->nelts; i++) {

  49. #if (NGX_STREAM_UPSTREAM_ZONE)
  50.             if (server[i].host.len) {
  51.                 resolve = 1;
  52.             }
  53. #endif

  54.             if (server[i].backup) {
  55.                 continue;
  56.             }

  57. #if (NGX_STREAM_UPSTREAM_ZONE)
  58.             if (server[i].host.len) {
  59.                 r++;
  60.                 continue;
  61.             }
  62. #endif

  63.             n += server[i].naddrs;
  64.             w += server[i].naddrs * server[i].weight;

  65.             if (!server[i].down) {
  66.                 t += server[i].naddrs;
  67.             }
  68.         }

  69. #if (NGX_STREAM_UPSTREAM_ZONE)
  70.         if (us->shm_zone) {

  71.             if (resolve && !(us->flags & NGX_STREAM_UPSTREAM_MODIFY)) {
  72.                 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  73.                               "load balancing method does not support"
  74.                               " resolving names at run time in"
  75.                               " upstream \"%V\" in %s:%ui",
  76.                               &us->host, us->file_name, us->line);
  77.                 return NGX_ERROR;
  78.             }

  79.             cscf = ngx_stream_conf_get_module_srv_conf(cf,
  80.                                                        ngx_stream_core_module);

  81.             if (us->resolver == NULL) {
  82.                 us->resolver = cscf->resolver;
  83.             }

  84.             /*
  85.              * Without "resolver_timeout" in stream{} the merged value is unset.
  86.              */
  87.             ngx_conf_merge_msec_value(us->resolver_timeout,
  88.                                       cscf->resolver_timeout, 30000);

  89.             if (resolve
  90.                 && (us->resolver == NULL
  91.                     || us->resolver->connections.nelts == 0))
  92.             {
  93.                 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  94.                               "no resolver defined to resolve names"
  95.                               " at run time in upstream \"%V\" in %s:%ui",
  96.                               &us->host, us->file_name, us->line);
  97.                 return NGX_ERROR;
  98.             }

  99.         } else if (resolve) {

  100.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  101.                           "resolving names at run time requires"
  102.                           " upstream \"%V\" in %s:%ui"
  103.                           " to be in shared memory",
  104.                           &us->host, us->file_name, us->line);
  105.             return NGX_ERROR;
  106.         }
  107. #endif

  108.         if (n + r == 0) {
  109.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  110.                           "no servers in upstream \"%V\" in %s:%ui",
  111.                           &us->host, us->file_name, us->line);
  112.             return NGX_ERROR;
  113.         }

  114.         peers = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peers_t));
  115.         if (peers == NULL) {
  116.             return NGX_ERROR;
  117.         }

  118.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t)
  119.                                      * (n + r));
  120.         if (peer == NULL) {
  121.             return NGX_ERROR;
  122.         }

  123.         peers->single = (n == 1);
  124.         peers->number = n;
  125.         peers->weighted = (w != n);
  126.         peers->total_weight = w;
  127.         peers->tries = t;
  128.         peers->name = &us->host;

  129.         n = 0;
  130.         peerp = &peers->peer;

  131. #if (NGX_STREAM_UPSTREAM_ZONE)
  132.         rpeerp = &peers->resolve;
  133. #endif

  134.         for (i = 0; i < us->servers->nelts; i++) {
  135.             if (server[i].backup) {
  136.                 continue;
  137.             }

  138. #if (NGX_STREAM_UPSTREAM_ZONE)
  139.             if (server[i].host.len) {

  140.                 peer[n].host = ngx_pcalloc(cf->pool,
  141.                                            sizeof(ngx_stream_upstream_host_t));
  142.                 if (peer[n].host == NULL) {
  143.                     return NGX_ERROR;
  144.                 }

  145.                 peer[n].host->name = server[i].host;
  146.                 peer[n].host->service = server[i].service;

  147.                 peer[n].sockaddr = server[i].addrs[0].sockaddr;
  148.                 peer[n].socklen = server[i].addrs[0].socklen;
  149.                 peer[n].name = server[i].addrs[0].name;
  150.                 peer[n].weight = server[i].weight;
  151.                 peer[n].effective_weight = server[i].weight;
  152.                 peer[n].current_weight = 0;
  153.                 peer[n].max_conns = server[i].max_conns;
  154.                 peer[n].max_fails = server[i].max_fails;
  155.                 peer[n].fail_timeout = server[i].fail_timeout;
  156.                 peer[n].down = server[i].down;
  157.                 peer[n].server = server[i].name;
  158.                 *rpeerp = &peer[n];
  159.                 rpeerp = &peer[n].next;
  160.                 n++;

  161.                 continue;
  162.             }
  163. #endif

  164.             for (j = 0; j < server[i].naddrs; j++) {
  165.                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
  166.                 peer[n].socklen = server[i].addrs[j].socklen;
  167.                 peer[n].name = server[i].addrs[j].name;
  168.                 peer[n].weight = server[i].weight;
  169.                 peer[n].effective_weight = server[i].weight;
  170.                 peer[n].current_weight = 0;
  171.                 peer[n].max_conns = server[i].max_conns;
  172.                 peer[n].max_fails = server[i].max_fails;
  173.                 peer[n].fail_timeout = server[i].fail_timeout;
  174.                 peer[n].down = server[i].down;
  175.                 peer[n].server = server[i].name;

  176.                 *peerp = &peer[n];
  177.                 peerp = &peer[n].next;
  178.                 n++;
  179.             }
  180.         }

  181.         us->peer.data = peers;

  182.         /* backup servers */

  183.         n = 0;
  184.         r = 0;
  185.         w = 0;
  186.         t = 0;

  187.         for (i = 0; i < us->servers->nelts; i++) {
  188.             if (!server[i].backup) {
  189.                 continue;
  190.             }

  191. #if (NGX_STREAM_UPSTREAM_ZONE)
  192.             if (server[i].host.len) {
  193.                 r++;
  194.                 continue;
  195.             }
  196. #endif

  197.             n += server[i].naddrs;
  198.             w += server[i].naddrs * server[i].weight;

  199.             if (!server[i].down) {
  200.                 t += server[i].naddrs;
  201.             }
  202.         }

  203.         if (n == 0
  204. #if (NGX_STREAM_UPSTREAM_ZONE)
  205.             && !resolve
  206. #endif
  207.         ) {
  208.             return NGX_OK;
  209.         }

  210.         if (n + r == 0 && !(us->flags & NGX_STREAM_UPSTREAM_BACKUP)) {
  211.             return NGX_OK;
  212.         }

  213.         backup = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peers_t));
  214.         if (backup == NULL) {
  215.             return NGX_ERROR;
  216.         }

  217.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t)
  218.                                      * (n + r));
  219.         if (peer == NULL) {
  220.             return NGX_ERROR;
  221.         }

  222.         if (n > 0) {
  223.             peers->single = 0;
  224.         }

  225.         backup->single = 0;
  226.         backup->number = n;
  227.         backup->weighted = (w != n);
  228.         backup->total_weight = w;
  229.         backup->tries = t;
  230.         backup->name = &us->host;

  231.         n = 0;
  232.         peerp = &backup->peer;

  233. #if (NGX_STREAM_UPSTREAM_ZONE)
  234.         rpeerp = &backup->resolve;
  235. #endif

  236.         for (i = 0; i < us->servers->nelts; i++) {
  237.             if (!server[i].backup) {
  238.                 continue;
  239.             }

  240. #if (NGX_STREAM_UPSTREAM_ZONE)
  241.             if (server[i].host.len) {

  242.                 peer[n].host = ngx_pcalloc(cf->pool,
  243.                                            sizeof(ngx_stream_upstream_host_t));
  244.                 if (peer[n].host == NULL) {
  245.                     return NGX_ERROR;
  246.                 }

  247.                 peer[n].host->name = server[i].host;
  248.                 peer[n].host->service = server[i].service;

  249.                 peer[n].sockaddr = server[i].addrs[0].sockaddr;
  250.                 peer[n].socklen = server[i].addrs[0].socklen;
  251.                 peer[n].name = server[i].addrs[0].name;
  252.                 peer[n].weight = server[i].weight;
  253.                 peer[n].effective_weight = server[i].weight;
  254.                 peer[n].current_weight = 0;
  255.                 peer[n].max_conns = server[i].max_conns;
  256.                 peer[n].max_fails = server[i].max_fails;
  257.                 peer[n].fail_timeout = server[i].fail_timeout;
  258.                 peer[n].down = server[i].down;
  259.                 peer[n].server = server[i].name;
  260.                 *rpeerp = &peer[n];
  261.                 rpeerp = &peer[n].next;
  262.                 n++;

  263.                 continue;
  264.             }
  265. #endif

  266.             for (j = 0; j < server[i].naddrs; j++) {
  267.                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
  268.                 peer[n].socklen = server[i].addrs[j].socklen;
  269.                 peer[n].name = server[i].addrs[j].name;
  270.                 peer[n].weight = server[i].weight;
  271.                 peer[n].effective_weight = server[i].weight;
  272.                 peer[n].current_weight = 0;
  273.                 peer[n].max_conns = server[i].max_conns;
  274.                 peer[n].max_fails = server[i].max_fails;
  275.                 peer[n].fail_timeout = server[i].fail_timeout;
  276.                 peer[n].down = server[i].down;
  277.                 peer[n].server = server[i].name;

  278.                 *peerp = &peer[n];
  279.                 peerp = &peer[n].next;
  280.                 n++;
  281.             }
  282.         }

  283.         peers->next = backup;

  284.         return NGX_OK;
  285.     }


  286.     /* an upstream implicitly defined by proxy_pass, etc. */

  287.     if (us->port == 0) {
  288.         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  289.                       "no port in upstream \"%V\" in %s:%ui",
  290.                       &us->host, us->file_name, us->line);
  291.         return NGX_ERROR;
  292.     }

  293.     ngx_memzero(&u, sizeof(ngx_url_t));

  294.     u.host = us->host;
  295.     u.port = us->port;

  296.     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
  297.         if (u.err) {
  298.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  299.                           "%s in upstream \"%V\" in %s:%ui",
  300.                           u.err, &us->host, us->file_name, us->line);
  301.         }

  302.         return NGX_ERROR;
  303.     }

  304.     n = u.naddrs;

  305.     peers = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peers_t));
  306.     if (peers == NULL) {
  307.         return NGX_ERROR;
  308.     }

  309.     peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t) * n);
  310.     if (peer == NULL) {
  311.         return NGX_ERROR;
  312.     }

  313.     peers->single = (n == 1);
  314.     peers->number = n;
  315.     peers->weighted = 0;
  316.     peers->total_weight = n;
  317.     peers->tries = n;
  318.     peers->name = &us->host;

  319.     peerp = &peers->peer;

  320.     for (i = 0; i < u.naddrs; i++) {
  321.         peer[i].sockaddr = u.addrs[i].sockaddr;
  322.         peer[i].socklen = u.addrs[i].socklen;
  323.         peer[i].name = u.addrs[i].name;
  324.         peer[i].weight = 1;
  325.         peer[i].effective_weight = 1;
  326.         peer[i].current_weight = 0;
  327.         peer[i].max_conns = 0;
  328.         peer[i].max_fails = 1;
  329.         peer[i].fail_timeout = 10;
  330.         *peerp = &peer[i];
  331.         peerp = &peer[i].next;
  332.     }

  333.     us->peer.data = peers;

  334.     /* implicitly defined upstream has no backup servers */

  335.     return NGX_OK;
  336. }


  337. ngx_int_t
  338. ngx_stream_upstream_init_round_robin_peer(ngx_stream_session_t *s,
  339.     ngx_stream_upstream_srv_conf_t *us)
  340. {
  341.     ngx_uint_t                           n;
  342.     ngx_stream_upstream_rr_peer_data_t  *rrp;

  343.     rrp = s->upstream->peer.data;

  344.     if (rrp == NULL) {
  345.         rrp = ngx_palloc(s->connection->pool,
  346.                          sizeof(ngx_stream_upstream_rr_peer_data_t));
  347.         if (rrp == NULL) {
  348.             return NGX_ERROR;
  349.         }

  350.         s->upstream->peer.data = rrp;
  351.     }

  352.     rrp->peers = us->peer.data;
  353.     rrp->current = NULL;

  354.     ngx_stream_upstream_rr_peers_rlock(rrp->peers);

  355. #if (NGX_STREAM_UPSTREAM_ZONE)
  356.     rrp->config = rrp->peers->config ? *rrp->peers->config : 0;
  357. #endif

  358.     n = rrp->peers->number;

  359.     if (rrp->peers->next && rrp->peers->next->number > n) {
  360.         n = rrp->peers->next->number;
  361.     }

  362.     s->upstream->peer.tries = ngx_stream_upstream_tries(rrp->peers);

  363.     ngx_stream_upstream_rr_peers_unlock(rrp->peers);

  364.     if (n <= 8 * sizeof(uintptr_t)) {
  365.         rrp->tried = &rrp->data;
  366.         rrp->data = 0;

  367.     } else {
  368.         n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));

  369.         rrp->tried = ngx_pcalloc(s->connection->pool, n * sizeof(uintptr_t));
  370.         if (rrp->tried == NULL) {
  371.             return NGX_ERROR;
  372.         }
  373.     }

  374.     s->upstream->peer.get = ngx_stream_upstream_get_round_robin_peer;
  375.     s->upstream->peer.free = ngx_stream_upstream_free_round_robin_peer;
  376.     s->upstream->peer.notify = ngx_stream_upstream_notify_round_robin_peer;

  377. #if (NGX_STREAM_SSL)
  378.     s->upstream->peer.set_session =
  379.                              ngx_stream_upstream_set_round_robin_peer_session;
  380.     s->upstream->peer.save_session =
  381.                              ngx_stream_upstream_save_round_robin_peer_session;
  382. #endif

  383.     return NGX_OK;
  384. }


  385. ngx_int_t
  386. ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s,
  387.     ngx_stream_upstream_resolved_t *ur)
  388. {
  389.     u_char                              *p;
  390.     size_t                               len;
  391.     socklen_t                            socklen;
  392.     ngx_uint_t                           i, n;
  393.     struct sockaddr                     *sockaddr;
  394.     ngx_stream_upstream_rr_peer_t       *peer, **peerp;
  395.     ngx_stream_upstream_rr_peers_t      *peers;
  396.     ngx_stream_upstream_rr_peer_data_t  *rrp;

  397.     rrp = s->upstream->peer.data;

  398.     if (rrp == NULL) {
  399.         rrp = ngx_palloc(s->connection->pool,
  400.                          sizeof(ngx_stream_upstream_rr_peer_data_t));
  401.         if (rrp == NULL) {
  402.             return NGX_ERROR;
  403.         }

  404.         s->upstream->peer.data = rrp;
  405.     }

  406.     peers = ngx_pcalloc(s->connection->pool,
  407.                         sizeof(ngx_stream_upstream_rr_peers_t));
  408.     if (peers == NULL) {
  409.         return NGX_ERROR;
  410.     }

  411.     peer = ngx_pcalloc(s->connection->pool,
  412.                        sizeof(ngx_stream_upstream_rr_peer_t) * ur->naddrs);
  413.     if (peer == NULL) {
  414.         return NGX_ERROR;
  415.     }

  416.     peers->single = (ur->naddrs == 1);
  417.     peers->number = ur->naddrs;
  418.     peers->tries = ur->naddrs;
  419.     peers->name = &ur->host;

  420.     if (ur->sockaddr) {
  421.         peer[0].sockaddr = ur->sockaddr;
  422.         peer[0].socklen = ur->socklen;
  423.         peer[0].name = ur->name;
  424.         peer[0].weight = 1;
  425.         peer[0].effective_weight = 1;
  426.         peer[0].current_weight = 0;
  427.         peer[0].max_conns = 0;
  428.         peer[0].max_fails = 1;
  429.         peer[0].fail_timeout = 10;
  430.         peers->peer = peer;

  431.     } else {
  432.         peerp = &peers->peer;

  433.         for (i = 0; i < ur->naddrs; i++) {

  434.             socklen = ur->addrs[i].socklen;

  435.             sockaddr = ngx_palloc(s->connection->pool, socklen);
  436.             if (sockaddr == NULL) {
  437.                 return NGX_ERROR;
  438.             }

  439.             ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
  440.             ngx_inet_set_port(sockaddr, ur->port);

  441.             p = ngx_pnalloc(s->connection->pool, NGX_SOCKADDR_STRLEN);
  442.             if (p == NULL) {
  443.                 return NGX_ERROR;
  444.             }

  445.             len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);

  446.             peer[i].sockaddr = sockaddr;
  447.             peer[i].socklen = socklen;
  448.             peer[i].name.len = len;
  449.             peer[i].name.data = p;
  450.             peer[i].weight = 1;
  451.             peer[i].effective_weight = 1;
  452.             peer[i].current_weight = 0;
  453.             peer[i].max_conns = 0;
  454.             peer[i].max_fails = 1;
  455.             peer[i].fail_timeout = 10;
  456.             *peerp = &peer[i];
  457.             peerp = &peer[i].next;
  458.         }
  459.     }

  460.     rrp->peers = peers;
  461.     rrp->current = NULL;
  462.     rrp->config = 0;

  463.     if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
  464.         rrp->tried = &rrp->data;
  465.         rrp->data = 0;

  466.     } else {
  467.         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
  468.                 / (8 * sizeof(uintptr_t));

  469.         rrp->tried = ngx_pcalloc(s->connection->pool, n * sizeof(uintptr_t));
  470.         if (rrp->tried == NULL) {
  471.             return NGX_ERROR;
  472.         }
  473.     }

  474.     s->upstream->peer.get = ngx_stream_upstream_get_round_robin_peer;
  475.     s->upstream->peer.free = ngx_stream_upstream_free_round_robin_peer;
  476.     s->upstream->peer.tries = ngx_stream_upstream_tries(rrp->peers);
  477. #if (NGX_STREAM_SSL)
  478.     s->upstream->peer.set_session = ngx_stream_upstream_empty_set_session;
  479.     s->upstream->peer.save_session = ngx_stream_upstream_empty_save_session;
  480. #endif

  481.     return NGX_OK;
  482. }


  483. ngx_int_t
  484. ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
  485. {
  486.     ngx_stream_upstream_rr_peer_data_t *rrp = data;

  487.     ngx_int_t                        rc;
  488.     ngx_uint_t                       i, n;
  489.     ngx_stream_upstream_rr_peer_t   *peer;
  490.     ngx_stream_upstream_rr_peers_t  *peers;

  491.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  492.                    "get rr peer, try: %ui", pc->tries);

  493.     pc->connection = NULL;

  494.     peers = rrp->peers;
  495.     ngx_stream_upstream_rr_peers_wlock(peers);

  496. #if (NGX_STREAM_UPSTREAM_ZONE)
  497.     if (peers->config && rrp->config != *peers->config) {
  498.         goto busy;
  499.     }
  500. #endif

  501.     if (peers->single) {
  502.         peer = peers->peer;

  503.         if (peer->down) {
  504.             goto failed;
  505.         }

  506.         if (peer->max_conns && peer->conns >= peer->max_conns) {
  507.             goto failed;
  508.         }

  509.         rrp->current = peer;
  510.         ngx_stream_upstream_rr_peer_ref(peers, peer);

  511.     } else {

  512.         /* there are several peers */

  513.         peer = ngx_stream_upstream_get_peer(rrp);

  514.         if (peer == NULL) {
  515.             goto failed;
  516.         }

  517.         ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  518.                        "get rr peer, current: %p %i",
  519.                        peer, peer->current_weight);
  520.     }

  521.     pc->sockaddr = peer->sockaddr;
  522.     pc->socklen = peer->socklen;
  523.     pc->name = &peer->name;

  524.     peer->conns++;

  525.     ngx_stream_upstream_rr_peers_unlock(peers);

  526.     return NGX_OK;

  527. failed:

  528.     if (peers->next) {

  529.         ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "backup servers");

  530.         rrp->peers = peers->next;

  531.         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
  532.                 / (8 * sizeof(uintptr_t));

  533.         for (i = 0; i < n; i++) {
  534.             rrp->tried[i] = 0;
  535.         }

  536.         ngx_stream_upstream_rr_peers_unlock(peers);

  537.         rc = ngx_stream_upstream_get_round_robin_peer(pc, rrp);

  538.         if (rc != NGX_BUSY) {
  539.             return rc;
  540.         }

  541.         ngx_stream_upstream_rr_peers_wlock(peers);
  542.     }

  543. #if (NGX_STREAM_UPSTREAM_ZONE)
  544. busy:
  545. #endif

  546.     ngx_stream_upstream_rr_peers_unlock(peers);

  547.     pc->name = peers->name;

  548.     return NGX_BUSY;
  549. }


  550. static ngx_stream_upstream_rr_peer_t *
  551. ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp)
  552. {
  553.     time_t                          now;
  554.     uintptr_t                       m;
  555.     ngx_int_t                       total;
  556.     ngx_uint_t                      i, n, p;
  557.     ngx_stream_upstream_rr_peer_t  *peer, *best;

  558.     now = ngx_time();

  559.     best = NULL;
  560.     total = 0;

  561. #if (NGX_SUPPRESS_WARN)
  562.     p = 0;
  563. #endif

  564.     for (peer = rrp->peers->peer, i = 0;
  565.          peer;
  566.          peer = peer->next, i++)
  567.     {
  568.         n = i / (8 * sizeof(uintptr_t));
  569.         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  570.         if (rrp->tried[n] & m) {
  571.             continue;
  572.         }

  573.         if (peer->down) {
  574.             continue;
  575.         }

  576.         if (peer->max_fails
  577.             && peer->fails >= peer->max_fails
  578.             && now - peer->checked <= peer->fail_timeout)
  579.         {
  580.             continue;
  581.         }

  582.         if (peer->max_conns && peer->conns >= peer->max_conns) {
  583.             continue;
  584.         }

  585.         peer->current_weight += peer->effective_weight;
  586.         total += peer->effective_weight;

  587.         if (peer->effective_weight < peer->weight) {
  588.             peer->effective_weight++;
  589.         }

  590.         if (best == NULL || peer->current_weight > best->current_weight) {
  591.             best = peer;
  592.             p = i;
  593.         }
  594.     }

  595.     if (best == NULL) {
  596.         return NULL;
  597.     }

  598.     rrp->current = best;
  599.     ngx_stream_upstream_rr_peer_ref(rrp->peers, best);

  600.     n = p / (8 * sizeof(uintptr_t));
  601.     m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));

  602.     rrp->tried[n] |= m;

  603.     best->current_weight -= total;

  604.     if (now - best->checked > best->fail_timeout) {
  605.         best->checked = now;
  606.     }

  607.     return best;
  608. }


  609. void
  610. ngx_stream_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
  611.     ngx_uint_t state)
  612. {
  613.     ngx_stream_upstream_rr_peer_data_t  *rrp = data;

  614.     time_t                          now;
  615.     ngx_stream_upstream_rr_peer_t  *peer;

  616.     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  617.                    "free rr peer %ui %ui", pc->tries, state);

  618.     peer = rrp->current;

  619.     ngx_stream_upstream_rr_peers_rlock(rrp->peers);
  620.     ngx_stream_upstream_rr_peer_lock(rrp->peers, peer);

  621.     if (rrp->peers->single) {

  622.         if (peer->fails) {
  623.             peer->fails = 0;
  624.         }

  625.         peer->conns--;

  626.         if (ngx_stream_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
  627.             ngx_stream_upstream_rr_peer_unlock(rrp->peers, peer);
  628.         }

  629.         ngx_stream_upstream_rr_peers_unlock(rrp->peers);

  630.         pc->tries = 0;
  631.         return;
  632.     }

  633.     if (state & NGX_PEER_FAILED) {
  634.         now = ngx_time();

  635.         peer->fails++;
  636.         peer->accessed = now;
  637.         peer->checked = now;

  638.         if (peer->max_fails) {
  639.             peer->effective_weight -= peer->weight / peer->max_fails;

  640.             if (peer->fails >= peer->max_fails) {
  641.                 ngx_log_error(NGX_LOG_WARN, pc->log, 0,
  642.                               "upstream server temporarily disabled");
  643.             }
  644.         }

  645.         ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  646.                        "free rr peer failed: %p %i",
  647.                        peer, peer->effective_weight);

  648.         if (peer->effective_weight < 0) {
  649.             peer->effective_weight = 0;
  650.         }

  651.     } else {

  652.         /* mark peer live if check passed */

  653.         if (peer->accessed < peer->checked) {
  654.             peer->fails = 0;
  655.         }
  656.     }

  657.     peer->conns--;

  658.     if (ngx_stream_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
  659.         ngx_stream_upstream_rr_peer_unlock(rrp->peers, peer);
  660.     }

  661.     ngx_stream_upstream_rr_peers_unlock(rrp->peers);

  662.     if (pc->tries) {
  663.         pc->tries--;
  664.     }
  665. }


  666. static void
  667. ngx_stream_upstream_notify_round_robin_peer(ngx_peer_connection_t *pc,
  668.     void *data, ngx_uint_t type)
  669. {
  670.     ngx_stream_upstream_rr_peer_data_t  *rrp = data;

  671.     ngx_stream_upstream_rr_peer_t  *peer;

  672.     peer = rrp->current;

  673.     if (type == NGX_STREAM_UPSTREAM_NOTIFY_CONNECT
  674.         && pc->connection->type == SOCK_STREAM)
  675.     {
  676.         ngx_stream_upstream_rr_peers_rlock(rrp->peers);
  677.         ngx_stream_upstream_rr_peer_lock(rrp->peers, peer);

  678.         if (peer->accessed < peer->checked) {
  679.             peer->fails = 0;
  680.         }

  681.         ngx_stream_upstream_rr_peer_unlock(rrp->peers, peer);
  682.         ngx_stream_upstream_rr_peers_unlock(rrp->peers);
  683.     }
  684. }


  685. #if (NGX_STREAM_SSL)

  686. static ngx_int_t
  687. ngx_stream_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
  688.     void *data)
  689. {
  690.     ngx_stream_upstream_rr_peer_data_t  *rrp = data;

  691.     ngx_int_t                        rc;
  692.     ngx_ssl_session_t               *ssl_session;
  693.     ngx_stream_upstream_rr_peer_t   *peer;
  694. #if (NGX_STREAM_UPSTREAM_ZONE)
  695.     int                              len;
  696.     const u_char                    *p;
  697.     ngx_stream_upstream_rr_peers_t  *peers;
  698.     u_char                           buf[NGX_SSL_MAX_SESSION_SIZE];
  699. #endif

  700.     peer = rrp->current;

  701. #if (NGX_STREAM_UPSTREAM_ZONE)
  702.     peers = rrp->peers;

  703.     if (peers->shpool) {
  704.         ngx_stream_upstream_rr_peers_rlock(peers);
  705.         ngx_stream_upstream_rr_peer_lock(peers, peer);

  706.         if (peer->ssl_session == NULL) {
  707.             ngx_stream_upstream_rr_peer_unlock(peers, peer);
  708.             ngx_stream_upstream_rr_peers_unlock(peers);
  709.             return NGX_OK;
  710.         }

  711.         len = peer->ssl_session_len;

  712.         ngx_memcpy(buf, peer->ssl_session, len);

  713.         ngx_stream_upstream_rr_peer_unlock(peers, peer);
  714.         ngx_stream_upstream_rr_peers_unlock(peers);

  715.         p = buf;
  716.         ssl_session = d2i_SSL_SESSION(NULL, &p, len);

  717.         rc = ngx_ssl_set_session(pc->connection, ssl_session);

  718.         ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  719.                        "set session: %p", ssl_session);

  720.         ngx_ssl_free_session(ssl_session);

  721.         return rc;
  722.     }
  723. #endif

  724.     ssl_session = peer->ssl_session;

  725.     rc = ngx_ssl_set_session(pc->connection, ssl_session);

  726.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  727.                    "set session: %p", ssl_session);

  728.     return rc;
  729. }


  730. static void
  731. ngx_stream_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
  732.     void *data)
  733. {
  734.     ngx_stream_upstream_rr_peer_data_t  *rrp = data;

  735.     ngx_ssl_session_t               *old_ssl_session, *ssl_session;
  736.     ngx_stream_upstream_rr_peer_t   *peer;
  737. #if (NGX_STREAM_UPSTREAM_ZONE)
  738.     int                              len;
  739.     u_char                          *p;
  740.     ngx_stream_upstream_rr_peers_t  *peers;
  741.     u_char                           buf[NGX_SSL_MAX_SESSION_SIZE];
  742. #endif

  743. #if (NGX_STREAM_UPSTREAM_ZONE)
  744.     peers = rrp->peers;

  745.     if (peers->shpool) {

  746.         ssl_session = ngx_ssl_get0_session(pc->connection);

  747.         if (ssl_session == NULL) {
  748.             return;
  749.         }

  750.         ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  751.                        "save session: %p", ssl_session);

  752.         len = i2d_SSL_SESSION(ssl_session, NULL);

  753.         /* do not cache too big session */

  754.         if (len > NGX_SSL_MAX_SESSION_SIZE) {
  755.             return;
  756.         }

  757.         p = buf;
  758.         (void) i2d_SSL_SESSION(ssl_session, &p);

  759.         peer = rrp->current;

  760.         ngx_stream_upstream_rr_peers_rlock(peers);
  761.         ngx_stream_upstream_rr_peer_lock(peers, peer);

  762.         if (len > peer->ssl_session_len) {
  763.             ngx_shmtx_lock(&peers->shpool->mutex);

  764.             if (peer->ssl_session) {
  765.                 ngx_slab_free_locked(peers->shpool, peer->ssl_session);
  766.             }

  767.             peer->ssl_session = ngx_slab_alloc_locked(peers->shpool, len);

  768.             ngx_shmtx_unlock(&peers->shpool->mutex);

  769.             if (peer->ssl_session == NULL) {
  770.                 peer->ssl_session_len = 0;

  771.                 ngx_stream_upstream_rr_peer_unlock(peers, peer);
  772.                 ngx_stream_upstream_rr_peers_unlock(peers);
  773.                 return;
  774.             }

  775.             peer->ssl_session_len = len;
  776.         }

  777.         ngx_memcpy(peer->ssl_session, buf, len);

  778.         ngx_stream_upstream_rr_peer_unlock(peers, peer);
  779.         ngx_stream_upstream_rr_peers_unlock(peers);

  780.         return;
  781.     }
  782. #endif

  783.     ssl_session = ngx_ssl_get_session(pc->connection);

  784.     if (ssl_session == NULL) {
  785.         return;
  786.     }

  787.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  788.                    "save session: %p", ssl_session);

  789.     peer = rrp->current;

  790.     old_ssl_session = peer->ssl_session;
  791.     peer->ssl_session = ssl_session;

  792.     if (old_ssl_session) {

  793.         ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
  794.                        "old session: %p", old_ssl_session);

  795.         /* TODO: may block */

  796.         ngx_ssl_free_session(old_ssl_session);
  797.     }
  798. }


  799. static ngx_int_t
  800. ngx_stream_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
  801. {
  802.     return NGX_OK;
  803. }


  804. static void
  805. ngx_stream_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
  806. {
  807.     return;
  808. }

  809. #endif