src/http/ngx_http_upstream_round_robin.c - nginx-1.31.3 nginx/ @ 42f8df65b

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_http.h>
  8. #include <ngx_md5.h>


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


  11. #if (NGX_HTTP_UPSTREAM_SID)
  12. static ngx_int_t ngx_http_upstream_create_sid(ngx_conf_t *cf,
  13.     ngx_http_upstream_rr_peer_t *peer, ngx_str_t *route);
  14. #endif

  15. static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
  16.     ngx_http_upstream_rr_peer_data_t *rrp, ngx_peer_connection_t *pc);

  17. #if (NGX_HTTP_SSL)

  18. static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
  19.     void *data);
  20. static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
  21.     void *data);

  22. #endif


  23. ngx_int_t
  24. ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
  25.     ngx_http_upstream_srv_conf_t *us)
  26. {
  27.     ngx_url_t                      u;
  28.     ngx_uint_t                     i, j, n, r, w, t;
  29.     ngx_http_upstream_server_t    *server;
  30.     ngx_http_upstream_rr_peer_t   *peer, **peerp;
  31.     ngx_http_upstream_rr_peers_t  *peers, *backup;
  32. #if (NGX_HTTP_UPSTREAM_ZONE)
  33.     ngx_uint_t                     resolve;
  34.     ngx_http_core_loc_conf_t      *clcf;
  35.     ngx_http_upstream_rr_peer_t  **rpeerp;
  36. #endif

  37.     us->peer.init = ngx_http_upstream_init_round_robin_peer;

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

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

  44. #if (NGX_HTTP_UPSTREAM_ZONE)
  45.         resolve = 0;
  46. #endif

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

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

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

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

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

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

  68. #if (NGX_HTTP_UPSTREAM_ZONE)
  69.         if (us->shm_zone) {

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

  78.             clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  79.             if (us->resolver == NULL) {
  80.                 us->resolver = clcf->resolver;
  81.             }

  82.             /*
  83.              * Without "resolver_timeout" in http{} the merged value is unset.
  84.              */
  85.             ngx_conf_merge_msec_value(us->resolver_timeout,
  86.                                       clcf->resolver_timeout, 30000);

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

  97.         } else if (resolve) {

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

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

  112.         peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
  113.         if (peers == NULL) {
  114.             return NGX_ERROR;
  115.         }

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

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

  127.         n = 0;
  128.         peerp = &peers->peer;

  129. #if (NGX_HTTP_UPSTREAM_ZONE)
  130.         rpeerp = &peers->resolve;
  131. #endif

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

  136. #if (NGX_HTTP_UPSTREAM_ZONE)
  137.             if (server[i].host.len) {

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

  143.                 peer[n].host->name = server[i].host;
  144.                 peer[n].host->service = server[i].service;

  145.                 peer[n].sockaddr = server[i].addrs[0].sockaddr;
  146.                 peer[n].socklen = server[i].addrs[0].socklen;
  147.                 peer[n].name = server[i].addrs[0].name;
  148.                 peer[n].weight = server[i].weight;
  149.                 peer[n].effective_weight = server[i].weight;
  150.                 peer[n].current_weight = 0;
  151.                 peer[n].max_conns = server[i].max_conns;
  152.                 peer[n].max_fails = server[i].max_fails;
  153.                 peer[n].fail_timeout = server[i].fail_timeout;
  154.                 peer[n].down = server[i].down;
  155.                 peer[n].server = server[i].name;

  156. #if (NGX_HTTP_UPSTREAM_SID)
  157.                 if (ngx_http_upstream_create_sid(cf, &peer[n], &server[i].sid)
  158.                     != NGX_OK)
  159.                 {
  160.                     return NGX_ERROR;
  161.                 }
  162. #endif

  163.                 *rpeerp = &peer[n];
  164.                 rpeerp = &peer[n].next;
  165.                 n++;

  166.                 continue;
  167.             }
  168. #endif

  169.             for (j = 0; j < server[i].naddrs; j++) {
  170.                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
  171.                 peer[n].socklen = server[i].addrs[j].socklen;
  172.                 peer[n].name = server[i].addrs[j].name;
  173.                 peer[n].weight = server[i].weight;
  174.                 peer[n].effective_weight = server[i].weight;
  175.                 peer[n].current_weight = 0;
  176.                 peer[n].max_conns = server[i].max_conns;
  177.                 peer[n].max_fails = server[i].max_fails;
  178.                 peer[n].fail_timeout = server[i].fail_timeout;
  179.                 peer[n].down = server[i].down;
  180.                 peer[n].server = server[i].name;

  181. #if (NGX_HTTP_UPSTREAM_SID)
  182.                 if (ngx_http_upstream_create_sid(cf, &peer[n], &server[i].sid)
  183.                     != NGX_OK)
  184.                 {
  185.                     return NGX_ERROR;
  186.                 }
  187. #endif

  188.                 *peerp = &peer[n];
  189.                 peerp = &peer[n].next;
  190.                 n++;
  191.             }
  192.         }

  193.         us->peer.data = peers;

  194.         /* backup servers */

  195.         n = 0;
  196.         r = 0;
  197.         w = 0;
  198.         t = 0;

  199.         for (i = 0; i < us->servers->nelts; i++) {
  200.             if (!server[i].backup) {
  201.                 continue;
  202.             }

  203. #if (NGX_HTTP_UPSTREAM_ZONE)
  204.             if (server[i].host.len) {
  205.                 r++;
  206.                 continue;
  207.             }
  208. #endif

  209.             n += server[i].naddrs;
  210.             w += server[i].naddrs * server[i].weight;

  211.             if (!server[i].down) {
  212.                 t += server[i].naddrs;
  213.             }
  214.         }

  215.         if (n == 0
  216. #if (NGX_HTTP_UPSTREAM_ZONE)
  217.             && !resolve
  218. #endif
  219.         ) {
  220.             return NGX_OK;
  221.         }

  222.         if (n + r == 0 && !(us->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
  223.             return NGX_OK;
  224.         }

  225.         backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
  226.         if (backup == NULL) {
  227.             return NGX_ERROR;
  228.         }

  229.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t)
  230.                                      * (n + r));
  231.         if (peer == NULL) {
  232.             return NGX_ERROR;
  233.         }

  234.         if (n > 0) {
  235.             peers->single = 0;
  236.         }

  237.         backup->single = 0;
  238.         backup->number = n;
  239.         backup->weighted = (w != n);
  240.         backup->total_weight = w;
  241.         backup->tries = t;
  242.         backup->name = &us->host;

  243.         n = 0;
  244.         peerp = &backup->peer;

  245. #if (NGX_HTTP_UPSTREAM_ZONE)
  246.         rpeerp = &backup->resolve;
  247. #endif

  248.         for (i = 0; i < us->servers->nelts; i++) {
  249.             if (!server[i].backup) {
  250.                 continue;
  251.             }

  252. #if (NGX_HTTP_UPSTREAM_ZONE)
  253.             if (server[i].host.len) {

  254.                 peer[n].host = ngx_pcalloc(cf->pool,
  255.                                            sizeof(ngx_http_upstream_host_t));
  256.                 if (peer[n].host == NULL) {
  257.                     return NGX_ERROR;
  258.                 }

  259.                 peer[n].host->name = server[i].host;
  260.                 peer[n].host->service = server[i].service;

  261.                 peer[n].sockaddr = server[i].addrs[0].sockaddr;
  262.                 peer[n].socklen = server[i].addrs[0].socklen;
  263.                 peer[n].name = server[i].addrs[0].name;
  264.                 peer[n].weight = server[i].weight;
  265.                 peer[n].effective_weight = server[i].weight;
  266.                 peer[n].current_weight = 0;
  267.                 peer[n].max_conns = server[i].max_conns;
  268.                 peer[n].max_fails = server[i].max_fails;
  269.                 peer[n].fail_timeout = server[i].fail_timeout;
  270.                 peer[n].down = server[i].down;
  271.                 peer[n].server = server[i].name;

  272. #if (NGX_HTTP_UPSTREAM_SID)
  273.                 if (ngx_http_upstream_create_sid(cf, &peer[n], &server[i].sid)
  274.                     != NGX_OK)
  275.                 {
  276.                     return NGX_ERROR;
  277.                 }
  278. #endif

  279.                 *rpeerp = &peer[n];
  280.                 rpeerp = &peer[n].next;
  281.                 n++;

  282.                 continue;
  283.             }
  284. #endif

  285.             for (j = 0; j < server[i].naddrs; j++) {
  286.                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
  287.                 peer[n].socklen = server[i].addrs[j].socklen;
  288.                 peer[n].name = server[i].addrs[j].name;
  289.                 peer[n].weight = server[i].weight;
  290.                 peer[n].effective_weight = server[i].weight;
  291.                 peer[n].current_weight = 0;
  292.                 peer[n].max_conns = server[i].max_conns;
  293.                 peer[n].max_fails = server[i].max_fails;
  294.                 peer[n].fail_timeout = server[i].fail_timeout;
  295.                 peer[n].down = server[i].down;
  296.                 peer[n].server = server[i].name;

  297. #if (NGX_HTTP_UPSTREAM_SID)
  298.                 if (ngx_http_upstream_create_sid(cf, &peer[n], &server[i].sid)
  299.                     != NGX_OK)
  300.                 {
  301.                     return NGX_ERROR;
  302.                 }
  303. #endif

  304.                 *peerp = &peer[n];
  305.                 peerp = &peer[n].next;
  306.                 n++;
  307.             }
  308.         }

  309.         peers->next = backup;

  310.         return NGX_OK;
  311.     }


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

  313.     if (us->port == 0) {
  314.         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  315.                       "no port in upstream \"%V\" in %s:%ui",
  316.                       &us->host, us->file_name, us->line);
  317.         return NGX_ERROR;
  318.     }

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

  320.     u.host = us->host;
  321.     u.port = us->port;

  322.     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
  323.         if (u.err) {
  324.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  325.                           "%s in upstream \"%V\" in %s:%ui",
  326.                           u.err, &us->host, us->file_name, us->line);
  327.         }

  328.         return NGX_ERROR;
  329.     }

  330.     n = u.naddrs;

  331.     peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
  332.     if (peers == NULL) {
  333.         return NGX_ERROR;
  334.     }

  335.     peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
  336.     if (peer == NULL) {
  337.         return NGX_ERROR;
  338.     }

  339.     peers->single = (n == 1);
  340.     peers->number = n;
  341.     peers->weighted = 0;
  342.     peers->total_weight = n;
  343.     peers->tries = n;
  344.     peers->name = &us->host;

  345.     peerp = &peers->peer;

  346.     for (i = 0; i < u.naddrs; i++) {
  347.         peer[i].sockaddr = u.addrs[i].sockaddr;
  348.         peer[i].socklen = u.addrs[i].socklen;
  349.         peer[i].name = u.addrs[i].name;
  350.         peer[i].weight = 1;
  351.         peer[i].effective_weight = 1;
  352.         peer[i].current_weight = 0;
  353.         peer[i].max_conns = 0;
  354.         peer[i].max_fails = 1;
  355.         peer[i].fail_timeout = 10;
  356.         *peerp = &peer[i];
  357.         peerp = &peer[i].next;
  358.     }

  359.     us->peer.data = peers;

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

  361.     return NGX_OK;
  362. }


  363. #if (NGX_HTTP_UPSTREAM_SID)

  364. static ngx_int_t
  365. ngx_http_upstream_create_sid(ngx_conf_t *cf, ngx_http_upstream_rr_peer_t *peer,
  366.     ngx_str_t *route)
  367. {
  368.     if (route->len) {
  369.         peer->route = 1;
  370.         peer->sid = *route;
  371.         return NGX_OK;
  372.     }

  373.     peer->sid.data = ngx_pnalloc(cf->pool, NGX_HTTP_UPSTREAM_SID_LEN);
  374.     if (peer->sid.data == NULL) {
  375.         return NGX_ERROR;
  376.     }

  377.     ngx_http_upstream_init_round_robin_sid(peer, NULL);

  378.     return NGX_OK;
  379. }


  380. void
  381. ngx_http_upstream_init_round_robin_sid(ngx_http_upstream_rr_peer_t *peer,
  382.     ngx_str_t *route)
  383. {
  384.     u_char     hash[16];
  385.     ngx_md5_t  md5;

  386.     if (route && route->len) {
  387.         peer->route = 1;
  388.         peer->sid.len = route->len;
  389.         ngx_memcpy(peer->sid.data, route->data, route->len);
  390.         return;
  391.     }

  392.     peer->route = 0;

  393.     /* SID is the MD5 hash of a printable socket address */

  394.     if (peer->name.len == 0) {
  395.         peer->sid.len = 0;
  396.         return;
  397.     }

  398.     ngx_md5_init(&md5);
  399.     ngx_md5_update(&md5, peer->name.data, peer->name.len);
  400.     ngx_md5_final(hash, &md5);

  401.     ngx_hex_dump(peer->sid.data, hash, 16);
  402.     peer->sid.len = NGX_HTTP_UPSTREAM_SID_LEN;
  403. }

  404. #endif


  405. ngx_int_t
  406. ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
  407.     ngx_http_upstream_srv_conf_t *us)
  408. {
  409.     ngx_uint_t                         n;
  410.     ngx_http_upstream_rr_peer_data_t  *rrp;

  411.     rrp = r->upstream->peer.data;

  412.     if (rrp == NULL) {
  413.         rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
  414.         if (rrp == NULL) {
  415.             return NGX_ERROR;
  416.         }

  417.         r->upstream->peer.data = rrp;
  418.     }

  419.     rrp->peers = us->peer.data;
  420.     rrp->current = NULL;

  421.     ngx_http_upstream_rr_peers_rlock(rrp->peers);

  422. #if (NGX_HTTP_UPSTREAM_ZONE)
  423.     rrp->config = rrp->peers->config ? *rrp->peers->config : 0;
  424. #endif

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

  426.     if (rrp->peers->next && rrp->peers->next->number > n) {
  427.         n = rrp->peers->next->number;
  428.     }

  429.     r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);

  430.     ngx_http_upstream_rr_peers_unlock(rrp->peers);

  431.     if (n <= 8 * sizeof(uintptr_t)) {
  432.         rrp->tried = &rrp->data;
  433.         rrp->data = 0;

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

  436.         rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
  437.         if (rrp->tried == NULL) {
  438.             return NGX_ERROR;
  439.         }
  440.     }

  441.     r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
  442.     r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
  443. #if (NGX_HTTP_SSL)
  444.     r->upstream->peer.set_session =
  445.                                ngx_http_upstream_set_round_robin_peer_session;
  446.     r->upstream->peer.save_session =
  447.                                ngx_http_upstream_save_round_robin_peer_session;
  448. #endif

  449.     return NGX_OK;
  450. }


  451. ngx_int_t
  452. ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
  453.     ngx_http_upstream_resolved_t *ur)
  454. {
  455.     u_char                            *p;
  456.     size_t                             len;
  457.     socklen_t                          socklen;
  458.     ngx_uint_t                         i, n;
  459.     struct sockaddr                   *sockaddr;
  460.     ngx_http_upstream_rr_peer_t       *peer, **peerp;
  461.     ngx_http_upstream_rr_peers_t      *peers;
  462.     ngx_http_upstream_rr_peer_data_t  *rrp;

  463.     rrp = r->upstream->peer.data;

  464.     if (rrp == NULL) {
  465.         rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
  466.         if (rrp == NULL) {
  467.             return NGX_ERROR;
  468.         }

  469.         r->upstream->peer.data = rrp;
  470.     }

  471.     peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t));
  472.     if (peers == NULL) {
  473.         return NGX_ERROR;
  474.     }

  475.     peer = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peer_t)
  476.                                 * ur->naddrs);
  477.     if (peer == NULL) {
  478.         return NGX_ERROR;
  479.     }

  480.     peers->single = (ur->naddrs == 1);
  481.     peers->number = ur->naddrs;
  482.     peers->tries = ur->naddrs;
  483.     peers->name = &ur->host;

  484.     if (ur->sockaddr) {
  485.         peer[0].sockaddr = ur->sockaddr;
  486.         peer[0].socklen = ur->socklen;
  487.         peer[0].name = ur->name.data ? ur->name : ur->host;
  488.         peer[0].weight = 1;
  489.         peer[0].effective_weight = 1;
  490.         peer[0].current_weight = 0;
  491.         peer[0].max_conns = 0;
  492.         peer[0].max_fails = 1;
  493.         peer[0].fail_timeout = 10;
  494.         peers->peer = peer;

  495.     } else {
  496.         peerp = &peers->peer;

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

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

  499.             sockaddr = ngx_palloc(r->pool, socklen);
  500.             if (sockaddr == NULL) {
  501.                 return NGX_ERROR;
  502.             }

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

  505.             p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
  506.             if (p == NULL) {
  507.                 return NGX_ERROR;
  508.             }

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

  510.             peer[i].sockaddr = sockaddr;
  511.             peer[i].socklen = socklen;
  512.             peer[i].name.len = len;
  513.             peer[i].name.data = p;
  514.             peer[i].weight = 1;
  515.             peer[i].effective_weight = 1;
  516.             peer[i].current_weight = 0;
  517.             peer[i].max_conns = 0;
  518.             peer[i].max_fails = 1;
  519.             peer[i].fail_timeout = 10;
  520.             *peerp = &peer[i];
  521.             peerp = &peer[i].next;
  522.         }
  523.     }

  524.     rrp->peers = peers;
  525.     rrp->current = NULL;
  526.     rrp->config = 0;

  527.     if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
  528.         rrp->tried = &rrp->data;
  529.         rrp->data = 0;

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

  533.         rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
  534.         if (rrp->tried == NULL) {
  535.             return NGX_ERROR;
  536.         }
  537.     }

  538.     r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
  539.     r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
  540.     r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
  541. #if (NGX_HTTP_SSL)
  542.     r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
  543.     r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
  544. #endif

  545.     return NGX_OK;
  546. }


  547. ngx_int_t
  548. ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
  549. {
  550.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  551.     ngx_int_t                      rc;
  552.     ngx_uint_t                     i, n;
  553.     ngx_http_upstream_rr_peer_t   *peer;
  554.     ngx_http_upstream_rr_peers_t  *peers;

  555.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  556.                    "get rr peer, try: %ui", pc->tries);

  557.     pc->cached = 0;
  558.     pc->connection = NULL;

  559.     peers = rrp->peers;
  560.     ngx_http_upstream_rr_peers_wlock(peers);

  561. #if (NGX_HTTP_UPSTREAM_ZONE)
  562.     if (peers->config && rrp->config != *peers->config) {
  563.         goto busy;
  564.     }
  565. #endif

  566.     if (peers->single) {
  567. #if (NGX_HTTP_UPSTREAM_SID)
  568.         peer = ngx_http_upstream_get_rr_peer_by_sid(rrp, pc->hint, &i, 0);

  569.         if (peer == NULL) {
  570. #endif
  571.             peer = peers->peer;

  572.             if (peer->down) {
  573.                 goto failed;
  574.             }

  575.             if (peer->max_conns && peer->conns >= peer->max_conns) {
  576.                 goto failed;
  577.             }
  578. #if (NGX_HTTP_UPSTREAM_SID)
  579.         }
  580. #endif

  581.         rrp->current = peer;
  582.         ngx_http_upstream_rr_peer_ref(peers, peer);

  583.     } else {

  584.         /* there are several peers */

  585.         peer = ngx_http_upstream_get_peer(rrp, pc);

  586.         if (peer == NULL) {
  587.             goto failed;
  588.         }

  589.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  590.                        "get rr peer, current: %p %i",
  591.                        peer, peer->current_weight);
  592.     }

  593.     pc->sockaddr = peer->sockaddr;
  594.     pc->socklen = peer->socklen;
  595.     pc->name = &peer->name;

  596. #if (NGX_HTTP_UPSTREAM_SID)
  597.     pc->sid = &peer->sid;
  598. #endif

  599.     peer->conns++;

  600.     ngx_http_upstream_rr_peers_unlock(peers);

  601.     return NGX_OK;

  602. failed:

  603.     if (peers->next) {

  604.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");

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

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

  608.         for (i = 0; i < n; i++) {
  609.             rrp->tried[i] = 0;
  610.         }

  611.         ngx_http_upstream_rr_peers_unlock(peers);

  612.         rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);

  613.         if (rc != NGX_BUSY) {
  614.             return rc;
  615.         }

  616.         ngx_http_upstream_rr_peers_wlock(peers);
  617.     }

  618. #if (NGX_HTTP_UPSTREAM_ZONE)
  619. busy:
  620. #endif

  621.     ngx_http_upstream_rr_peers_unlock(peers);

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

  623.     return NGX_BUSY;
  624. }


  625. static ngx_http_upstream_rr_peer_t *
  626. ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp,
  627.     ngx_peer_connection_t *pc)
  628. {
  629.     time_t                        now;
  630.     uintptr_t                     m;
  631.     ngx_int_t                     total;
  632.     ngx_uint_t                    i, n, p;
  633.     ngx_http_upstream_rr_peer_t  *peer, *best;

  634. #if (NGX_HTTP_UPSTREAM_SID)
  635.     ngx_int_t                     low_limit;
  636.     ngx_uint_t                    st_p;
  637.     ngx_http_upstream_rr_peer_t  *st_peer;
  638. #endif

  639.     now = ngx_time();

  640.     best = NULL;
  641.     total = 0;

  642. #if (NGX_SUPPRESS_WARN)
  643.     p = 0;
  644. #endif

  645. #if (NGX_HTTP_UPSTREAM_SID)
  646.     st_peer = ngx_http_upstream_get_rr_peer_by_sid(rrp, pc->hint, &p, 0);

  647.     if (st_peer) {

  648.         low_limit = -((ngx_int_t)(rrp->peers->total_weight - st_peer->weight));

  649.         /*
  650.          * note: current code accounts only one sticky request in a row, if it
  651.          *       is required to account more, multiply low_limit by N below
  652.          */
  653.         if (st_peer->current_weight <= low_limit) {

  654.             /* do not update weights if the limit exceeded */
  655.             best = st_peer;
  656.             goto best_chosen;
  657.         }
  658.         /* else: proceed to reweight with existing st_peer */
  659.     }

  660.     st_p = p;
  661. #endif

  662.     for (peer = rrp->peers->peer, i = 0;
  663.          peer;
  664.          peer = peer->next, i++)
  665.     {
  666.         n = i / (8 * sizeof(uintptr_t));
  667.         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  668.         if (rrp->tried[n] & m) {
  669.             continue;
  670.         }

  671.         if (peer->down) {
  672.             continue;
  673.         }

  674.         if (peer->max_fails
  675.             && peer->fails >= peer->max_fails
  676.             && now - peer->checked <= peer->fail_timeout)
  677.         {
  678.             continue;
  679.         }

  680.         if (peer->max_conns && peer->conns >= peer->max_conns) {
  681.             continue;
  682.         }

  683.         peer->current_weight += peer->effective_weight;
  684.         total += peer->effective_weight;

  685.         if (peer->effective_weight < peer->weight) {
  686.             peer->effective_weight++;
  687.         }

  688.         if (best == NULL || peer->current_weight > best->current_weight) {
  689.             best = peer;
  690.             p = i;
  691.         }
  692.     }

  693. #if (NGX_HTTP_UPSTREAM_SID)
  694.     /* prefer peer chosen by sticky to best from RR */

  695.     if (st_peer) {
  696.         best = st_peer;
  697.         p = st_p;
  698.     }
  699. #endif

  700.     if (best == NULL) {
  701.         return NULL;
  702.     }

  703.     best->current_weight -= total;

  704. #if (NGX_HTTP_UPSTREAM_SID)
  705. best_chosen:
  706. #endif

  707.     rrp->current = best;
  708.     ngx_http_upstream_rr_peer_ref(rrp->peers, best);

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

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

  712.     if (now - best->checked > best->fail_timeout) {
  713.         best->checked = now;
  714.     }

  715.     return best;
  716. }


  717. #if (NGX_HTTP_UPSTREAM_SID)

  718. ngx_http_upstream_rr_peer_t *
  719. ngx_http_upstream_get_rr_peer_by_sid(ngx_http_upstream_rr_peer_data_t *rrp,
  720.     ngx_str_t *hint, ngx_uint_t *p, ngx_uint_t lock)
  721. {
  722.     uintptr_t                     m;
  723.     ngx_uint_t                    i, n;
  724.     ngx_http_upstream_rr_peer_t  *peer;

  725.     if (hint == NULL) {
  726.         return NULL;
  727.     }

  728.     for (peer = rrp->peers->peer, i = 0;
  729.          peer;
  730.          peer = peer->next, i++)
  731.     {

  732.         if (peer->sid.len == hint->len
  733.             && ngx_memcmp(peer->sid.data, hint->data, hint->len) == 0)
  734.         {
  735.             goto found;
  736.         }
  737.     }

  738.     return NULL;

  739. found:

  740.     n = i / (8 * sizeof(uintptr_t));
  741.     m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  742.     if (rrp->tried[n] & m) {
  743.         return NULL;
  744.     }

  745.     if (lock) {
  746.         ngx_http_upstream_rr_peer_lock(rrp->peers, peer);
  747.     }

  748.     if (peer->down
  749. #if (NGX_HTTP_UPSTREAM_STICKY)
  750.         & ~NGX_HTTP_UPSTREAM_DRAINING
  751. #endif
  752.     ) {
  753.         goto failed;
  754.     }

  755.     if (peer->max_fails
  756.         && peer->fails >= peer->max_fails
  757.         && ngx_time() - peer->checked <= peer->fail_timeout)
  758.     {
  759.         goto failed;
  760.     }

  761.     if (peer->max_conns && peer->conns >= peer->max_conns) {
  762.         goto failed;
  763.     }

  764.     *p = i;
  765.     return peer;

  766. failed:

  767.     if (lock) {
  768.         ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
  769.     }

  770.     return NULL;
  771. }

  772. #endif


  773. void
  774. ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
  775.     ngx_uint_t state)
  776. {
  777. #if (NGX_HTTP_UPSTREAM_ZONE)
  778.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  779.     ngx_http_upstream_rr_peers_rlock(rrp->peers);
  780.     ngx_http_upstream_rr_peer_lock(rrp->peers, rrp->current);
  781. #endif

  782.     ngx_http_upstream_free_round_robin_peer_locked(pc, data, state);
  783. }


  784. void
  785. ngx_http_upstream_free_round_robin_peer_locked(ngx_peer_connection_t *pc,
  786.     void *data, ngx_uint_t state)
  787. {
  788.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  789.     time_t                       now;
  790.     ngx_http_upstream_rr_peer_t  *peer;

  791.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  792.                    "free rr peer %ui %ui", pc->tries, state);

  793.     /* TODO: NGX_PEER_KEEPALIVE */

  794.     peer = rrp->current;

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

  796.         if (peer->fails) {
  797.             peer->fails = 0;
  798.         }

  799.         peer->conns--;

  800.         if (ngx_http_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
  801.             ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
  802.         }

  803.         ngx_http_upstream_rr_peers_unlock(rrp->peers);

  804.         pc->tries = 0;
  805.         return;
  806.     }

  807.     if (state & NGX_PEER_FAILED) {
  808.         now = ngx_time();

  809.         peer->fails++;
  810.         peer->accessed = now;
  811.         peer->checked = now;

  812.         if (peer->max_fails) {
  813.             peer->effective_weight -= peer->weight / peer->max_fails;

  814.             if (peer->fails >= peer->max_fails) {
  815.                 ngx_log_error(NGX_LOG_WARN, pc->log, 0,
  816.                               "upstream server temporarily disabled");
  817.             }
  818.         }

  819.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  820.                        "free rr peer failed: %p %i",
  821.                        peer, peer->effective_weight);

  822.         if (peer->effective_weight < 0) {
  823.             peer->effective_weight = 0;
  824.         }

  825.     } else {

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

  827.         if (peer->accessed < peer->checked) {
  828.             peer->fails = 0;
  829.         }
  830.     }

  831.     peer->conns--;

  832.     if (ngx_http_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
  833.         ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
  834.     }

  835.     ngx_http_upstream_rr_peers_unlock(rrp->peers);

  836.     if (pc->tries) {
  837.         pc->tries--;
  838.     }
  839. }


  840. #if (NGX_HTTP_SSL)

  841. ngx_int_t
  842. ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
  843.     void *data)
  844. {
  845.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  846.     ngx_int_t                      rc;
  847.     ngx_ssl_session_t             *ssl_session;
  848.     ngx_http_upstream_rr_peer_t   *peer;
  849. #if (NGX_HTTP_UPSTREAM_ZONE)
  850.     int                            len;
  851.     const u_char                  *p;
  852.     ngx_http_upstream_rr_peers_t  *peers;
  853. #endif

  854.     peer = rrp->current;

  855. #if (NGX_HTTP_UPSTREAM_ZONE)
  856.     peers = rrp->peers;

  857.     if (peers->shpool) {
  858.         ngx_http_upstream_rr_peers_rlock(peers);
  859.         ngx_http_upstream_rr_peer_lock(peers, peer);

  860.         if (peer->ssl_session == NULL) {
  861.             ngx_http_upstream_rr_peer_unlock(peers, peer);
  862.             ngx_http_upstream_rr_peers_unlock(peers);
  863.             return NGX_OK;
  864.         }

  865.         len = peer->ssl_session_len;

  866.         ngx_memcpy(ngx_ssl_session_buffer, peer->ssl_session, len);

  867.         ngx_http_upstream_rr_peer_unlock(peers, peer);
  868.         ngx_http_upstream_rr_peers_unlock(peers);

  869.         p = ngx_ssl_session_buffer;
  870.         ssl_session = d2i_SSL_SESSION(NULL, &p, len);

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

  872.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  873.                        "set session: %p", ssl_session);

  874.         ngx_ssl_free_session(ssl_session);

  875.         return rc;
  876.     }
  877. #endif

  878.     ssl_session = peer->ssl_session;

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

  880.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  881.                    "set session: %p", ssl_session);

  882.     return rc;
  883. }


  884. void
  885. ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
  886.     void *data)
  887. {
  888.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  889.     ngx_ssl_session_t             *old_ssl_session, *ssl_session;
  890.     ngx_http_upstream_rr_peer_t   *peer;
  891. #if (NGX_HTTP_UPSTREAM_ZONE)
  892.     int                            len;
  893.     u_char                        *p;
  894.     ngx_http_upstream_rr_peers_t  *peers;
  895. #endif

  896. #if (NGX_HTTP_UPSTREAM_ZONE)
  897.     peers = rrp->peers;

  898.     if (peers->shpool) {

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

  900.         if (ssl_session == NULL) {
  901.             return;
  902.         }

  903.         len = i2d_SSL_SESSION(ssl_session, NULL);

  904.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  905.                        "save session: %p:%d", ssl_session, len);

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

  907.         if (len > NGX_SSL_MAX_SESSION_SIZE) {
  908.             return;
  909.         }

  910.         p = ngx_ssl_session_buffer;
  911.         (void) i2d_SSL_SESSION(ssl_session, &p);

  912.         peer = rrp->current;

  913.         ngx_http_upstream_rr_peers_rlock(peers);
  914.         ngx_http_upstream_rr_peer_lock(peers, peer);

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

  917.             if (peer->ssl_session) {
  918.                 ngx_slab_free_locked(peers->shpool, peer->ssl_session);
  919.             }

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

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

  922.             if (peer->ssl_session == NULL) {
  923.                 peer->ssl_session_len = 0;

  924.                 ngx_http_upstream_rr_peer_unlock(peers, peer);
  925.                 ngx_http_upstream_rr_peers_unlock(peers);
  926.                 return;
  927.             }

  928.             peer->ssl_session_len = len;
  929.         }

  930.         ngx_memcpy(peer->ssl_session, ngx_ssl_session_buffer, len);

  931.         ngx_http_upstream_rr_peer_unlock(peers, peer);
  932.         ngx_http_upstream_rr_peers_unlock(peers);

  933.         return;
  934.     }
  935. #endif

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

  937.     if (ssl_session == NULL) {
  938.         return;
  939.     }

  940.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  941.                    "save session: %p", ssl_session);

  942.     peer = rrp->current;

  943.     old_ssl_session = peer->ssl_session;
  944.     peer->ssl_session = ssl_session;

  945.     if (old_ssl_session) {

  946.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  947.                        "old session: %p", old_ssl_session);

  948.         ngx_ssl_free_session(old_ssl_session);
  949.     }
  950. }


  951. static ngx_int_t
  952. ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
  953. {
  954.     return NGX_OK;
  955. }


  956. static void
  957. ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
  958. {
  959.     return;
  960. }

  961. #endif