blob: 2a0869683d587cb11f422cdaaf6a336388f6c530 [file] [log] [blame]
Igor Sysoev3d2fd182006-12-04 16:46:13 +00001
2/*
3 * Copyright (C) Igor Sysoev
Maxim Konovalovf8d59e32012-01-18 15:07:43 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoev3d2fd182006-12-04 16:46:13 +00005 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_http.h>
11
12
Roman Arutyunyancfc3db12014-09-12 18:50:46 +040013#define ngx_http_upstream_tries(p) ((p)->number \
14 + ((p)->next ? (p)->next->number : 0))
15
16
Maxim Dounin52327e02012-05-14 09:57:20 +000017static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
18 ngx_http_upstream_rr_peer_data_t *rrp);
Igor Sysoevd12a5712007-07-28 16:04:01 +000019
Igor Sysoev08b59752011-07-22 16:30:17 +000020#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
Igor Sysoevd12a5712007-07-28 16:04:01 +000029
Igor Sysoev3d2fd182006-12-04 16:46:13 +000030ngx_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;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +000035 ngx_uint_t i, j, n, w;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000036 ngx_http_upstream_server_t *server;
Ruslan Ermilov0c957672015-04-10 14:48:36 +030037 ngx_http_upstream_rr_peer_t *peer, **peerp;
Igor Sysoev6876bcd2007-08-09 13:54:33 +000038 ngx_http_upstream_rr_peers_t *peers, *backup;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000039
40 us->peer.init = ngx_http_upstream_init_round_robin_peer;
41
42 if (us->servers) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +000043 server = us->servers->elts;
44
Igor Sysoev6876bcd2007-08-09 13:54:33 +000045 n = 0;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +000046 w = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +000047
Igor Sysoev3d2fd182006-12-04 16:46:13 +000048 for (i = 0; i < us->servers->nelts; i++) {
Igor Sysoev6876bcd2007-08-09 13:54:33 +000049 if (server[i].backup) {
50 continue;
51 }
52
Igor Sysoev3d2fd182006-12-04 16:46:13 +000053 n += server[i].naddrs;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +000054 w += server[i].naddrs * server[i].weight;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000055 }
56
Maxim Dounina5d4f662012-04-02 21:29:35 +000057 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
Ruslan Ermilov0c957672015-04-10 14:48:36 +030064 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +000065 if (peers == NULL) {
66 return NGX_ERROR;
67 }
68
Ruslan Ermilov0c957672015-04-10 14:48:36 +030069 peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
70 if (peer == NULL) {
71 return NGX_ERROR;
72 }
73
Igor Sysoev6876bcd2007-08-09 13:54:33 +000074 peers->single = (n == 1);
Igor Sysoev3d2fd182006-12-04 16:46:13 +000075 peers->number = n;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +000076 peers->weighted = (w != n);
77 peers->total_weight = w;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000078 peers->name = &us->host;
79
80 n = 0;
Ruslan Ermilov0c957672015-04-10 14:48:36 +030081 peerp = &peers->peer;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000082
83 for (i = 0; i < us->servers->nelts; i++) {
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +080084 if (server[i].backup) {
85 continue;
86 }
Igor Sysoev6876bcd2007-08-09 13:54:33 +000087
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +080088 for (j = 0; j < server[i].naddrs; j++) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +040089 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;
Ruslan Ermilov49dec842016-09-22 19:32:47 +030095 peer[n].max_conns = server[i].max_conns;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +040096 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;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300100
101 *peerp = &peer[n];
102 peerp = &peer[n].next;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000103 n++;
104 }
105 }
106
107 us->peer.data = peers;
108
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000109 /* backup servers */
110
111 n = 0;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000112 w = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000113
114 for (i = 0; i < us->servers->nelts; i++) {
115 if (!server[i].backup) {
116 continue;
117 }
118
119 n += server[i].naddrs;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000120 w += server[i].naddrs * server[i].weight;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000121 }
122
123 if (n == 0) {
124 return NGX_OK;
125 }
126
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300127 backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000128 if (backup == NULL) {
129 return NGX_ERROR;
130 }
131
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300132 peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
133 if (peer == NULL) {
134 return NGX_ERROR;
135 }
136
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000137 peers->single = 0;
138 backup->single = 0;
139 backup->number = n;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000140 backup->weighted = (w != n);
141 backup->total_weight = w;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000142 backup->name = &us->host;
143
144 n = 0;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300145 peerp = &backup->peer;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000146
147 for (i = 0; i < us->servers->nelts; i++) {
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +0800148 if (!server[i].backup) {
149 continue;
150 }
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000151
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +0800152 for (j = 0; j < server[i].naddrs; j++) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400153 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;
Ruslan Ermilov49dec842016-09-22 19:32:47 +0300159 peer[n].max_conns = server[i].max_conns;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400160 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;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300164
165 *peerp = &peer[n];
166 peerp = &peer[n].next;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000167 n++;
168 }
169 }
170
171 peers->next = backup;
172
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000173 return NGX_OK;
174 }
175
176
177 /* an upstream implicitly defined by proxy_pass, etc. */
178
Ruslan Ermilova2a22912013-01-10 12:58:55 +0000179 if (us->port == 0) {
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000180 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
181 "no port in upstream \"%V\" in %s:%ui",
Igor Sysoev4b96baa2007-09-15 17:11:06 +0000182 &us->host, us->file_name, us->line);
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000183 return NGX_ERROR;
184 }
185
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000186 ngx_memzero(&u, sizeof(ngx_url_t));
187
188 u.host = us->host;
Ruslan Ermilova2a22912013-01-10 12:58:55 +0000189 u.port = us->port;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000190
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000191 if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000192 if (u.err) {
193 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
Igor Sysoev5d118d32006-12-11 08:59:30 +0000194 "%s in upstream \"%V\" in %s:%ui",
Igor Sysoev4b96baa2007-09-15 17:11:06 +0000195 u.err, &us->host, us->file_name, us->line);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000196 }
197
198 return NGX_ERROR;
199 }
200
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000201 n = u.naddrs;
202
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300203 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000204 if (peers == NULL) {
205 return NGX_ERROR;
206 }
207
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300208 peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
209 if (peer == NULL) {
210 return NGX_ERROR;
211 }
212
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000213 peers->single = (n == 1);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000214 peers->number = n;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000215 peers->weighted = 0;
216 peers->total_weight = n;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000217 peers->name = &us->host;
218
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300219 peerp = &peers->peer;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400220
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000221 for (i = 0; i < u.naddrs; i++) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400222 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;
Ruslan Ermilov49dec842016-09-22 19:32:47 +0300228 peer[i].max_conns = 0;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400229 peer[i].max_fails = 1;
230 peer[i].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300231 *peerp = &peer[i];
232 peerp = &peer[i].next;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000233 }
234
235 us->peer.data = peers;
236
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000237 /* implicitly defined upstream has no backup servers */
238
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000239 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;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300262 rrp->current = NULL;
Maxim Dounin144dc692016-09-29 18:06:04 +0300263 rrp->config = 0;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000264
Maxim Douninb7fcb432011-08-18 17:04:52 +0000265 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)) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000272 rrp->tried = &rrp->data;
273 rrp->data = 0;
274
275 } else {
Maxim Douninb7fcb432011-08-18 17:04:52 +0000276 n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000277
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;
Roman Arutyunyancfc3db12014-09-12 18:50:46 +0400286 r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000287#if (NGX_HTTP_SSL)
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000288 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;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000292#endif
293
294 return NGX_OK;
295}
296
297
298ngx_int_t
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000299ngx_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;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400304 socklen_t socklen;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000305 ngx_uint_t i, n;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400306 struct sockaddr *sockaddr;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300307 ngx_http_upstream_rr_peer_t *peer, **peerp;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000308 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
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300322 peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000323 if (peers == NULL) {
324 return NGX_ERROR;
325 }
326
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300327 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
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000333 peers->single = (ur->naddrs == 1);
334 peers->number = ur->naddrs;
335 peers->name = &ur->host;
336
Igor Sysoev302cedc2008-12-23 19:35:12 +0000337 if (ur->sockaddr) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400338 peer[0].sockaddr = ur->sockaddr;
339 peer[0].socklen = ur->socklen;
Ruslan Ermilovf043ecf2016-10-31 18:33:33 +0300340 peer[0].name = ur->name.data ? ur->name : ur->host;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400341 peer[0].weight = 1;
342 peer[0].effective_weight = 1;
343 peer[0].current_weight = 0;
Ruslan Ermilov49dec842016-09-22 19:32:47 +0300344 peer[0].max_conns = 0;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400345 peer[0].max_fails = 1;
346 peer[0].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300347 peers->peer = peer;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000348
Igor Sysoev302cedc2008-12-23 19:35:12 +0000349 } else {
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300350 peerp = &peers->peer;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000351
Igor Sysoev302cedc2008-12-23 19:35:12 +0000352 for (i = 0; i < ur->naddrs; i++) {
353
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400354 socklen = ur->addrs[i].socklen;
Igor Sysoev302cedc2008-12-23 19:35:12 +0000355
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400356 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);
Roman Arutyunyan85a0ab52016-06-20 11:50:39 +0300362 ngx_inet_set_port(sockaddr, ur->port);
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400363
364 p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
Igor Sysoev302cedc2008-12-23 19:35:12 +0000365 if (p == NULL) {
366 return NGX_ERROR;
367 }
368
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400369 len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
Igor Sysoev302cedc2008-12-23 19:35:12 +0000370
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400371 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;
Ruslan Ermilov49dec842016-09-22 19:32:47 +0300378 peer[i].max_conns = 0;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400379 peer[i].max_fails = 1;
380 peer[i].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300381 *peerp = &peer[i];
382 peerp = &peer[i].next;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000383 }
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000384 }
385
386 rrp->peers = peers;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300387 rrp->current = NULL;
Maxim Dounin144dc692016-09-29 18:06:04 +0300388 rrp->config = 0;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000389
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;
Roman Arutyunyancfc3db12014-09-12 18:50:46 +0400406 r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000407#if (NGX_HTTP_SSL)
Igor Sysoev08b59752011-07-22 16:30:17 +0000408 r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
409 r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000410#endif
411
412 return NGX_OK;
413}
414
415
416ngx_int_t
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000417ngx_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
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000421 ngx_int_t rc;
422 ngx_uint_t i, n;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000423 ngx_http_upstream_rr_peer_t *peer;
424 ngx_http_upstream_rr_peers_t *peers;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000425
426 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
427 "get rr peer, try: %ui", pc->tries);
428
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000429 pc->cached = 0;
430 pc->connection = NULL;
431
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400432 peers = rrp->peers;
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300433 ngx_http_upstream_rr_peers_wlock(peers);
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400434
435 if (peers->single) {
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300436 peer = peers->peer;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000437
Ruslan Ermilov4d0d2b22012-11-16 12:18:05 +0000438 if (peer->down) {
439 goto failed;
440 }
441
Ruslan Ermilov49dec842016-09-22 19:32:47 +0300442 if (peer->max_conns && peer->conns >= peer->max_conns) {
443 goto failed;
444 }
445
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300446 rrp->current = peer;
447
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000448 } else {
449
450 /* there are several peers */
451
Maxim Dounin52327e02012-05-14 09:57:20 +0000452 peer = ngx_http_upstream_get_peer(rrp);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000453
Maxim Dounin52327e02012-05-14 09:57:20 +0000454 if (peer == NULL) {
455 goto failed;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000456 }
457
Maxim Dounin52327e02012-05-14 09:57:20 +0000458 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300459 "get rr peer, current: %p %i",
460 peer, peer->current_weight);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000461 }
462
463 pc->sockaddr = peer->sockaddr;
464 pc->socklen = peer->socklen;
465 pc->name = &peer->name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000466
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300467 peer->conns++;
468
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300469 ngx_http_upstream_rr_peers_unlock(peers);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000470
471 return NGX_OK;
472
473failed:
474
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000475 if (peers->next) {
476
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000477 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
478
479 rrp->peers = peers->next;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000480
Valentin Bartenevdd46cc62012-12-25 08:02:21 +0000481 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
482 / (8 * sizeof(uintptr_t));
483
Igor Sysoevcc076092007-08-14 13:35:52 +0000484 for (i = 0; i < n; i++) {
Ruslan Ermilov2161d8a2016-03-30 11:52:16 +0300485 rrp->tried[i] = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000486 }
487
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300488 ngx_http_upstream_rr_peers_unlock(peers);
489
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000490 rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
491
492 if (rc != NGX_BUSY) {
493 return rc;
494 }
495
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300496 ngx_http_upstream_rr_peers_wlock(peers);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000497 }
498
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300499 ngx_http_upstream_rr_peers_unlock(peers);
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000500
501 pc->name = peers->name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000502
503 return NGX_BUSY;
504}
505
506
Maxim Dounin52327e02012-05-14 09:57:20 +0000507static ngx_http_upstream_rr_peer_t *
508ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
Igor Sysoevd12a5712007-07-28 16:04:01 +0000509{
Maxim Dounin52327e02012-05-14 09:57:20 +0000510 time_t now;
511 uintptr_t m;
512 ngx_int_t total;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300513 ngx_uint_t i, n, p;
Maxim Dounin52327e02012-05-14 09:57:20 +0000514 ngx_http_upstream_rr_peer_t *peer, *best;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000515
Maxim Dounin52327e02012-05-14 09:57:20 +0000516 now = ngx_time();
Igor Sysoevd12a5712007-07-28 16:04:01 +0000517
Maxim Dounin52327e02012-05-14 09:57:20 +0000518 best = NULL;
519 total = 0;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000520
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300521#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 {
Maxim Dounin52327e02012-05-14 09:57:20 +0000529 n = i / (8 * sizeof(uintptr_t));
530 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
Igor Sysoevd12a5712007-07-28 16:04:01 +0000531
Maxim Dounin52327e02012-05-14 09:57:20 +0000532 if (rrp->tried[n] & m) {
533 continue;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000534 }
535
Maxim Dounin52327e02012-05-14 09:57:20 +0000536 if (peer->down) {
537 continue;
Maxim Dounin624fbe92011-08-18 16:52:38 +0000538 }
539
Maxim Dounin52327e02012-05-14 09:57:20 +0000540 if (peer->max_fails
541 && peer->fails >= peer->max_fails
542 && now - peer->checked <= peer->fail_timeout)
543 {
544 continue;
545 }
546
Ruslan Ermilov49dec842016-09-22 19:32:47 +0300547 if (peer->max_conns && peer->conns >= peer->max_conns) {
548 continue;
549 }
550
Maxim Dounin52327e02012-05-14 09:57:20 +0000551 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;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300560 p = i;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000561 }
562 }
Maxim Dounin52327e02012-05-14 09:57:20 +0000563
564 if (best == NULL) {
565 return NULL;
566 }
567
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300568 rrp->current = best;
Maxim Dounin52327e02012-05-14 09:57:20 +0000569
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300570 n = p / (8 * sizeof(uintptr_t));
571 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
Maxim Dounin52327e02012-05-14 09:57:20 +0000572
573 rrp->tried[n] |= m;
574
575 best->current_weight -= total;
Maxim Dounina1ab0dd2013-05-21 21:47:50 +0400576
577 if (now - best->checked > best->fail_timeout) {
578 best->checked = now;
579 }
Maxim Dounin52327e02012-05-14 09:57:20 +0000580
581 return best;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000582}
583
584
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000585void
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
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000597 /* TODO: NGX_PEER_KEEPALIVE */
598
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300599 peer = rrp->current;
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300600
Ruslan Ermilovc7236ff2015-04-19 22:41:09 +0300601 ngx_http_upstream_rr_peers_rlock(rrp->peers);
602 ngx_http_upstream_rr_peer_lock(rrp->peers, peer);
603
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000604 if (rrp->peers->single) {
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300605
606 peer->conns--;
607
Ruslan Ermilovc7236ff2015-04-19 22:41:09 +0300608 ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
609 ngx_http_upstream_rr_peers_unlock(rrp->peers);
610
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000611 pc->tries = 0;
612 return;
613 }
614
615 if (state & NGX_PEER_FAILED) {
616 now = ngx_time();
617
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000618 peer->fails++;
619 peer->accessed = now;
Maxim Douninb713e482011-10-12 14:22:48 +0000620 peer->checked = now;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000621
Igor Sysoev333723e2008-08-26 14:34:16 +0000622 if (peer->max_fails) {
Maxim Dounin52327e02012-05-14 09:57:20 +0000623 peer->effective_weight -= peer->weight / peer->max_fails;
Ruslan Ermilov39566f72015-05-20 22:44:00 +0300624
625 if (peer->fails >= peer->max_fails) {
626 ngx_log_error(NGX_LOG_WARN, pc->log, 0,
627 "upstream server temporarily disabled");
628 }
Igor Sysoev333723e2008-08-26 14:34:16 +0000629 }
Igor Sysoevd12a5712007-07-28 16:04:01 +0000630
631 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300632 "free rr peer failed: %p %i",
633 peer, peer->effective_weight);
Igor Sysoevd12a5712007-07-28 16:04:01 +0000634
Maxim Dounin52327e02012-05-14 09:57:20 +0000635 if (peer->effective_weight < 0) {
636 peer->effective_weight = 0;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000637 }
638
Maxim Douninb713e482011-10-12 14:22:48 +0000639 } else {
640
641 /* mark peer live if check passed */
642
643 if (peer->accessed < peer->checked) {
644 peer->fails = 0;
645 }
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000646 }
647
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300648 peer->conns--;
649
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300650 ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
651 ngx_http_upstream_rr_peers_unlock(rrp->peers);
652
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000653 if (pc->tries) {
654 pc->tries--;
655 }
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000656}
657
658
659#if (NGX_HTTP_SSL)
660
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000661ngx_int_t
662ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
663 void *data)
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000664{
665 ngx_http_upstream_rr_peer_data_t *rrp = data;
666
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300667 ngx_int_t rc;
668 ngx_ssl_session_t *ssl_session;
669 ngx_http_upstream_rr_peer_t *peer;
Piotr Sikorae2690832016-10-16 21:55:37 -0700670#if (NGX_HTTP_UPSTREAM_ZONE || NGX_COMPAT)
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300671 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
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000679
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300680 peer = rrp->current;
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000681
Piotr Sikorae2690832016-10-16 21:55:37 -0700682#if (NGX_HTTP_UPSTREAM_ZONE || NGX_COMPAT)
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300683 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
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000716 ssl_session = peer->ssl_session;
717
718 rc = ngx_ssl_set_session(pc->connection, ssl_session);
719
Piotr Sikorad224ed72014-07-06 16:41:14 -0700720 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
721 "set session: %p", ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000722
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000723 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
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300733 ngx_ssl_session_t *old_ssl_session, *ssl_session;
734 ngx_http_upstream_rr_peer_t *peer;
Piotr Sikorae2690832016-10-16 21:55:37 -0700735#if (NGX_HTTP_UPSTREAM_ZONE || NGX_COMPAT)
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300736 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
Piotr Sikorae2690832016-10-16 21:55:37 -0700742#if (NGX_HTTP_UPSTREAM_ZONE || NGX_COMPAT)
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300743 peers = rrp->peers;
744
745 if (peers->shpool) {
746
Sergey Kandaurov8cd300a2018-07-17 12:53:23 +0300747 ssl_session = ngx_ssl_get0_session(pc->connection);
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300748
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
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000802
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000803 ssl_session = ngx_ssl_get_session(pc->connection);
804
805 if (ssl_session == NULL) {
806 return;
807 }
808
Piotr Sikorad224ed72014-07-06 16:41:14 -0700809 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
810 "save session: %p", ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000811
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300812 peer = rrp->current;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000813
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000814 old_ssl_session = peer->ssl_session;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000815 peer->ssl_session = ssl_session;
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000816
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000817 if (old_ssl_session) {
818
Piotr Sikorad224ed72014-07-06 16:41:14 -0700819 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
820 "old session: %p", old_ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000821
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000822 /* TODO: may block */
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000823
824 ngx_ssl_free_session(old_ssl_session);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000825 }
826}
827
Igor Sysoev08b59752011-07-22 16:30:17 +0000828
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
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000842#endif