blob: 8342dc8eda8318b7d92353a02427c4075a50aa3b [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;
95 peer[n].max_fails = server[i].max_fails;
96 peer[n].fail_timeout = server[i].fail_timeout;
97 peer[n].down = server[i].down;
98 peer[n].server = server[i].name;
Ruslan Ermilov0c957672015-04-10 14:48:36 +030099
100 *peerp = &peer[n];
101 peerp = &peer[n].next;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000102 n++;
103 }
104 }
105
106 us->peer.data = peers;
107
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000108 /* backup servers */
109
110 n = 0;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000111 w = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000112
113 for (i = 0; i < us->servers->nelts; i++) {
114 if (!server[i].backup) {
115 continue;
116 }
117
118 n += server[i].naddrs;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000119 w += server[i].naddrs * server[i].weight;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000120 }
121
122 if (n == 0) {
123 return NGX_OK;
124 }
125
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300126 backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000127 if (backup == NULL) {
128 return NGX_ERROR;
129 }
130
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300131 peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
132 if (peer == NULL) {
133 return NGX_ERROR;
134 }
135
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000136 peers->single = 0;
137 backup->single = 0;
138 backup->number = n;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000139 backup->weighted = (w != n);
140 backup->total_weight = w;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000141 backup->name = &us->host;
142
143 n = 0;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300144 peerp = &backup->peer;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000145
146 for (i = 0; i < us->servers->nelts; i++) {
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +0800147 if (!server[i].backup) {
148 continue;
149 }
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000150
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +0800151 for (j = 0; j < server[i].naddrs; j++) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400152 peer[n].sockaddr = server[i].addrs[j].sockaddr;
153 peer[n].socklen = server[i].addrs[j].socklen;
154 peer[n].name = server[i].addrs[j].name;
155 peer[n].weight = server[i].weight;
156 peer[n].effective_weight = server[i].weight;
157 peer[n].current_weight = 0;
158 peer[n].max_fails = server[i].max_fails;
159 peer[n].fail_timeout = server[i].fail_timeout;
160 peer[n].down = server[i].down;
161 peer[n].server = server[i].name;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300162
163 *peerp = &peer[n];
164 peerp = &peer[n].next;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000165 n++;
166 }
167 }
168
169 peers->next = backup;
170
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000171 return NGX_OK;
172 }
173
174
175 /* an upstream implicitly defined by proxy_pass, etc. */
176
Ruslan Ermilova2a22912013-01-10 12:58:55 +0000177 if (us->port == 0) {
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000178 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
179 "no port in upstream \"%V\" in %s:%ui",
Igor Sysoev4b96baa2007-09-15 17:11:06 +0000180 &us->host, us->file_name, us->line);
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000181 return NGX_ERROR;
182 }
183
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000184 ngx_memzero(&u, sizeof(ngx_url_t));
185
186 u.host = us->host;
Ruslan Ermilova2a22912013-01-10 12:58:55 +0000187 u.port = us->port;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000188
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000189 if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000190 if (u.err) {
191 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
Igor Sysoev5d118d32006-12-11 08:59:30 +0000192 "%s in upstream \"%V\" in %s:%ui",
Igor Sysoev4b96baa2007-09-15 17:11:06 +0000193 u.err, &us->host, us->file_name, us->line);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000194 }
195
196 return NGX_ERROR;
197 }
198
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000199 n = u.naddrs;
200
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300201 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000202 if (peers == NULL) {
203 return NGX_ERROR;
204 }
205
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300206 peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
207 if (peer == NULL) {
208 return NGX_ERROR;
209 }
210
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000211 peers->single = (n == 1);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000212 peers->number = n;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000213 peers->weighted = 0;
214 peers->total_weight = n;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000215 peers->name = &us->host;
216
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300217 peerp = &peers->peer;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400218
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000219 for (i = 0; i < u.naddrs; i++) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400220 peer[i].sockaddr = u.addrs[i].sockaddr;
221 peer[i].socklen = u.addrs[i].socklen;
222 peer[i].name = u.addrs[i].name;
223 peer[i].weight = 1;
224 peer[i].effective_weight = 1;
225 peer[i].current_weight = 0;
226 peer[i].max_fails = 1;
227 peer[i].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300228 *peerp = &peer[i];
229 peerp = &peer[i].next;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000230 }
231
232 us->peer.data = peers;
233
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000234 /* implicitly defined upstream has no backup servers */
235
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000236 return NGX_OK;
237}
238
239
240ngx_int_t
241ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
242 ngx_http_upstream_srv_conf_t *us)
243{
244 ngx_uint_t n;
245 ngx_http_upstream_rr_peer_data_t *rrp;
246
247 rrp = r->upstream->peer.data;
248
249 if (rrp == NULL) {
250 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
251 if (rrp == NULL) {
252 return NGX_ERROR;
253 }
254
255 r->upstream->peer.data = rrp;
256 }
257
258 rrp->peers = us->peer.data;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300259 rrp->current = NULL;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000260
Maxim Douninb7fcb432011-08-18 17:04:52 +0000261 n = rrp->peers->number;
262
263 if (rrp->peers->next && rrp->peers->next->number > n) {
264 n = rrp->peers->next->number;
265 }
266
267 if (n <= 8 * sizeof(uintptr_t)) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000268 rrp->tried = &rrp->data;
269 rrp->data = 0;
270
271 } else {
Maxim Douninb7fcb432011-08-18 17:04:52 +0000272 n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000273
274 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
275 if (rrp->tried == NULL) {
276 return NGX_ERROR;
277 }
278 }
279
280 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
281 r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
Roman Arutyunyancfc3db12014-09-12 18:50:46 +0400282 r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000283#if (NGX_HTTP_SSL)
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000284 r->upstream->peer.set_session =
285 ngx_http_upstream_set_round_robin_peer_session;
286 r->upstream->peer.save_session =
287 ngx_http_upstream_save_round_robin_peer_session;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000288#endif
289
290 return NGX_OK;
291}
292
293
294ngx_int_t
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000295ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
296 ngx_http_upstream_resolved_t *ur)
297{
298 u_char *p;
299 size_t len;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400300 socklen_t socklen;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000301 ngx_uint_t i, n;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400302 struct sockaddr *sockaddr;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300303 ngx_http_upstream_rr_peer_t *peer, **peerp;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000304 ngx_http_upstream_rr_peers_t *peers;
305 ngx_http_upstream_rr_peer_data_t *rrp;
306
307 rrp = r->upstream->peer.data;
308
309 if (rrp == NULL) {
310 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
311 if (rrp == NULL) {
312 return NGX_ERROR;
313 }
314
315 r->upstream->peer.data = rrp;
316 }
317
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300318 peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000319 if (peers == NULL) {
320 return NGX_ERROR;
321 }
322
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300323 peer = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peer_t)
324 * ur->naddrs);
325 if (peer == NULL) {
326 return NGX_ERROR;
327 }
328
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000329 peers->single = (ur->naddrs == 1);
330 peers->number = ur->naddrs;
331 peers->name = &ur->host;
332
Igor Sysoev302cedc2008-12-23 19:35:12 +0000333 if (ur->sockaddr) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400334 peer[0].sockaddr = ur->sockaddr;
335 peer[0].socklen = ur->socklen;
336 peer[0].name = ur->host;
337 peer[0].weight = 1;
338 peer[0].effective_weight = 1;
339 peer[0].current_weight = 0;
340 peer[0].max_fails = 1;
341 peer[0].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300342 peers->peer = peer;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000343
Igor Sysoev302cedc2008-12-23 19:35:12 +0000344 } else {
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300345 peerp = &peers->peer;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000346
Igor Sysoev302cedc2008-12-23 19:35:12 +0000347 for (i = 0; i < ur->naddrs; i++) {
348
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400349 socklen = ur->addrs[i].socklen;
Igor Sysoev302cedc2008-12-23 19:35:12 +0000350
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400351 sockaddr = ngx_palloc(r->pool, socklen);
352 if (sockaddr == NULL) {
353 return NGX_ERROR;
354 }
355
356 ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
357
358 switch (sockaddr->sa_family) {
359#if (NGX_HAVE_INET6)
360 case AF_INET6:
361 ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(ur->port);
362 break;
363#endif
364 default: /* AF_INET */
365 ((struct sockaddr_in *) sockaddr)->sin_port = htons(ur->port);
366 }
367
368 p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
Igor Sysoev302cedc2008-12-23 19:35:12 +0000369 if (p == NULL) {
370 return NGX_ERROR;
371 }
372
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400373 len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
Igor Sysoev302cedc2008-12-23 19:35:12 +0000374
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400375 peer[i].sockaddr = sockaddr;
376 peer[i].socklen = socklen;
377 peer[i].name.len = len;
378 peer[i].name.data = p;
379 peer[i].weight = 1;
380 peer[i].effective_weight = 1;
381 peer[i].current_weight = 0;
382 peer[i].max_fails = 1;
383 peer[i].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300384 *peerp = &peer[i];
385 peerp = &peer[i].next;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000386 }
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000387 }
388
389 rrp->peers = peers;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300390 rrp->current = NULL;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000391
392 if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
393 rrp->tried = &rrp->data;
394 rrp->data = 0;
395
396 } else {
397 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
398 / (8 * sizeof(uintptr_t));
399
400 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
401 if (rrp->tried == NULL) {
402 return NGX_ERROR;
403 }
404 }
405
406 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
407 r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
Roman Arutyunyancfc3db12014-09-12 18:50:46 +0400408 r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000409#if (NGX_HTTP_SSL)
Igor Sysoev08b59752011-07-22 16:30:17 +0000410 r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
411 r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000412#endif
413
414 return NGX_OK;
415}
416
417
418ngx_int_t
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000419ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
420{
421 ngx_http_upstream_rr_peer_data_t *rrp = data;
422
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000423 ngx_int_t rc;
424 ngx_uint_t i, n;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000425 ngx_http_upstream_rr_peer_t *peer;
426 ngx_http_upstream_rr_peers_t *peers;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000427
428 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
429 "get rr peer, try: %ui", pc->tries);
430
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000431 pc->cached = 0;
432 pc->connection = NULL;
433
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400434 peers = rrp->peers;
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300435 ngx_http_upstream_rr_peers_wlock(peers);
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400436
437 if (peers->single) {
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300438 peer = peers->peer;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000439
Ruslan Ermilov4d0d2b22012-11-16 12:18:05 +0000440 if (peer->down) {
441 goto failed;
442 }
443
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300444 rrp->current = peer;
445
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000446 } else {
447
448 /* there are several peers */
449
Maxim Dounin52327e02012-05-14 09:57:20 +0000450 peer = ngx_http_upstream_get_peer(rrp);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000451
Maxim Dounin52327e02012-05-14 09:57:20 +0000452 if (peer == NULL) {
453 goto failed;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000454 }
455
Maxim Dounin52327e02012-05-14 09:57:20 +0000456 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300457 "get rr peer, current: %p %i",
458 peer, peer->current_weight);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000459 }
460
461 pc->sockaddr = peer->sockaddr;
462 pc->socklen = peer->socklen;
463 pc->name = &peer->name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000464
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300465 peer->conns++;
466
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300467 ngx_http_upstream_rr_peers_unlock(peers);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000468
469 return NGX_OK;
470
471failed:
472
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000473 if (peers->next) {
474
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000475 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
476
477 rrp->peers = peers->next;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000478
Valentin Bartenevdd46cc62012-12-25 08:02:21 +0000479 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
480 / (8 * sizeof(uintptr_t));
481
Igor Sysoevcc076092007-08-14 13:35:52 +0000482 for (i = 0; i < n; i++) {
Ruslan Ermilov2161d8a2016-03-30 11:52:16 +0300483 rrp->tried[i] = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000484 }
485
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300486 ngx_http_upstream_rr_peers_unlock(peers);
487
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000488 rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
489
490 if (rc != NGX_BUSY) {
491 return rc;
492 }
493
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300494 ngx_http_upstream_rr_peers_wlock(peers);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000495 }
496
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000497 /* all peers failed, mark them as live for quick recovery */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000498
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300499 for (peer = peers->peer; peer; peer = peer->next) {
500 peer->fails = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000501 }
502
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300503 ngx_http_upstream_rr_peers_unlock(peers);
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000504
505 pc->name = peers->name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000506
507 return NGX_BUSY;
508}
509
510
Maxim Dounin52327e02012-05-14 09:57:20 +0000511static ngx_http_upstream_rr_peer_t *
512ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
Igor Sysoevd12a5712007-07-28 16:04:01 +0000513{
Maxim Dounin52327e02012-05-14 09:57:20 +0000514 time_t now;
515 uintptr_t m;
516 ngx_int_t total;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300517 ngx_uint_t i, n, p;
Maxim Dounin52327e02012-05-14 09:57:20 +0000518 ngx_http_upstream_rr_peer_t *peer, *best;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000519
Maxim Dounin52327e02012-05-14 09:57:20 +0000520 now = ngx_time();
Igor Sysoevd12a5712007-07-28 16:04:01 +0000521
Maxim Dounin52327e02012-05-14 09:57:20 +0000522 best = NULL;
523 total = 0;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000524
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300525#if (NGX_SUPPRESS_WARN)
526 p = 0;
527#endif
528
529 for (peer = rrp->peers->peer, i = 0;
530 peer;
531 peer = peer->next, i++)
532 {
Igor Sysoevd12a5712007-07-28 16:04:01 +0000533
Maxim Dounin52327e02012-05-14 09:57:20 +0000534 n = i / (8 * sizeof(uintptr_t));
535 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
Igor Sysoevd12a5712007-07-28 16:04:01 +0000536
Maxim Dounin52327e02012-05-14 09:57:20 +0000537 if (rrp->tried[n] & m) {
538 continue;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000539 }
540
Maxim Dounin52327e02012-05-14 09:57:20 +0000541 if (peer->down) {
542 continue;
Maxim Dounin624fbe92011-08-18 16:52:38 +0000543 }
544
Maxim Dounin52327e02012-05-14 09:57:20 +0000545 if (peer->max_fails
546 && peer->fails >= peer->max_fails
547 && now - peer->checked <= peer->fail_timeout)
548 {
549 continue;
550 }
551
552 peer->current_weight += peer->effective_weight;
553 total += peer->effective_weight;
554
555 if (peer->effective_weight < peer->weight) {
556 peer->effective_weight++;
557 }
558
559 if (best == NULL || peer->current_weight > best->current_weight) {
560 best = peer;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300561 p = i;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000562 }
563 }
Maxim Dounin52327e02012-05-14 09:57:20 +0000564
565 if (best == NULL) {
566 return NULL;
567 }
568
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300569 rrp->current = best;
Maxim Dounin52327e02012-05-14 09:57:20 +0000570
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300571 n = p / (8 * sizeof(uintptr_t));
572 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
Maxim Dounin52327e02012-05-14 09:57:20 +0000573
574 rrp->tried[n] |= m;
575
576 best->current_weight -= total;
Maxim Dounina1ab0dd2013-05-21 21:47:50 +0400577
578 if (now - best->checked > best->fail_timeout) {
579 best->checked = now;
580 }
Maxim Dounin52327e02012-05-14 09:57:20 +0000581
582 return best;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000583}
584
585
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000586void
587ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
588 ngx_uint_t state)
589{
590 ngx_http_upstream_rr_peer_data_t *rrp = data;
591
592 time_t now;
593 ngx_http_upstream_rr_peer_t *peer;
594
595 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
596 "free rr peer %ui %ui", pc->tries, state);
597
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000598 /* TODO: NGX_PEER_KEEPALIVE */
599
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300600 peer = rrp->current;
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300601
Ruslan Ermilovc7236ff2015-04-19 22:41:09 +0300602 ngx_http_upstream_rr_peers_rlock(rrp->peers);
603 ngx_http_upstream_rr_peer_lock(rrp->peers, peer);
604
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000605 if (rrp->peers->single) {
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300606
607 peer->conns--;
608
Ruslan Ermilovc7236ff2015-04-19 22:41:09 +0300609 ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
610 ngx_http_upstream_rr_peers_unlock(rrp->peers);
611
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000612 pc->tries = 0;
613 return;
614 }
615
616 if (state & NGX_PEER_FAILED) {
617 now = ngx_time();
618
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000619 peer->fails++;
620 peer->accessed = now;
Maxim Douninb713e482011-10-12 14:22:48 +0000621 peer->checked = now;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000622
Igor Sysoev333723e2008-08-26 14:34:16 +0000623 if (peer->max_fails) {
Maxim Dounin52327e02012-05-14 09:57:20 +0000624 peer->effective_weight -= peer->weight / peer->max_fails;
Ruslan Ermilov39566f72015-05-20 22:44:00 +0300625
626 if (peer->fails >= peer->max_fails) {
627 ngx_log_error(NGX_LOG_WARN, pc->log, 0,
628 "upstream server temporarily disabled");
629 }
Igor Sysoev333723e2008-08-26 14:34:16 +0000630 }
Igor Sysoevd12a5712007-07-28 16:04:01 +0000631
632 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300633 "free rr peer failed: %p %i",
634 peer, peer->effective_weight);
Igor Sysoevd12a5712007-07-28 16:04:01 +0000635
Maxim Dounin52327e02012-05-14 09:57:20 +0000636 if (peer->effective_weight < 0) {
637 peer->effective_weight = 0;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000638 }
639
Maxim Douninb713e482011-10-12 14:22:48 +0000640 } else {
641
642 /* mark peer live if check passed */
643
644 if (peer->accessed < peer->checked) {
645 peer->fails = 0;
646 }
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000647 }
648
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300649 peer->conns--;
650
Ruslan Ermilov5019f9e2015-04-14 19:01:23 +0300651 ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
652 ngx_http_upstream_rr_peers_unlock(rrp->peers);
653
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000654 if (pc->tries) {
655 pc->tries--;
656 }
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000657}
658
659
660#if (NGX_HTTP_SSL)
661
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000662ngx_int_t
663ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
664 void *data)
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000665{
666 ngx_http_upstream_rr_peer_data_t *rrp = data;
667
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300668 ngx_int_t rc;
669 ngx_ssl_session_t *ssl_session;
670 ngx_http_upstream_rr_peer_t *peer;
671#if (NGX_HTTP_UPSTREAM_ZONE)
672 int len;
673#if OPENSSL_VERSION_NUMBER >= 0x0090707fL
674 const
675#endif
676 u_char *p;
677 ngx_http_upstream_rr_peers_t *peers;
678 u_char buf[NGX_SSL_MAX_SESSION_SIZE];
679#endif
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000680
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300681 peer = rrp->current;
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000682
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300683#if (NGX_HTTP_UPSTREAM_ZONE)
684 peers = rrp->peers;
685
686 if (peers->shpool) {
687 ngx_http_upstream_rr_peers_rlock(peers);
688 ngx_http_upstream_rr_peer_lock(peers, peer);
689
690 if (peer->ssl_session == NULL) {
691 ngx_http_upstream_rr_peer_unlock(peers, peer);
692 ngx_http_upstream_rr_peers_unlock(peers);
693 return NGX_OK;
694 }
695
696 len = peer->ssl_session_len;
697
698 ngx_memcpy(buf, peer->ssl_session, len);
699
700 ngx_http_upstream_rr_peer_unlock(peers, peer);
701 ngx_http_upstream_rr_peers_unlock(peers);
702
703 p = buf;
704 ssl_session = d2i_SSL_SESSION(NULL, &p, len);
705
706 rc = ngx_ssl_set_session(pc->connection, ssl_session);
707
708 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
709 "set session: %p", ssl_session);
710
711 ngx_ssl_free_session(ssl_session);
712
713 return rc;
714 }
715#endif
716
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000717 ssl_session = peer->ssl_session;
718
719 rc = ngx_ssl_set_session(pc->connection, ssl_session);
720
Piotr Sikorad224ed72014-07-06 16:41:14 -0700721 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
722 "set session: %p", ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000723
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000724 return rc;
725}
726
727
728void
729ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
730 void *data)
731{
732 ngx_http_upstream_rr_peer_data_t *rrp = data;
733
Ruslan Ermilovbbc5a9e2015-04-14 19:01:25 +0300734 ngx_ssl_session_t *old_ssl_session, *ssl_session;
735 ngx_http_upstream_rr_peer_t *peer;
736#if (NGX_HTTP_UPSTREAM_ZONE)
737 int len;
738 u_char *p;
739 ngx_http_upstream_rr_peers_t *peers;
740 u_char buf[NGX_SSL_MAX_SESSION_SIZE];
741#endif
742
743#if (NGX_HTTP_UPSTREAM_ZONE)
744 peers = rrp->peers;
745
746 if (peers->shpool) {
747
748 ssl_session = SSL_get0_session(pc->connection->ssl->connection);
749
750 if (ssl_session == NULL) {
751 return;
752 }
753
754 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
755 "save session: %p", ssl_session);
756
757 len = i2d_SSL_SESSION(ssl_session, NULL);
758
759 /* do not cache too big session */
760
761 if (len > NGX_SSL_MAX_SESSION_SIZE) {
762 return;
763 }
764
765 p = buf;
766 (void) i2d_SSL_SESSION(ssl_session, &p);
767
768 peer = rrp->current;
769
770 ngx_http_upstream_rr_peers_rlock(peers);
771 ngx_http_upstream_rr_peer_lock(peers, peer);
772
773 if (len > peer->ssl_session_len) {
774 ngx_shmtx_lock(&peers->shpool->mutex);
775
776 if (peer->ssl_session) {
777 ngx_slab_free_locked(peers->shpool, peer->ssl_session);
778 }
779
780 peer->ssl_session = ngx_slab_alloc_locked(peers->shpool, len);
781
782 ngx_shmtx_unlock(&peers->shpool->mutex);
783
784 if (peer->ssl_session == NULL) {
785 peer->ssl_session_len = 0;
786
787 ngx_http_upstream_rr_peer_unlock(peers, peer);
788 ngx_http_upstream_rr_peers_unlock(peers);
789 return;
790 }
791
792 peer->ssl_session_len = len;
793 }
794
795 ngx_memcpy(peer->ssl_session, buf, len);
796
797 ngx_http_upstream_rr_peer_unlock(peers, peer);
798 ngx_http_upstream_rr_peers_unlock(peers);
799
800 return;
801 }
802#endif
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000803
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000804 ssl_session = ngx_ssl_get_session(pc->connection);
805
806 if (ssl_session == NULL) {
807 return;
808 }
809
Piotr Sikorad224ed72014-07-06 16:41:14 -0700810 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
811 "save session: %p", ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000812
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300813 peer = rrp->current;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000814
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000815 old_ssl_session = peer->ssl_session;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000816 peer->ssl_session = ssl_session;
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000817
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000818 if (old_ssl_session) {
819
Piotr Sikorad224ed72014-07-06 16:41:14 -0700820 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
821 "old session: %p", old_ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000822
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000823 /* TODO: may block */
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000824
825 ngx_ssl_free_session(old_ssl_session);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000826 }
827}
828
Igor Sysoev08b59752011-07-22 16:30:17 +0000829
830static ngx_int_t
831ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
832{
833 return NGX_OK;
834}
835
836
837static void
838ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
839{
840 return;
841}
842
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000843#endif