/src/haproxy/src/backend.c
Line | Count | Source |
1 | | /* |
2 | | * Backend variables and functions. |
3 | | * |
4 | | * Copyright 2000-2013 Willy Tarreau <w@1wt.eu> |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU General Public License |
8 | | * as published by the Free Software Foundation; either version |
9 | | * 2 of the License, or (at your option) any later version. |
10 | | * |
11 | | */ |
12 | | |
13 | | #include <errno.h> |
14 | | #include <stdio.h> |
15 | | #include <stdlib.h> |
16 | | #include <syslog.h> |
17 | | #include <string.h> |
18 | | #include <ctype.h> |
19 | | #include <sys/types.h> |
20 | | |
21 | | #include <import/ceb64_tree.h> |
22 | | |
23 | | #include <haproxy/api.h> |
24 | | #include <haproxy/acl.h> |
25 | | #include <haproxy/activity.h> |
26 | | #include <haproxy/arg.h> |
27 | | #include <haproxy/backend.h> |
28 | | #include <haproxy/channel.h> |
29 | | #include <haproxy/check.h> |
30 | | #include <haproxy/counters.h> |
31 | | #include <haproxy/frontend.h> |
32 | | #include <haproxy/global.h> |
33 | | #include <haproxy/hash.h> |
34 | | #include <haproxy/http.h> |
35 | | #include <haproxy/http_ana.h> |
36 | | #include <haproxy/http_htx.h> |
37 | | #include <haproxy/htx.h> |
38 | | #include <haproxy/lb_chash.h> |
39 | | #include <haproxy/lb_fas.h> |
40 | | #include <haproxy/lb_fwlc.h> |
41 | | #include <haproxy/lb_fwrr.h> |
42 | | #include <haproxy/lb_map.h> |
43 | | #include <haproxy/lb_ss.h> |
44 | | #include <haproxy/log.h> |
45 | | #include <haproxy/namespace.h> |
46 | | #include <haproxy/obj_type.h> |
47 | | #include <haproxy/payload.h> |
48 | | #include <haproxy/proto_tcp.h> |
49 | | #include <haproxy/protocol.h> |
50 | | #include <haproxy/proxy.h> |
51 | | #include <haproxy/queue.h> |
52 | | #include <haproxy/sample.h> |
53 | | #include <haproxy/sc_strm.h> |
54 | | #include <haproxy/server.h> |
55 | | #include <haproxy/session.h> |
56 | | #include <haproxy/ssl_sock.h> |
57 | | #include <haproxy/stconn.h> |
58 | | #include <haproxy/stream.h> |
59 | | #include <haproxy/task.h> |
60 | | #include <haproxy/ticks.h> |
61 | | #include <haproxy/time.h> |
62 | | #include <haproxy/tools.h> |
63 | | #include <haproxy/trace.h> |
64 | | |
65 | | #define TRACE_SOURCE &trace_strm |
66 | | |
67 | | struct list lb_ops_list = LIST_HEAD_INIT(lb_ops_list); |
68 | | |
69 | | void lb_ops_register(struct lb_ops *ops) |
70 | 0 | { |
71 | 0 | LIST_APPEND(&lb_ops_list, &ops->link); |
72 | 0 | } |
73 | | |
74 | | /* helper function to invoke the correct hash method */ |
75 | | unsigned int gen_hash(const struct proxy* px, const char* key, unsigned long len) |
76 | 0 | { |
77 | 0 | unsigned int hash; |
78 | |
|
79 | 0 | switch (px->lbprm.algo & BE_LB_HASH_FUNC) { |
80 | 0 | case BE_LB_HFCN_DJB2: |
81 | 0 | hash = hash_djb2(key, len); |
82 | 0 | break; |
83 | 0 | case BE_LB_HFCN_WT6: |
84 | 0 | hash = hash_wt6(key, len); |
85 | 0 | break; |
86 | 0 | case BE_LB_HFCN_CRC32: |
87 | 0 | hash = hash_crc32(key, len); |
88 | 0 | break; |
89 | 0 | case BE_LB_HFCN_NONE: |
90 | | /* use key as a hash. It MUST be in string format */ |
91 | 0 | { |
92 | 0 | const char *_key = key; |
93 | |
|
94 | 0 | hash = read_int64(&_key, _key + len); |
95 | 0 | } |
96 | 0 | break; |
97 | 0 | case BE_LB_HFCN_SDBM: |
98 | | /* this is the default hash function */ |
99 | 0 | default: |
100 | 0 | hash = hash_sdbm(key, len); |
101 | 0 | break; |
102 | 0 | } |
103 | | |
104 | 0 | if ((px->lbprm.algo & BE_LB_HASH_MOD) == BE_LB_HMOD_AVAL) |
105 | 0 | hash = full_hash(hash); |
106 | |
|
107 | 0 | return hash; |
108 | 0 | } |
109 | | |
110 | | /* |
111 | | * This function recounts the number of usable active and backup servers for |
112 | | * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck. |
113 | | * This function also recomputes the total active and backup weights. However, |
114 | | * it does not update tot_weight nor tot_used. Use update_backend_weight() for |
115 | | * this. |
116 | | * This functions is designed to be called before server's weight and state |
117 | | * commit so it uses 'next' weight and states values. |
118 | | * |
119 | | * threads: this is the caller responsibility to lock data. For now, this |
120 | | * function is called from lb modules, so it should be ok. But if you need to |
121 | | * call it from another place, be careful (and update this comment). |
122 | | */ |
123 | | void recount_servers(struct proxy *px) |
124 | 0 | { |
125 | 0 | struct server *srv; |
126 | |
|
127 | 0 | px->srv_act = px->srv_bck = 0; |
128 | 0 | px->lbprm.tot_wact = px->lbprm.tot_wbck = 0; |
129 | 0 | px->lbprm.fbck = NULL; |
130 | 0 | for (srv = px->srv; srv != NULL; srv = srv->next) { |
131 | 0 | if (!srv_willbe_usable(srv)) |
132 | 0 | continue; |
133 | | |
134 | 0 | if (srv->flags & SRV_F_BACKUP) { |
135 | 0 | if (!px->srv_bck && |
136 | 0 | !(px->options & PR_O_USE_ALL_BK)) |
137 | 0 | px->lbprm.fbck = srv; |
138 | 0 | px->srv_bck++; |
139 | 0 | srv->cumulative_weight = px->lbprm.tot_wbck; |
140 | 0 | px->lbprm.tot_wbck += srv->next_eweight; |
141 | 0 | } else { |
142 | 0 | px->srv_act++; |
143 | 0 | srv->cumulative_weight = px->lbprm.tot_wact; |
144 | 0 | px->lbprm.tot_wact += srv->next_eweight; |
145 | 0 | } |
146 | 0 | } |
147 | 0 | } |
148 | | |
149 | | /* This function simply updates the backend's tot_weight and tot_used values |
150 | | * after servers weights have been updated. It is designed to be used after |
151 | | * recount_servers() or equivalent. |
152 | | * |
153 | | * threads: this is the caller responsibility to lock data. For now, this |
154 | | * function is called from lb modules, so it should be ok. But if you need to |
155 | | * call it from another place, be careful (and update this comment). |
156 | | */ |
157 | | void update_backend_weight(struct proxy *px) |
158 | 0 | { |
159 | 0 | if (px->srv_act) { |
160 | 0 | px->lbprm.tot_weight = px->lbprm.tot_wact; |
161 | 0 | px->lbprm.tot_used = px->srv_act; |
162 | 0 | } |
163 | 0 | else if (px->lbprm.fbck) { |
164 | | /* use only the first backup server */ |
165 | 0 | px->lbprm.tot_weight = px->lbprm.fbck->next_eweight; |
166 | 0 | px->lbprm.tot_used = 1; |
167 | 0 | } |
168 | 0 | else { |
169 | 0 | px->lbprm.tot_weight = px->lbprm.tot_wbck; |
170 | 0 | px->lbprm.tot_used = px->srv_bck; |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | | /* |
175 | | * This function tries to find a running server for the proxy <px> following |
176 | | * the source hash method. Depending on the number of active/backup servers, |
177 | | * it will either look for active servers, or for backup servers. |
178 | | * If any server is found, it will be returned. If no valid server is found, |
179 | | * NULL is returned. |
180 | | */ |
181 | | struct server *get_server_sh(struct proxy *px, const char *addr, int len, const struct server *avoid) |
182 | 0 | { |
183 | 0 | unsigned int h, l; |
184 | |
|
185 | 0 | if (px->lbprm.tot_weight == 0) |
186 | 0 | return NULL; |
187 | | |
188 | 0 | l = h = 0; |
189 | | |
190 | | /* note: we won't hash if there's only one server left */ |
191 | 0 | if (px->lbprm.tot_used == 1) |
192 | 0 | goto hash_done; |
193 | | |
194 | 0 | while ((l + sizeof (int)) <= len) { |
195 | 0 | h ^= ntohl(*(unsigned int *)(&addr[l])); |
196 | 0 | l += sizeof (int); |
197 | 0 | } |
198 | | /* FIXME: why don't we use gen_hash() here as well? |
199 | | * -> we don't take into account hash function from "hash_type" |
200 | | * options here.. |
201 | | */ |
202 | 0 | if ((px->lbprm.algo & BE_LB_HASH_MOD) == BE_LB_HMOD_AVAL) |
203 | 0 | h = full_hash(h); |
204 | 0 | hash_done: |
205 | 0 | if ((px->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_CHTREE) |
206 | 0 | return chash_get_server_hash(px, h, avoid); |
207 | 0 | else |
208 | 0 | return map_get_server_hash(px, h); |
209 | 0 | } |
210 | | |
211 | | /* |
212 | | * This function tries to find a running server for the proxy <px> following |
213 | | * the URI hash method. In order to optimize cache hits, the hash computation |
214 | | * ends at the question mark. Depending on the number of active/backup servers, |
215 | | * it will either look for active servers, or for backup servers. |
216 | | * If any server is found, it will be returned. If no valid server is found, |
217 | | * NULL is returned. The lbprm.arg_opt{1,2,3} values correspond respectively to |
218 | | * the "whole" optional argument (boolean, bit0), the "len" argument (numeric) |
219 | | * and the "depth" argument (numeric). |
220 | | * |
221 | | * This code was contributed by Guillaume Dallaire, who also selected this hash |
222 | | * algorithm out of a tens because it gave him the best results. |
223 | | * |
224 | | */ |
225 | | struct server *get_server_uh(struct proxy *px, char *uri, int uri_len, const struct server *avoid) |
226 | 0 | { |
227 | 0 | unsigned int hash = 0; |
228 | 0 | int c; |
229 | 0 | int slashes = 0; |
230 | 0 | const char *start, *end; |
231 | |
|
232 | 0 | if (px->lbprm.tot_weight == 0) |
233 | 0 | return NULL; |
234 | | |
235 | | /* note: we won't hash if there's only one server left */ |
236 | 0 | if (px->lbprm.tot_used == 1) |
237 | 0 | goto hash_done; |
238 | | |
239 | 0 | if (px->lbprm.arg_opt2) // "len" |
240 | 0 | uri_len = MIN(uri_len, px->lbprm.arg_opt2); |
241 | |
|
242 | 0 | start = end = uri; |
243 | 0 | while (uri_len--) { |
244 | 0 | c = *end; |
245 | 0 | if (c == '/') { |
246 | 0 | slashes++; |
247 | 0 | if (slashes == px->lbprm.arg_opt3) /* depth+1 */ |
248 | 0 | break; |
249 | 0 | } |
250 | 0 | else if (c == '?' && !(px->lbprm.arg_opt1 & 1)) // "whole" |
251 | 0 | break; |
252 | 0 | end++; |
253 | 0 | } |
254 | |
|
255 | 0 | hash = gen_hash(px, start, (end - start)); |
256 | |
|
257 | 0 | hash_done: |
258 | 0 | if ((px->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_CHTREE) |
259 | 0 | return chash_get_server_hash(px, hash, avoid); |
260 | 0 | else |
261 | 0 | return map_get_server_hash(px, hash); |
262 | 0 | } |
263 | | |
264 | | /* |
265 | | * This function tries to find a running server for the proxy <px> following |
266 | | * the URL parameter hash method. It looks for a specific parameter in the |
267 | | * URL and hashes it to compute the server ID. This is useful to optimize |
268 | | * performance by avoiding bounces between servers in contexts where sessions |
269 | | * are shared but cookies are not usable. If the parameter is not found, NULL |
270 | | * is returned. If any server is found, it will be returned. If no valid server |
271 | | * is found, NULL is returned. |
272 | | */ |
273 | | struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len, const struct server *avoid) |
274 | 0 | { |
275 | 0 | unsigned int hash = 0; |
276 | 0 | const char *start, *end; |
277 | 0 | const char *p; |
278 | 0 | const char *params; |
279 | 0 | int plen; |
280 | | |
281 | | /* when tot_weight is 0 then so is srv_count */ |
282 | 0 | if (px->lbprm.tot_weight == 0) |
283 | 0 | return NULL; |
284 | | |
285 | 0 | if ((p = memchr(uri, '?', uri_len)) == NULL) |
286 | 0 | return NULL; |
287 | | |
288 | 0 | p++; |
289 | |
|
290 | 0 | uri_len -= (p - uri); |
291 | 0 | plen = px->lbprm.arg_len; |
292 | 0 | params = p; |
293 | |
|
294 | 0 | while (uri_len > plen) { |
295 | | /* Look for the parameter name followed by an equal symbol */ |
296 | 0 | if (params[plen] == '=') { |
297 | 0 | if (memcmp(params, px->lbprm.arg_str, plen) == 0) { |
298 | | /* OK, we have the parameter here at <params>, and |
299 | | * the value after the equal sign, at <p> |
300 | | * skip the equal symbol |
301 | | */ |
302 | 0 | p += plen + 1; |
303 | 0 | start = end = p; |
304 | 0 | uri_len -= plen + 1; |
305 | |
|
306 | 0 | while (uri_len && *end != '&') { |
307 | 0 | uri_len--; |
308 | 0 | end++; |
309 | 0 | } |
310 | 0 | hash = gen_hash(px, start, (end - start)); |
311 | |
|
312 | 0 | if ((px->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_CHTREE) |
313 | 0 | return chash_get_server_hash(px, hash, avoid); |
314 | 0 | else |
315 | 0 | return map_get_server_hash(px, hash); |
316 | 0 | } |
317 | 0 | } |
318 | | /* skip to next parameter */ |
319 | 0 | p = memchr(params, '&', uri_len); |
320 | 0 | if (!p) |
321 | 0 | return NULL; |
322 | 0 | p++; |
323 | 0 | uri_len -= (p - params); |
324 | 0 | params = p; |
325 | 0 | } |
326 | 0 | return NULL; |
327 | 0 | } |
328 | | |
329 | | /* |
330 | | * this does the same as the previous server_ph, but check the body contents |
331 | | */ |
332 | | struct server *get_server_ph_post(struct stream *s, const struct server *avoid) |
333 | 0 | { |
334 | 0 | unsigned int hash = 0; |
335 | 0 | struct channel *req = &s->req; |
336 | 0 | struct proxy *px = s->be; |
337 | 0 | struct htx *htx = htxbuf(&req->buf); |
338 | 0 | struct htx_blk *blk; |
339 | 0 | unsigned int plen = px->lbprm.arg_len; |
340 | 0 | unsigned long len; |
341 | 0 | const char *params, *p, *start, *end; |
342 | |
|
343 | 0 | if (px->lbprm.tot_weight == 0) |
344 | 0 | return NULL; |
345 | | |
346 | 0 | p = params = NULL; |
347 | 0 | len = 0; |
348 | 0 | for (blk = htx_get_first_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) { |
349 | 0 | enum htx_blk_type type = htx_get_blk_type(blk); |
350 | 0 | struct ist v; |
351 | |
|
352 | 0 | if (type != HTX_BLK_DATA) |
353 | 0 | continue; |
354 | 0 | v = htx_get_blk_value(htx, blk); |
355 | 0 | p = params = v.ptr; |
356 | 0 | len = v.len; |
357 | 0 | break; |
358 | 0 | } |
359 | |
|
360 | 0 | while (len > plen) { |
361 | | /* Look for the parameter name followed by an equal symbol */ |
362 | 0 | if (params[plen] == '=') { |
363 | 0 | if (memcmp(params, px->lbprm.arg_str, plen) == 0) { |
364 | | /* OK, we have the parameter here at <params>, and |
365 | | * the value after the equal sign, at <p> |
366 | | * skip the equal symbol |
367 | | */ |
368 | 0 | p += plen + 1; |
369 | 0 | start = end = p; |
370 | 0 | len -= plen + 1; |
371 | |
|
372 | 0 | while (len && *end != '&') { |
373 | 0 | if (unlikely(!HTTP_IS_TOKEN(*end))) { |
374 | | /* if in a POST, body must be URI encoded or it's not a URI. |
375 | | * Do not interpret any possible binary data as a parameter. |
376 | | */ |
377 | 0 | if (likely(HTTP_IS_LWS(*end))) /* eol, uncertain uri len */ |
378 | 0 | break; |
379 | 0 | return NULL; /* oh, no; this is not uri-encoded. |
380 | | * This body does not contain parameters. |
381 | | */ |
382 | 0 | } |
383 | 0 | len--; |
384 | 0 | end++; |
385 | | /* should we break if vlen exceeds limit? */ |
386 | 0 | } |
387 | 0 | hash = gen_hash(px, start, (end - start)); |
388 | |
|
389 | 0 | if ((px->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_CHTREE) |
390 | 0 | return chash_get_server_hash(px, hash, avoid); |
391 | 0 | else |
392 | 0 | return map_get_server_hash(px, hash); |
393 | 0 | } |
394 | 0 | } |
395 | | /* skip to next parameter */ |
396 | 0 | p = memchr(params, '&', len); |
397 | 0 | if (!p) |
398 | 0 | return NULL; |
399 | 0 | p++; |
400 | 0 | len -= (p - params); |
401 | 0 | params = p; |
402 | 0 | } |
403 | 0 | return NULL; |
404 | 0 | } |
405 | | |
406 | | |
407 | | /* |
408 | | * This function tries to find a running server for the proxy <px> following |
409 | | * the Header parameter hash method. It looks for a specific parameter in the |
410 | | * URL and hashes it to compute the server ID. This is useful to optimize |
411 | | * performance by avoiding bounces between servers in contexts where sessions |
412 | | * are shared but cookies are not usable. If the parameter is not found, NULL |
413 | | * is returned. If any server is found, it will be returned. If no valid server |
414 | | * is found, NULL is returned. When lbprm.arg_opt1 is set, the hash will only |
415 | | * apply to the middle part of a domain name ("use_domain_only" option). |
416 | | */ |
417 | | struct server *get_server_hh(struct stream *s, const struct server *avoid) |
418 | 0 | { |
419 | 0 | unsigned int hash = 0; |
420 | 0 | struct proxy *px = s->be; |
421 | 0 | unsigned int plen = px->lbprm.arg_len; |
422 | 0 | unsigned long len; |
423 | 0 | const char *p; |
424 | 0 | const char *start, *end; |
425 | 0 | struct htx *htx = htxbuf(&s->req.buf); |
426 | 0 | struct http_hdr_ctx ctx = { .blk = NULL }; |
427 | | |
428 | | /* tot_weight appears to mean srv_count */ |
429 | 0 | if (px->lbprm.tot_weight == 0) |
430 | 0 | return NULL; |
431 | | |
432 | | /* note: we won't hash if there's only one server left */ |
433 | 0 | if (px->lbprm.tot_used == 1) |
434 | 0 | goto hash_done; |
435 | | |
436 | 0 | http_find_header(htx, ist2(px->lbprm.arg_str, plen), &ctx, 0); |
437 | | |
438 | | /* if the header is not found or empty, let's fallback to round robin */ |
439 | 0 | if (!ctx.blk || !ctx.value.len) |
440 | 0 | return NULL; |
441 | | |
442 | | /* Found a the param_name in the headers. |
443 | | * we will compute the hash based on this value ctx.val. |
444 | | */ |
445 | 0 | len = ctx.value.len; |
446 | 0 | p = ctx.value.ptr; |
447 | |
|
448 | 0 | if (!px->lbprm.arg_opt1) { |
449 | 0 | hash = gen_hash(px, p, len); |
450 | 0 | } else { |
451 | 0 | int dohash = 0; |
452 | 0 | p += len; |
453 | | /* special computation, use only main domain name, not tld/host |
454 | | * going back from the end of string, start hashing at first |
455 | | * dot stop at next. |
456 | | * This is designed to work with the 'Host' header, and requires |
457 | | * a special option to activate this. |
458 | | */ |
459 | 0 | end = p; |
460 | 0 | while (len) { |
461 | 0 | if (dohash) { |
462 | | /* Rewind the pointer until the previous char |
463 | | * is a dot, this will allow to set the start |
464 | | * position of the domain. */ |
465 | 0 | if (*(p - 1) == '.') |
466 | 0 | break; |
467 | 0 | } |
468 | 0 | else if (*p == '.') { |
469 | | /* The pointer is rewound to the dot before the |
470 | | * tld, we memorize the end of the domain and |
471 | | * can enter the domain processing. */ |
472 | 0 | end = p; |
473 | 0 | dohash = 1; |
474 | 0 | } |
475 | 0 | p--; |
476 | 0 | len--; |
477 | 0 | } |
478 | 0 | start = p; |
479 | 0 | hash = gen_hash(px, start, (end - start)); |
480 | 0 | } |
481 | |
|
482 | 0 | hash_done: |
483 | 0 | if ((px->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_CHTREE) |
484 | 0 | return chash_get_server_hash(px, hash, avoid); |
485 | 0 | else |
486 | 0 | return map_get_server_hash(px, hash); |
487 | 0 | } |
488 | | |
489 | | /* RDP Cookie HASH. */ |
490 | | struct server *get_server_rch(struct stream *s, const struct server *avoid) |
491 | 0 | { |
492 | 0 | unsigned int hash = 0; |
493 | 0 | struct proxy *px = s->be; |
494 | 0 | unsigned long len; |
495 | 0 | int ret; |
496 | 0 | struct sample smp; |
497 | 0 | int rewind; |
498 | | |
499 | | /* tot_weight appears to mean srv_count */ |
500 | 0 | if (px->lbprm.tot_weight == 0) |
501 | 0 | return NULL; |
502 | | |
503 | 0 | memset(&smp, 0, sizeof(smp)); |
504 | |
|
505 | 0 | rewind = co_data(&s->req); |
506 | 0 | c_rew(&s->req, rewind); |
507 | |
|
508 | 0 | ret = fetch_rdp_cookie_name(s, &smp, px->lbprm.arg_str, px->lbprm.arg_len); |
509 | 0 | len = smp.data.u.str.data; |
510 | |
|
511 | 0 | c_adv(&s->req, rewind); |
512 | |
|
513 | 0 | if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || len == 0) |
514 | 0 | return NULL; |
515 | | |
516 | | /* note: we won't hash if there's only one server left */ |
517 | 0 | if (px->lbprm.tot_used == 1) |
518 | 0 | goto hash_done; |
519 | | |
520 | | /* Found the param_name in the headers. |
521 | | * we will compute the hash based on this value ctx.val. |
522 | | */ |
523 | 0 | hash = gen_hash(px, smp.data.u.str.area, len); |
524 | |
|
525 | 0 | hash_done: |
526 | 0 | if ((px->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_CHTREE) |
527 | 0 | return chash_get_server_hash(px, hash, avoid); |
528 | 0 | else |
529 | 0 | return map_get_server_hash(px, hash); |
530 | 0 | } |
531 | | |
532 | | /* sample expression HASH. Returns NULL if the sample is not found or if there |
533 | | * are no server, relying on the caller to fall back to round robin instead. |
534 | | */ |
535 | | struct server *get_server_expr(struct stream *s, const struct server *avoid) |
536 | 0 | { |
537 | 0 | struct proxy *px = s->be; |
538 | 0 | struct sample *smp; |
539 | 0 | unsigned int hash = 0; |
540 | |
|
541 | 0 | if (px->lbprm.tot_weight == 0) |
542 | 0 | return NULL; |
543 | | |
544 | | /* note: no need to hash if there's only one server left */ |
545 | 0 | if (px->lbprm.tot_used == 1) |
546 | 0 | goto hash_done; |
547 | | |
548 | | /* Note that if the hash-type doesn't hash the key, we must provide it |
549 | | * as a string representing a number as it will be parsed by read_int64(). |
550 | | * Otherwise it's binary. The difference happens on samples returing |
551 | | * ints (e.g. rand()) as well as IP addresses, which, when turned to |
552 | | * binary, are just binary-encoded and cannot be parsed. |
553 | | */ |
554 | 0 | smp = sample_fetch_as_type(px, s->sess, s, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, px->lbprm.expr, |
555 | 0 | ((px->lbprm.algo & BE_LB_HASH_FUNC) == BE_LB_HFCN_NONE) ? SMP_T_STR : SMP_T_BIN); |
556 | 0 | if (!smp) |
557 | 0 | return NULL; |
558 | | |
559 | | /* We have the desired data. Let's hash it according to the configured |
560 | | * options and algorithm. |
561 | | */ |
562 | 0 | hash = gen_hash(px, smp->data.u.str.area, smp->data.u.str.data); |
563 | |
|
564 | 0 | hash_done: |
565 | 0 | if ((px->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_CHTREE) |
566 | 0 | return chash_get_server_hash(px, hash, avoid); |
567 | 0 | else |
568 | 0 | return map_get_server_hash(px, hash); |
569 | 0 | } |
570 | | |
571 | | /* random value */ |
572 | | struct server *get_server_rnd(struct stream *s, const struct server *avoid) |
573 | 0 | { |
574 | 0 | unsigned int hash = 0; |
575 | 0 | struct proxy *px = s->be; |
576 | 0 | struct server *prev, *curr; |
577 | 0 | int draws = px->lbprm.arg_opt1; // number of draws |
578 | | |
579 | | /* tot_weight appears to mean srv_count */ |
580 | 0 | if (px->lbprm.tot_weight == 0) |
581 | 0 | return NULL; |
582 | | |
583 | 0 | curr = NULL; |
584 | 0 | do { |
585 | 0 | prev = curr; |
586 | 0 | hash = statistical_prng(); |
587 | 0 | curr = chash_get_server_hash(px, hash, avoid); |
588 | 0 | if (!curr) |
589 | 0 | break; |
590 | | |
591 | | /* compare the new server to the previous best choice and pick |
592 | | * the one with the least currently served requests. |
593 | | */ |
594 | 0 | if (prev && prev != curr) { |
595 | 0 | uint64_t wcurr = (uint64_t)curr->served * prev->cur_eweight; |
596 | 0 | uint64_t wprev = (uint64_t)prev->served * curr->cur_eweight; |
597 | |
|
598 | 0 | if (wcurr > wprev) |
599 | 0 | curr = prev; |
600 | 0 | else if (wcurr == wprev && curr->counters.shared.tg && prev->counters.shared.tg) { |
601 | | /* same load: pick the lowest weighted request rate */ |
602 | 0 | wcurr = read_freq_ctr_period_estimate(&curr->counters.shared.tg[tgid - 1]->sess_per_sec, MS_TO_TICKS(1000)); |
603 | 0 | wprev = read_freq_ctr_period_estimate(&prev->counters.shared.tg[tgid - 1]->sess_per_sec, MS_TO_TICKS(1000)); |
604 | 0 | if (wprev * curr->cur_eweight < wcurr * prev->cur_eweight) |
605 | 0 | curr = prev; |
606 | 0 | } |
607 | 0 | } |
608 | 0 | } while (--draws > 0); |
609 | | |
610 | | /* if the selected server is full, pretend we have none so that we reach |
611 | | * the backend's queue instead. |
612 | | */ |
613 | 0 | if (curr && |
614 | 0 | (curr->queueslength || (curr->maxconn && curr->served >= srv_dynamic_maxconn(curr)))) |
615 | 0 | curr = NULL; |
616 | |
|
617 | 0 | return curr; |
618 | 0 | } |
619 | | |
620 | | /* |
621 | | * This function applies the load-balancing algorithm to the stream, as |
622 | | * defined by the backend it is assigned to. The stream is then marked as |
623 | | * 'assigned'. |
624 | | * |
625 | | * This function MAY NOT be called with SF_ASSIGNED already set. If the stream |
626 | | * had a server previously assigned, it is rebalanced, trying to avoid the same |
627 | | * server, which should still be present in target_srv(&s->target) before the call. |
628 | | * The function tries to keep the original connection slot if it reconnects to |
629 | | * the same server, otherwise it releases it and tries to offer it. |
630 | | * |
631 | | * It is illegal to call this function with a stream in a queue. |
632 | | * |
633 | | * It may return : |
634 | | * SRV_STATUS_OK if everything is OK. ->srv and ->target are assigned. |
635 | | * SRV_STATUS_NOSRV if no server is available. Stream is not ASSIGNED |
636 | | * SRV_STATUS_FULL if all servers are saturated. Stream is not ASSIGNED |
637 | | * SRV_STATUS_INTERNAL for other unrecoverable errors. |
638 | | * |
639 | | * Upon successful return, the stream flag SF_ASSIGNED is set to indicate that |
640 | | * it does not need to be called anymore. This means that target_srv(&s->target) |
641 | | * can be trusted in balance and direct modes. |
642 | | * |
643 | | */ |
644 | | |
645 | | int assign_server(struct stream *s) |
646 | 0 | { |
647 | 0 | struct connection *conn = NULL; |
648 | 0 | struct server *conn_slot; |
649 | 0 | struct server *srv = NULL, *prev_srv; |
650 | 0 | int err; |
651 | |
|
652 | 0 | err = SRV_STATUS_INTERNAL; |
653 | 0 | if (unlikely(s->pend_pos || s->flags & SF_ASSIGNED)) |
654 | 0 | goto out_err; |
655 | | |
656 | 0 | prev_srv = objt_server(s->target); |
657 | 0 | conn_slot = s->srv_conn; |
658 | | |
659 | | /* We have to release any connection slot before applying any LB algo, |
660 | | * otherwise we may erroneously end up with no available slot. |
661 | | */ |
662 | 0 | if (conn_slot) |
663 | 0 | sess_change_server(s, NULL); |
664 | | |
665 | | /* We will now try to find the good server and store it into <objt_server(s->target)>. |
666 | | * Note that <objt_server(s->target)> may be NULL in case of dispatch or proxy mode, |
667 | | * as well as if no server is available (check error code). |
668 | | */ |
669 | |
|
670 | 0 | srv = NULL; |
671 | 0 | s->target = NULL; |
672 | |
|
673 | 0 | if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI && |
674 | 0 | ((s->sess->flags & SESS_FL_PREFER_LAST) || |
675 | 0 | (s->be->options & PR_O_PREF_LAST))) { |
676 | 0 | struct sess_priv_conns *pconns; |
677 | 0 | list_for_each_entry(pconns, &s->sess->priv_conns, sess_el) { |
678 | 0 | struct server *tmpsrv = objt_server(pconns->target); |
679 | |
|
680 | 0 | if (tmpsrv && tmpsrv->proxy == s->be && |
681 | 0 | ((s->sess->flags & SESS_FL_PREFER_LAST) || |
682 | 0 | (!s->be->max_ka_queue || |
683 | 0 | server_has_room(tmpsrv) || ( |
684 | 0 | tmpsrv->queueslength + 1 < s->be->max_ka_queue))) && |
685 | 0 | srv_currently_usable(tmpsrv)) { |
686 | 0 | list_for_each_entry(conn, &pconns->conn_list, sess_el) { |
687 | 0 | if (!(conn->flags & CO_FL_WAIT_XPRT)) { |
688 | 0 | srv = tmpsrv; |
689 | 0 | stream_set_srv_target(s, srv); |
690 | 0 | goto out_ok; |
691 | 0 | } |
692 | 0 | } |
693 | 0 | } |
694 | 0 | } |
695 | 0 | } |
696 | | |
697 | 0 | if (s->be->lbprm.algo & BE_LB_KIND) { |
698 | | /* we must check if we have at least one server available */ |
699 | 0 | if (!s->be->lbprm.tot_weight) { |
700 | 0 | err = SRV_STATUS_NOSRV; |
701 | 0 | goto out; |
702 | 0 | } |
703 | | |
704 | | /* if there's some queue on the backend, with certain algos we |
705 | | * know it's because all servers are full. |
706 | | */ |
707 | 0 | if (s->be->queueslength && s->be->served && s->be->queueslength != s->be->beconn && |
708 | 0 | (((s->be->lbprm.algo & (BE_LB_KIND|BE_LB_NEED|BE_LB_PARM)) == BE_LB_ALGO_FAS)|| // first |
709 | 0 | ((s->be->lbprm.algo & (BE_LB_KIND|BE_LB_NEED|BE_LB_PARM)) == BE_LB_ALGO_RR) || // roundrobin |
710 | 0 | ((s->be->lbprm.algo & (BE_LB_KIND|BE_LB_NEED|BE_LB_PARM)) == BE_LB_ALGO_SRR))) { // static-rr |
711 | 0 | err = SRV_STATUS_FULL; |
712 | 0 | goto out; |
713 | 0 | } |
714 | | |
715 | | /* First check whether we need to fetch some data or simply call |
716 | | * the LB lookup function. Only the hashing functions will need |
717 | | * some input data in fact, and will support multiple algorithms. |
718 | | */ |
719 | 0 | switch (s->be->lbprm.algo & BE_LB_LKUP) { |
720 | 0 | case BE_LB_LKUP_RRTREE: |
721 | 0 | srv = fwrr_get_next_server(s->be, prev_srv); |
722 | 0 | break; |
723 | | |
724 | 0 | case BE_LB_LKUP_FSTREE: |
725 | 0 | srv = fas_get_next_server(s->be, prev_srv); |
726 | 0 | break; |
727 | | |
728 | 0 | case BE_LB_LKUP_LCTREE: |
729 | 0 | srv = fwlc_get_next_server(s->be, prev_srv); |
730 | 0 | break; |
731 | | |
732 | 0 | case BE_LB_LKUP_CHTREE: |
733 | 0 | case BE_LB_LKUP_MAP: |
734 | 0 | if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) { |
735 | | /* static-rr (map) or random (chash) */ |
736 | 0 | if ((s->be->lbprm.algo & BE_LB_PARM) == BE_LB_RR_RANDOM) |
737 | 0 | srv = get_server_rnd(s, prev_srv); |
738 | 0 | else |
739 | 0 | srv = map_get_server_rr(s->be, prev_srv); |
740 | 0 | break; |
741 | 0 | } |
742 | 0 | else if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI) { |
743 | | /* unknown balancing algorithm */ |
744 | 0 | err = SRV_STATUS_INTERNAL; |
745 | 0 | goto out; |
746 | 0 | } |
747 | | |
748 | 0 | switch (s->be->lbprm.algo & BE_LB_PARM) { |
749 | 0 | const struct sockaddr_storage *src; |
750 | | |
751 | 0 | case BE_LB_HASH_SRC: |
752 | 0 | src = sc_src(s->scf); |
753 | 0 | if (src && src->ss_family == AF_INET) { |
754 | 0 | srv = get_server_sh(s->be, |
755 | 0 | (void *)&((struct sockaddr_in *)src)->sin_addr, |
756 | 0 | 4, prev_srv); |
757 | 0 | } |
758 | 0 | else if (src && src->ss_family == AF_INET6) { |
759 | 0 | srv = get_server_sh(s->be, |
760 | 0 | (void *)&((struct sockaddr_in6 *)src)->sin6_addr, |
761 | 0 | 16, prev_srv); |
762 | 0 | } |
763 | 0 | break; |
764 | | |
765 | 0 | case BE_LB_HASH_URI: |
766 | | /* URI hashing */ |
767 | 0 | if (IS_HTX_STRM(s) && s->txn.http->req.msg_state >= HTTP_MSG_BODY) { |
768 | 0 | struct ist uri; |
769 | |
|
770 | 0 | uri = htx_sl_req_uri(http_get_stline(htxbuf(&s->req.buf))); |
771 | 0 | if (s->be->lbprm.arg_opt1 & 2) { |
772 | 0 | struct http_uri_parser parser = |
773 | 0 | http_uri_parser_init(uri); |
774 | |
|
775 | 0 | uri = http_parse_path(&parser); |
776 | 0 | if (!isttest(uri)) |
777 | 0 | uri = ist(""); |
778 | 0 | } |
779 | 0 | srv = get_server_uh(s->be, uri.ptr, uri.len, prev_srv); |
780 | 0 | } |
781 | 0 | break; |
782 | | |
783 | 0 | case BE_LB_HASH_PRM: |
784 | | /* URL Parameter hashing */ |
785 | 0 | if (IS_HTX_STRM(s) && s->txn.http->req.msg_state >= HTTP_MSG_BODY) { |
786 | 0 | struct ist uri; |
787 | |
|
788 | 0 | uri = htx_sl_req_uri(http_get_stline(htxbuf(&s->req.buf))); |
789 | 0 | srv = get_server_ph(s->be, uri.ptr, uri.len, prev_srv); |
790 | |
|
791 | 0 | if (!srv && s->txn.http->meth == HTTP_METH_POST) |
792 | 0 | srv = get_server_ph_post(s, prev_srv); |
793 | 0 | } |
794 | 0 | break; |
795 | | |
796 | 0 | case BE_LB_HASH_HDR: |
797 | | /* Header Parameter hashing */ |
798 | 0 | if (IS_HTX_STRM(s) && s->txn.http->req.msg_state >= HTTP_MSG_BODY) |
799 | 0 | srv = get_server_hh(s, prev_srv); |
800 | 0 | break; |
801 | | |
802 | 0 | case BE_LB_HASH_RDP: |
803 | | /* RDP Cookie hashing */ |
804 | 0 | srv = get_server_rch(s, prev_srv); |
805 | 0 | break; |
806 | | |
807 | 0 | case BE_LB_HASH_SMP: |
808 | | /* sample expression hashing */ |
809 | 0 | srv = get_server_expr(s, prev_srv); |
810 | 0 | break; |
811 | | |
812 | 0 | default: |
813 | | /* unknown balancing algorithm */ |
814 | 0 | err = SRV_STATUS_INTERNAL; |
815 | 0 | goto out; |
816 | 0 | } |
817 | | |
818 | | /* If the hashing parameter was not found, let's fall |
819 | | * back to round robin on the map. |
820 | | */ |
821 | 0 | if (!srv) { |
822 | 0 | if ((s->be->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_CHTREE) |
823 | 0 | srv = chash_get_next_server(s->be, prev_srv); |
824 | 0 | else |
825 | 0 | srv = map_get_server_rr(s->be, prev_srv); |
826 | 0 | } |
827 | | |
828 | | /* end of map-based LB */ |
829 | 0 | break; |
830 | | |
831 | 0 | default: |
832 | 0 | if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_SA) { |
833 | | /* some special algos that cannot be grouped together */ |
834 | |
|
835 | 0 | if ((s->be->lbprm.algo & BE_LB_PARM) == BE_LB_SA_SS) |
836 | 0 | srv = ss_get_server(s->be); |
837 | |
|
838 | 0 | break; |
839 | 0 | } |
840 | | /* unknown balancing algorithm */ |
841 | 0 | err = SRV_STATUS_INTERNAL; |
842 | 0 | goto out; |
843 | 0 | } |
844 | | |
845 | 0 | if (!srv) { |
846 | 0 | err = SRV_STATUS_FULL; |
847 | 0 | goto out; |
848 | 0 | } |
849 | 0 | else if (srv != prev_srv) { |
850 | 0 | if (s->be_tgcounters) |
851 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->cum_lbconn); |
852 | 0 | if (srv->counters.shared.tg) |
853 | 0 | _HA_ATOMIC_INC(&srv->counters.shared.tg[tgid - 1]->cum_lbconn); |
854 | 0 | } |
855 | 0 | stream_set_srv_target(s, srv); |
856 | 0 | } |
857 | 0 | else { |
858 | 0 | err = SRV_STATUS_NOSRV; |
859 | 0 | goto out; |
860 | 0 | } |
861 | | |
862 | 0 | out_ok: |
863 | 0 | s->flags |= SF_ASSIGNED; |
864 | 0 | err = SRV_STATUS_OK; |
865 | 0 | out: |
866 | | |
867 | | /* Either we take back our connection slot, or we offer it to someone |
868 | | * else if we don't need it anymore. |
869 | | */ |
870 | 0 | if (conn_slot) { |
871 | 0 | if (conn_slot == srv) { |
872 | 0 | sess_change_server(s, srv); |
873 | 0 | } else { |
874 | 0 | if (may_dequeue_tasks(conn_slot, s->be)) |
875 | 0 | process_srv_queue(conn_slot); |
876 | 0 | } |
877 | 0 | } |
878 | |
|
879 | 0 | out_err: |
880 | 0 | return err; |
881 | 0 | } |
882 | | |
883 | | /* Allocate <*ss> address unless already set. Address is then set to the |
884 | | * destination endpoint of <srv> server, or via <s> from a dispatch or |
885 | | * transparent address. |
886 | | * |
887 | | * Note that no address is allocated if server relies on reverse HTTP. |
888 | | * |
889 | | * Returns SRV_STATUS_OK on success, or if already already set. Else an error |
890 | | * code is returned and <*ss> is not allocated. |
891 | | */ |
892 | | static int alloc_dst_address(struct sockaddr_storage **ss, |
893 | | struct server *srv, struct stream *s) |
894 | 0 | { |
895 | 0 | const struct sockaddr_storage *dst; |
896 | |
|
897 | 0 | if (*ss) |
898 | 0 | return SRV_STATUS_OK; |
899 | | |
900 | 0 | if (srv && (srv->flags & SRV_F_RHTTP)) { |
901 | | /* For reverse HTTP, destination address is unknown. */ |
902 | 0 | return SRV_STATUS_OK; |
903 | 0 | } |
904 | | |
905 | 0 | if ((s->flags & SF_DIRECT) || (s->be->lbprm.algo & BE_LB_KIND)) { |
906 | | /* A server is necessarily known for this stream */ |
907 | 0 | if (!(s->flags & SF_ASSIGNED)) |
908 | 0 | return SRV_STATUS_INTERNAL; |
909 | | |
910 | 0 | if (!sockaddr_alloc(ss, NULL, 0)) |
911 | 0 | return SRV_STATUS_INTERNAL; |
912 | | |
913 | 0 | ASSUME_NONNULL(srv); /* srv is guaranteed by SF_ASSIGNED */ |
914 | |
|
915 | 0 | **ss = srv->addr; |
916 | 0 | set_host_port(*ss, srv->svc_port); |
917 | 0 | if (!is_addr(*ss)) { |
918 | | /* if the server has no address, we use the same address |
919 | | * the client asked, which is handy for remapping ports |
920 | | * locally on multiple addresses at once. Nothing is done |
921 | | * for AF_UNIX addresses. |
922 | | */ |
923 | 0 | dst = sc_dst(s->scf); |
924 | 0 | if (dst && dst->ss_family == AF_INET) { |
925 | 0 | ((struct sockaddr_in *)*ss)->sin_family = AF_INET; |
926 | 0 | ((struct sockaddr_in *)*ss)->sin_addr = |
927 | 0 | ((struct sockaddr_in *)dst)->sin_addr; |
928 | 0 | } else if (dst && dst->ss_family == AF_INET6) { |
929 | 0 | ((struct sockaddr_in6 *)*ss)->sin6_family = AF_INET6; |
930 | 0 | ((struct sockaddr_in6 *)*ss)->sin6_addr = |
931 | 0 | ((struct sockaddr_in6 *)dst)->sin6_addr; |
932 | 0 | } |
933 | 0 | } |
934 | | |
935 | | /* if this server remaps proxied ports, we'll use |
936 | | * the port the client connected to with an offset. */ |
937 | 0 | if ((srv->flags & SRV_F_MAPPORTS)) { |
938 | 0 | int base_port; |
939 | |
|
940 | 0 | dst = sc_dst(s->scf); |
941 | 0 | if (dst) { |
942 | | /* First, retrieve the port from the incoming connection */ |
943 | 0 | base_port = get_host_port(dst); |
944 | | |
945 | | /* Second, assign the outgoing connection's port */ |
946 | 0 | base_port += get_host_port(*ss); |
947 | 0 | set_host_port(*ss, base_port); |
948 | 0 | } |
949 | 0 | } |
950 | 0 | } |
951 | 0 | else { |
952 | | /* no server and no LB algorithm ! */ |
953 | 0 | return SRV_STATUS_INTERNAL; |
954 | 0 | } |
955 | | |
956 | 0 | return SRV_STATUS_OK; |
957 | 0 | } |
958 | | |
959 | | /* This function assigns a server to stream <s> if required, and can add the |
960 | | * connection to either the assigned server's queue or to the proxy's queue. |
961 | | * If ->srv_conn is set, the stream is first released from the server. |
962 | | * It may also be called with SF_DIRECT and/or SF_ASSIGNED though. It will |
963 | | * be called before any connection and after any retry or redispatch occurs. |
964 | | * |
965 | | * It is not allowed to call this function with a stream in a queue. |
966 | | * |
967 | | * Returns : |
968 | | * |
969 | | * SRV_STATUS_OK if everything is OK. |
970 | | * SRV_STATUS_NOSRV if no server is available. objt_server(s->target) = NULL. |
971 | | * SRV_STATUS_QUEUED if the connection has been queued. |
972 | | * SRV_STATUS_FULL if the server(s) is/are saturated and the |
973 | | * connection could not be queued at the server's, |
974 | | * which may be NULL if we queue on the backend. |
975 | | * SRV_STATUS_INTERNAL for other unrecoverable errors. |
976 | | * |
977 | | */ |
978 | | int assign_server_and_queue(struct stream *s) |
979 | 0 | { |
980 | 0 | struct pendconn *p; |
981 | 0 | struct server *srv; |
982 | 0 | int err; |
983 | |
|
984 | 0 | if (s->pend_pos) |
985 | 0 | return SRV_STATUS_INTERNAL; |
986 | | |
987 | 0 | err = SRV_STATUS_OK; |
988 | 0 | if (!(s->flags & SF_ASSIGNED)) { |
989 | 0 | struct server *prev_srv = objt_server(s->target); |
990 | |
|
991 | 0 | err = assign_server(s); |
992 | 0 | if (prev_srv) { |
993 | | /* This stream was previously assigned to a server. We have to |
994 | | * update the stream's and the server's stats : |
995 | | * - if the server changed : |
996 | | * - set TX_CK_DOWN if txn.flags was TX_CK_VALID |
997 | | * - set SF_REDISP if it was successfully redispatched |
998 | | * - increment srv->redispatches and be->redispatches |
999 | | * - if the server remained the same : update retries. |
1000 | | */ |
1001 | |
|
1002 | 0 | if (prev_srv != objt_server(s->target)) { |
1003 | 0 | if (s->txn.http && (s->txn.http->flags & TX_CK_MASK) == TX_CK_VALID) { |
1004 | 0 | s->txn.http->flags &= ~TX_CK_MASK; |
1005 | 0 | s->txn.http->flags |= TX_CK_DOWN; |
1006 | 0 | } |
1007 | 0 | s->flags |= SF_REDISP; |
1008 | 0 | if (prev_srv->counters.shared.tg) |
1009 | 0 | _HA_ATOMIC_INC(&prev_srv->counters.shared.tg[tgid - 1]->redispatches); |
1010 | 0 | if (s->be_tgcounters) |
1011 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->redispatches); |
1012 | 0 | } else { |
1013 | 0 | if (prev_srv->counters.shared.tg) |
1014 | 0 | _HA_ATOMIC_INC(&prev_srv->counters.shared.tg[tgid - 1]->retries); |
1015 | 0 | if (s->be_tgcounters) |
1016 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->retries); |
1017 | 0 | } |
1018 | 0 | } |
1019 | 0 | } |
1020 | |
|
1021 | 0 | switch (err) { |
1022 | 0 | case SRV_STATUS_OK: |
1023 | | /* we have SF_ASSIGNED set */ |
1024 | 0 | srv = objt_server(s->target); |
1025 | 0 | if (!srv) |
1026 | 0 | return SRV_STATUS_OK; /* dispatch or proxy mode */ |
1027 | | |
1028 | | /* If we already have a connection slot, no need to check any queue */ |
1029 | 0 | if (s->srv_conn == srv) |
1030 | 0 | return SRV_STATUS_OK; |
1031 | | |
1032 | | /* OK, this stream already has an assigned server, but no |
1033 | | * connection slot yet. Either it is a redispatch, or it was |
1034 | | * assigned from persistence information (direct mode). |
1035 | | */ |
1036 | 0 | if ((s->flags & SF_REDIRECTABLE) && srv->rdr_len) { |
1037 | | /* server scheduled for redirection, and already assigned. We |
1038 | | * don't want to go further nor check the queue. |
1039 | | */ |
1040 | 0 | sess_change_server(s, srv); /* not really needed in fact */ |
1041 | 0 | return SRV_STATUS_OK; |
1042 | 0 | } |
1043 | | |
1044 | | /* We might have to queue this stream if the assigned server is full. |
1045 | | * We know we have to queue it into the server's queue, so if a maxqueue |
1046 | | * is set on the server, we must also check that the server's queue is |
1047 | | * not full, in which case we have to return FULL. |
1048 | | */ |
1049 | 0 | if (srv->maxconn) { |
1050 | 0 | struct queue *queue = &srv->per_tgrp[tgid - 1].queue; |
1051 | 0 | int served; |
1052 | 0 | int got_it = 0; |
1053 | | |
1054 | | /* |
1055 | | * Make sure that there's still a slot on the server. |
1056 | | * Try to increment its served, while making sure |
1057 | | * it is < maxconn. |
1058 | | */ |
1059 | 0 | if (!queue->length && |
1060 | 0 | (served = srv->served) < srv_dynamic_maxconn(srv)) { |
1061 | | /* |
1062 | | * Attempt to increment served, while |
1063 | | * making sure it is always below maxconn |
1064 | | */ |
1065 | |
|
1066 | 0 | do { |
1067 | 0 | got_it = _HA_ATOMIC_CAS(&srv->served, |
1068 | 0 | &served, served + 1); |
1069 | 0 | } while (!got_it && served < srv_dynamic_maxconn(srv) && |
1070 | 0 | __ha_cpu_relax()); |
1071 | 0 | } |
1072 | 0 | if (!got_it) { |
1073 | 0 | if (srv->maxqueue > 0 && srv->queueslength >= srv->maxqueue) |
1074 | 0 | return SRV_STATUS_FULL; |
1075 | | |
1076 | 0 | p = pendconn_add(s); |
1077 | 0 | if (p) { |
1078 | | /* There's a TOCTOU here: it may happen that between the |
1079 | | * moment we decided to queue the request and the moment |
1080 | | * it was done, the last active request on the server |
1081 | | * ended and no new one will be able to dequeue that one. |
1082 | | * Since we already have our server we don't care, this |
1083 | | * will be handled by the caller which will check for |
1084 | | * this condition and will immediately dequeue it if |
1085 | | * possible. |
1086 | | */ |
1087 | 0 | return SRV_STATUS_QUEUED; |
1088 | 0 | } |
1089 | 0 | else |
1090 | 0 | return SRV_STATUS_INTERNAL; |
1091 | 0 | } |
1092 | 0 | } else |
1093 | 0 | _HA_ATOMIC_INC(&srv->served); |
1094 | | |
1095 | | /* OK, we can use this server. Let's reserve our place */ |
1096 | 0 | sess_change_server(s, srv); |
1097 | 0 | return SRV_STATUS_OK; |
1098 | | |
1099 | 0 | case SRV_STATUS_FULL: |
1100 | | /* queue this stream into the proxy's queue */ |
1101 | 0 | p = pendconn_add(s); |
1102 | 0 | if (p) { |
1103 | | /* There's a TOCTOU here: it may happen that between the |
1104 | | * moment we decided to queue the request and the moment |
1105 | | * it was done, the last active request in the backend |
1106 | | * ended and no new one will be able to dequeue that one. |
1107 | | * This is more visible with maxconn 1 where it can |
1108 | | * happen 1/1000 times, though the vast majority are |
1109 | | * correctly recovered from. |
1110 | | * To work around that, when a server is getting idle, |
1111 | | * it will set the ready_srv field of the proxy. |
1112 | | * Here, if ready_srv is non-NULL, we get that server, |
1113 | | * and we attempt to increment its served counter up to |
1114 | | * maxconn. If it works, then we can just run, otherwise, |
1115 | | * it means another stream will be running, and will |
1116 | | * dequeue us eventually, so we can just do nothing. |
1117 | | */ |
1118 | 0 | if (unlikely(s->be->ready_srv != NULL)) { |
1119 | 0 | struct server *newserv; |
1120 | |
|
1121 | 0 | newserv = HA_ATOMIC_XCHG(&s->be->ready_srv, NULL); |
1122 | 0 | if (newserv != NULL) { |
1123 | 0 | int got_slot = 0; |
1124 | |
|
1125 | 0 | while (_HA_ATOMIC_LOAD(&newserv->served) == 0) { |
1126 | 0 | int served = 0; |
1127 | |
|
1128 | 0 | if (_HA_ATOMIC_CAS(&newserv->served, &served, 1)) { |
1129 | 0 | got_slot = 1; |
1130 | 0 | break; |
1131 | 0 | } |
1132 | 0 | } |
1133 | 0 | if (!got_slot) { |
1134 | | /* |
1135 | | * Somebody else can now |
1136 | | * wake up us, stop now. |
1137 | | */ |
1138 | 0 | return SRV_STATUS_QUEUED; |
1139 | 0 | } |
1140 | | |
1141 | 0 | HA_SPIN_LOCK(QUEUE_LOCK, &p->queue->lock); |
1142 | 0 | if (!p->node.node.leaf_p) { |
1143 | 0 | HA_SPIN_UNLOCK(QUEUE_LOCK, &p->queue->lock); |
1144 | | /* |
1145 | | * Okay we've been queued and |
1146 | | * unqueued already, just leave |
1147 | | */ |
1148 | 0 | _HA_ATOMIC_DEC(&newserv->served); |
1149 | 0 | return SRV_STATUS_QUEUED; |
1150 | 0 | } |
1151 | 0 | eb32_delete(&p->node); |
1152 | 0 | HA_SPIN_UNLOCK(QUEUE_LOCK, &p->queue->lock); |
1153 | |
|
1154 | 0 | _HA_ATOMIC_DEC(&p->queue->length); |
1155 | |
|
1156 | 0 | if (p->queue->sv) |
1157 | 0 | _HA_ATOMIC_DEC(&p->queue->sv->queueslength); |
1158 | 0 | else |
1159 | 0 | _HA_ATOMIC_DEC(&p->queue->px->queueslength); |
1160 | |
|
1161 | 0 | _HA_ATOMIC_INC(&p->queue->idx); |
1162 | 0 | _HA_ATOMIC_DEC(&s->be->totpend); |
1163 | |
|
1164 | 0 | pool_free(pool_head_pendconn, p); |
1165 | |
|
1166 | 0 | s->flags |= SF_ASSIGNED; |
1167 | 0 | stream_set_srv_target(s, newserv); |
1168 | |
|
1169 | 0 | s->pend_pos = NULL; |
1170 | 0 | sess_change_server(s, newserv); |
1171 | 0 | return SRV_STATUS_OK; |
1172 | 0 | } |
1173 | 0 | } |
1174 | | |
1175 | 0 | return SRV_STATUS_QUEUED; |
1176 | 0 | } |
1177 | 0 | else |
1178 | 0 | return SRV_STATUS_INTERNAL; |
1179 | | |
1180 | 0 | case SRV_STATUS_NOSRV: |
1181 | 0 | return err; |
1182 | | |
1183 | 0 | case SRV_STATUS_INTERNAL: |
1184 | 0 | return err; |
1185 | | |
1186 | 0 | default: |
1187 | 0 | return SRV_STATUS_INTERNAL; |
1188 | 0 | } |
1189 | 0 | } |
1190 | | |
1191 | | /* Allocate an address if an explicit source address must be used for a backend |
1192 | | * connection. |
1193 | | * |
1194 | | * Two parameters are taken into account to check if specific source address is |
1195 | | * configured. The first one is <srv> which is the server instance to connect |
1196 | | * to. It may be NULL when dispatching is used. The second one <be> is the |
1197 | | * backend instance which contains the target server or dispatch. |
1198 | | * |
1199 | | * A stream instance <s> can be used to set the stream owner of the backend |
1200 | | * connection. It is a required parameter if the source address is a dynamic |
1201 | | * parameter. |
1202 | | * |
1203 | | * Returns SRV_STATUS_OK if either no specific source address specified or its |
1204 | | * allocation is done correctly. On error returns SRV_STATUS_INTERNAL. |
1205 | | */ |
1206 | | int alloc_bind_address(struct sockaddr_storage **ss, |
1207 | | struct server *srv, struct proxy *be, |
1208 | | struct stream *s) |
1209 | 0 | { |
1210 | 0 | #if defined(CONFIG_HAP_TRANSPARENT) |
1211 | 0 | const struct sockaddr_storage *addr; |
1212 | 0 | struct conn_src *src = NULL; |
1213 | 0 | struct sockaddr_in *sin; |
1214 | 0 | char *vptr; |
1215 | 0 | size_t vlen; |
1216 | 0 | #endif |
1217 | | |
1218 | | /* Ensure the function will not overwrite an allocated address. */ |
1219 | 0 | BUG_ON(*ss); |
1220 | |
|
1221 | 0 | #if defined(CONFIG_HAP_TRANSPARENT) |
1222 | 0 | if (srv && srv->conn_src.opts & CO_SRC_BIND) |
1223 | 0 | src = &srv->conn_src; |
1224 | 0 | else if (be->conn_src.opts & CO_SRC_BIND) |
1225 | 0 | src = &be->conn_src; |
1226 | | |
1227 | | /* no transparent mode, no need to allocate an address, returns OK */ |
1228 | 0 | if (!src) |
1229 | 0 | return SRV_STATUS_OK; |
1230 | | |
1231 | 0 | switch (src->opts & CO_SRC_TPROXY_MASK) { |
1232 | 0 | case CO_SRC_TPROXY_ADDR: |
1233 | 0 | if (!sockaddr_alloc(ss, NULL, 0)) |
1234 | 0 | return SRV_STATUS_INTERNAL; |
1235 | | |
1236 | 0 | **ss = src->tproxy_addr; |
1237 | 0 | break; |
1238 | | |
1239 | 0 | case CO_SRC_TPROXY_CLI: |
1240 | 0 | case CO_SRC_TPROXY_CIP: |
1241 | 0 | BUG_ON(!s); /* Dynamic source setting requires a stream instance. */ |
1242 | | |
1243 | | /* FIXME: what can we do if the client connects in IPv6 or unix socket ? */ |
1244 | 0 | addr = sc_src(s->scf); |
1245 | 0 | if (!addr) |
1246 | 0 | return SRV_STATUS_INTERNAL; |
1247 | | |
1248 | 0 | if (!sockaddr_alloc(ss, NULL, 0)) |
1249 | 0 | return SRV_STATUS_INTERNAL; |
1250 | | |
1251 | 0 | **ss = *addr; |
1252 | 0 | if ((src->opts & CO_SRC_TPROXY_MASK) == CO_SRC_TPROXY_CIP) { |
1253 | | /* always set port to zero when using "clientip", or |
1254 | | * the idle connection hash will include the port part. |
1255 | | */ |
1256 | 0 | if (addr->ss_family == AF_INET) |
1257 | 0 | ((struct sockaddr_in *)*ss)->sin_port = 0; |
1258 | 0 | else if (addr->ss_family == AF_INET6) |
1259 | 0 | ((struct sockaddr_in6 *)*ss)->sin6_port = 0; |
1260 | 0 | } |
1261 | 0 | break; |
1262 | | |
1263 | 0 | case CO_SRC_TPROXY_DYN: |
1264 | 0 | BUG_ON(!s); /* Dynamic source setting requires a stream instance. */ |
1265 | |
|
1266 | 0 | if (!src->bind_hdr_occ || !IS_HTX_STRM(s)) |
1267 | 0 | return SRV_STATUS_INTERNAL; |
1268 | | |
1269 | 0 | if (!sockaddr_alloc(ss, NULL, 0)) |
1270 | 0 | return SRV_STATUS_INTERNAL; |
1271 | | |
1272 | | /* bind to the IP in a header */ |
1273 | 0 | sin = (struct sockaddr_in *)*ss; |
1274 | 0 | sin->sin_family = AF_INET; |
1275 | 0 | sin->sin_port = 0; |
1276 | 0 | sin->sin_addr.s_addr = 0; |
1277 | 0 | if (!http_get_htx_hdr(htxbuf(&s->req.buf), |
1278 | 0 | ist2(src->bind_hdr_name, src->bind_hdr_len), |
1279 | 0 | src->bind_hdr_occ, NULL, &vptr, &vlen)) { |
1280 | 0 | sockaddr_free(ss); |
1281 | 0 | return SRV_STATUS_INTERNAL; |
1282 | 0 | } |
1283 | | |
1284 | 0 | sin->sin_addr.s_addr = htonl(inetaddr_host_lim(vptr, vptr + vlen)); |
1285 | 0 | break; |
1286 | | |
1287 | 0 | default: |
1288 | 0 | ; |
1289 | 0 | } |
1290 | 0 | #endif |
1291 | | |
1292 | 0 | return SRV_STATUS_OK; |
1293 | 0 | } |
1294 | | |
1295 | | /* Attempt to retrieve a connection matching <hash> from <srv> server lists for |
1296 | | * connection reuse. If <is_safe> is true, only connections considered safe for |
1297 | | * reuse are inspected. Thread-local list is inspected first. If no matching |
1298 | | * connection is found, takeover may be performed to steal a connection from a |
1299 | | * foreign thread. |
1300 | | * |
1301 | | * If <reuse_mode> backend policy is safe and connection MUX is subject to |
1302 | | * head-of-line blocking, connection is attached to <sess> session, which |
1303 | | * prevents mixing several frontend client over it. |
1304 | | * |
1305 | | * Returns the connection instance if found. |
1306 | | */ |
1307 | | struct connection *conn_backend_get(int reuse_mode, |
1308 | | struct server *srv, struct session *sess, |
1309 | | int is_safe, int64_t hash) |
1310 | 0 | { |
1311 | 0 | const struct tgroup_info *curtg = tg; |
1312 | 0 | struct connection *conn = NULL; |
1313 | 0 | unsigned int curtgid = tgid; |
1314 | 0 | int i; // thread number |
1315 | 0 | int found = 0; |
1316 | 0 | int stop; |
1317 | | |
1318 | | /* We need to lock even if this is our own list, because another |
1319 | | * thread may be trying to migrate that connection, and we don't want |
1320 | | * to end up with two threads using the same connection. |
1321 | | */ |
1322 | 0 | i = tid; |
1323 | 0 | HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); |
1324 | 0 | conn = srv_lookup_conn(is_safe ? &srv->per_thr[tid].safe_conns : &srv->per_thr[tid].idle_conns, hash); |
1325 | 0 | if (conn) |
1326 | 0 | conn_delete_from_tree(conn, tid); |
1327 | | |
1328 | | /* If we failed to pick a connection from the idle list, let's try again with |
1329 | | * the safe list. |
1330 | | */ |
1331 | 0 | if (!conn && !is_safe && srv->curr_safe_nb > 0) { |
1332 | 0 | conn = srv_lookup_conn(&srv->per_thr[tid].safe_conns, hash); |
1333 | 0 | if (conn) { |
1334 | 0 | conn_delete_from_tree(conn, tid); |
1335 | 0 | is_safe = 1; |
1336 | 0 | } |
1337 | 0 | } |
1338 | 0 | HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); |
1339 | | |
1340 | | /* If we found a connection in our own list, and we don't have to |
1341 | | * steal one from another thread, then we're done. |
1342 | | */ |
1343 | 0 | if (conn) |
1344 | 0 | goto done; |
1345 | | |
1346 | | /* pool sharing globally disabled ? */ |
1347 | 0 | if (!(global.tune.options & GTUNE_IDLE_POOL_SHARED)) |
1348 | 0 | goto done; |
1349 | | |
1350 | | /* Are we allowed to pick from another thread ? We'll still try |
1351 | | * it if we're running low on FDs as we don't want to create |
1352 | | * extra conns in this case, otherwise we can give up if we have |
1353 | | * too few idle conns and the server protocol supports establishing |
1354 | | * connections (i.e. not a reverse-http server for example). |
1355 | | */ |
1356 | 0 | if (srv->curr_idle_conns < srv->low_idle_conns && |
1357 | 0 | ha_used_fds < global.tune.pool_low_count) { |
1358 | 0 | const struct protocol *srv_proto = protocol_lookup(srv->addr.ss_family, PROTO_TYPE_STREAM, 0); |
1359 | |
|
1360 | 0 | if (srv_proto && srv_proto->connect) |
1361 | 0 | goto done; |
1362 | 0 | } |
1363 | | |
1364 | | /* Lookup all other threads for an idle connection, starting from last |
1365 | | * unvisited thread, but always staying in the same group. |
1366 | | */ |
1367 | 0 | stop = srv->per_tgrp[tgid - 1].next_takeover; |
1368 | 0 | if (stop >= curtg->count) |
1369 | 0 | stop %= curtg->count; |
1370 | 0 | stop += curtg->base; |
1371 | 0 | check_tgid: |
1372 | 0 | i = stop; |
1373 | 0 | do { |
1374 | | /* safe requests looked up conns in idle tree first, then safe |
1375 | | * tree; unsafe requests are looked up in the safe conns tree. |
1376 | | */ |
1377 | 0 | int search_tree = is_safe ? 1 : 0; // 0 = idle, 1 = safe |
1378 | 0 | struct ceb_root **tree; |
1379 | |
|
1380 | 0 | if (!srv->curr_idle_thr[i] || i == tid) |
1381 | 0 | continue; |
1382 | | |
1383 | 0 | if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock) != 0) |
1384 | 0 | continue; |
1385 | | |
1386 | 0 | do { |
1387 | 0 | if ((search_tree && !srv->curr_safe_nb) || |
1388 | 0 | (!search_tree && !srv->curr_idle_nb)) |
1389 | 0 | continue; |
1390 | | |
1391 | 0 | tree = search_tree ? &srv->per_thr[i].safe_conns : &srv->per_thr[i].idle_conns; |
1392 | 0 | conn = srv_lookup_conn(tree, hash); |
1393 | 0 | while (conn) { |
1394 | 0 | if (conn->mux->takeover && CALL_MUX_WITH_RET(conn->mux, takeover(conn, i, 0)) == 0) { |
1395 | 0 | conn_delete_from_tree(conn, i); |
1396 | 0 | _HA_ATOMIC_INC(&activity[tid].fd_takeover); |
1397 | 0 | found = 1; |
1398 | 0 | break; |
1399 | 0 | } |
1400 | 0 | conn = srv_lookup_conn_next(tree, conn); |
1401 | 0 | } |
1402 | 0 | } while (!found && ++search_tree <= 1); |
1403 | |
|
1404 | 0 | HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock); |
1405 | 0 | } while (!found && (i = (i + 1 == curtg->base + curtg->count) ? curtg->base : i + 1) != stop); |
1406 | |
|
1407 | 0 | if (!found && (global.tune.tg_takeover == FULL_THREADGROUP_TAKEOVER || |
1408 | 0 | (global.tune.tg_takeover == RESTRICTED_THREADGROUP_TAKEOVER && |
1409 | 0 | srv->flags & (SRV_F_RHTTP | SRV_F_STRICT_MAXCONN)))) { |
1410 | 0 | curtgid = curtgid + 1; |
1411 | 0 | if (curtgid == global.nbtgroups + 1) |
1412 | 0 | curtgid = 1; |
1413 | | /* If we haven't looped yet */ |
1414 | 0 | if (MAX_TGROUPS > 1 && curtgid != tgid) { |
1415 | 0 | curtg = &ha_tgroup_info[curtgid - 1]; |
1416 | 0 | stop = curtg->base; |
1417 | 0 | goto check_tgid; |
1418 | 0 | } |
1419 | 0 | } |
1420 | 0 | if (!found) |
1421 | 0 | conn = NULL; |
1422 | 0 | done: |
1423 | 0 | if (conn) { |
1424 | 0 | _HA_ATOMIC_STORE(&srv->per_tgrp[tgid - 1].next_takeover, (i + 1 == tg->base + tg->count) ? tg->base : i + 1); |
1425 | |
|
1426 | 0 | srv_use_conn(srv, conn); |
1427 | |
|
1428 | 0 | _HA_ATOMIC_DEC(&srv->curr_idle_conns); |
1429 | 0 | _HA_ATOMIC_DEC(conn->flags & CO_FL_SAFE_LIST ? &srv->curr_safe_nb : &srv->curr_idle_nb); |
1430 | 0 | _HA_ATOMIC_DEC(&srv->curr_idle_thr[i]); |
1431 | 0 | conn->flags &= ~CO_FL_LIST_MASK; |
1432 | 0 | __ha_barrier_atomic_store(); |
1433 | |
|
1434 | 0 | if (reuse_mode == PR_O_REUSE_SAFE && conn->mux->flags & MX_FL_HOL_RISK) { |
1435 | | /* attach the connection to the session private list */ |
1436 | 0 | session_add_conn(sess, conn); |
1437 | 0 | } |
1438 | 0 | else { |
1439 | 0 | srv_add_to_avail_list(srv, conn); |
1440 | 0 | } |
1441 | 0 | } |
1442 | |
|
1443 | 0 | return conn; |
1444 | 0 | } |
1445 | | |
1446 | | static int do_connect_server(struct stream *s, struct connection *conn) |
1447 | 0 | { |
1448 | 0 | int ret = SF_ERR_NONE; |
1449 | 0 | int conn_flags = 0; |
1450 | |
|
1451 | 0 | if (unlikely(!conn || !conn->ctrl || !conn->ctrl->connect)) |
1452 | 0 | return SF_ERR_INTERNAL; |
1453 | | |
1454 | 0 | if (co_data(&s->req)) |
1455 | 0 | conn_flags |= CONNECT_HAS_DATA; |
1456 | 0 | if (s->conn_retries == 0) |
1457 | 0 | conn_flags |= CONNECT_CAN_USE_TFO; |
1458 | 0 | if (!conn_ctrl_ready(conn) || !conn_xprt_ready(conn)) { |
1459 | 0 | ret = conn->ctrl->connect(conn, conn_flags); |
1460 | 0 | if (ret != SF_ERR_NONE) |
1461 | 0 | return ret; |
1462 | | |
1463 | | /* we're in the process of establishing a connection */ |
1464 | 0 | s->scb->state = SC_ST_CON; |
1465 | 0 | } |
1466 | 0 | else { |
1467 | | /* try to reuse the existing connection, it will be |
1468 | | * confirmed once we can send on it. |
1469 | | */ |
1470 | | /* Is the connection really ready ? */ |
1471 | 0 | if (conn->mux->ctl(conn, MUX_CTL_STATUS, NULL) & MUX_STATUS_READY) |
1472 | 0 | s->scb->state = SC_ST_RDY; |
1473 | 0 | else |
1474 | 0 | s->scb->state = SC_ST_CON; |
1475 | 0 | } |
1476 | | |
1477 | | /* needs src ip/port for logging */ |
1478 | 0 | if (s->flags & SF_SRC_ADDR) |
1479 | 0 | conn_get_src(conn); |
1480 | |
|
1481 | 0 | return ret; |
1482 | 0 | } |
1483 | | |
1484 | | /* |
1485 | | * Returns the first connection from a tree we managed to take over, |
1486 | | * if any. |
1487 | | */ |
1488 | | static struct connection * |
1489 | | takeover_random_idle_conn(struct ceb_root **root, int curtid) |
1490 | 0 | { |
1491 | 0 | struct connection *conn = NULL; |
1492 | |
|
1493 | 0 | conn = ceb64_item_first(root, hash_node.node, hash_node.key, struct connection); |
1494 | 0 | while (conn) { |
1495 | 0 | if (conn->mux->takeover && CALL_MUX_WITH_RET(conn->mux, takeover(conn, curtid, 1)) == 0) { |
1496 | 0 | conn_delete_from_tree(conn, curtid); |
1497 | 0 | return conn; |
1498 | 0 | } |
1499 | 0 | conn = ceb64_item_next(root, hash_node.node, hash_node.key, conn); |
1500 | 0 | } |
1501 | | |
1502 | 0 | return NULL; |
1503 | 0 | } |
1504 | | |
1505 | | /* |
1506 | | * Kills an idle connection, any idle connection we can get a hold on. |
1507 | | * The goal is just to free a connection in case we reached the max and |
1508 | | * have to establish a new one. |
1509 | | * Returns -1 if there is no idle connection to kill, 0 if there are some |
1510 | | * available but we failed to get one, and 1 if we successfully killed one. |
1511 | | */ |
1512 | | static int |
1513 | | kill_random_idle_conn(struct server *srv) |
1514 | 0 | { |
1515 | 0 | struct connection *conn = NULL; |
1516 | 0 | int i; |
1517 | 0 | int curtid; |
1518 | | /* No idle conn, then there is nothing we can do at this point */ |
1519 | |
|
1520 | 0 | if (srv->curr_idle_conns == 0) |
1521 | 0 | return -1; |
1522 | 0 | for (i = 0; i < global.nbthread; i++) { |
1523 | 0 | curtid = (i + tid) % global.nbthread; |
1524 | |
|
1525 | 0 | if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].idle_conns_lock) != 0) |
1526 | 0 | continue; |
1527 | 0 | conn = takeover_random_idle_conn(&srv->per_thr[curtid].idle_conns, curtid); |
1528 | 0 | if (!conn) |
1529 | 0 | conn = takeover_random_idle_conn(&srv->per_thr[curtid].safe_conns, curtid); |
1530 | 0 | HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].idle_conns_lock); |
1531 | 0 | if (conn) |
1532 | 0 | break; |
1533 | 0 | } |
1534 | 0 | if (conn) { |
1535 | | /* |
1536 | | * We have to manually decrement counters, as srv_release_conn() |
1537 | | * will attempt to access the current tid's counters, while |
1538 | | * we may have taken the connection from a different thread. |
1539 | | */ |
1540 | 0 | if (conn->flags & CO_FL_LIST_MASK) { |
1541 | 0 | _HA_ATOMIC_DEC(&srv->curr_idle_conns); |
1542 | 0 | _HA_ATOMIC_DEC(conn->flags & CO_FL_SAFE_LIST ? &srv->curr_safe_nb : &srv->curr_idle_nb); |
1543 | 0 | _HA_ATOMIC_DEC(&srv->curr_idle_thr[curtid]); |
1544 | 0 | conn->flags &= ~CO_FL_LIST_MASK; |
1545 | | /* |
1546 | | * If we have no list flag then srv_release_conn() |
1547 | | * will consider the connection is used, so let's |
1548 | | * pretend it is. |
1549 | | */ |
1550 | 0 | _HA_ATOMIC_INC(&srv->curr_used_conns); |
1551 | 0 | } |
1552 | 0 | CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx)); |
1553 | 0 | return 1; |
1554 | 0 | } |
1555 | 0 | return 0; |
1556 | 0 | } |
1557 | | |
1558 | | /* Returns backend reuse policy depending on <be>. It can be forced to always |
1559 | | * mode if <srv> is not NULL and uses reverse HTTP. |
1560 | | */ |
1561 | | int be_reuse_mode(const struct proxy *be, const struct server *srv) |
1562 | 0 | { |
1563 | 0 | if (srv && srv->flags & SRV_F_RHTTP) { |
1564 | | /* Override reuse-mode if reverse-connect is used. */ |
1565 | 0 | return PR_O_REUSE_ALWS; |
1566 | 0 | } |
1567 | | |
1568 | 0 | return be->options & PR_O_REUSE_MASK; |
1569 | 0 | } |
1570 | | |
1571 | | /* Calculate hash to select a matching connection for reuse. Here is the list |
1572 | | * of input parameters : |
1573 | | * - <srv> is the server instance. Can be NULL on dispatch/transparent proxy. |
1574 | | * - <strm> is the stream instance. Can be NULL if no stream is used. |
1575 | | * - <src> is the bind address if an explicit source address is used. |
1576 | | * - <dst> is the destination address. Must be set in every cases, except on |
1577 | | * reverse HTTP. |
1578 | | * - <name> is a string identifier associated to the connection. Set by |
1579 | | * pool-conn-name, also used for SSL SNI matching. |
1580 | | * |
1581 | | * Note that all input parameters can be NULL. The only requirement is that |
1582 | | * it's not possible to have both <srv> and <strm> NULL at the same time. |
1583 | | * |
1584 | | * Returns the calculated hash. |
1585 | | */ |
1586 | | int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm, |
1587 | | struct session *sess, |
1588 | | struct sockaddr_storage *src, |
1589 | | struct sockaddr_storage *dst, |
1590 | | struct ist name) |
1591 | 0 | { |
1592 | 0 | struct conn_hash_params hash_params; |
1593 | | |
1594 | | /* Caller cannot set both <srv> and <strm> to NULL. */ |
1595 | 0 | BUG_ON_HOT(!srv && !strm); |
1596 | | |
1597 | | /* first, set unique connection parameters and then calculate hash */ |
1598 | 0 | memset(&hash_params, 0, sizeof(hash_params)); |
1599 | | |
1600 | | /* 1. target */ |
1601 | 0 | hash_params.target = srv ? &srv->obj_type : strm->target; |
1602 | | |
1603 | | /* 2. pool-conn-name */ |
1604 | 0 | if (istlen(name)) { |
1605 | 0 | hash_params.name_prehash = |
1606 | 0 | conn_hash_prehash(istptr(name), istlen(name)); |
1607 | 0 | } |
1608 | | |
1609 | | /* 3. destination address */ |
1610 | 0 | hash_params.dst_addr = dst; |
1611 | | |
1612 | | /* 4. source address */ |
1613 | 0 | hash_params.src_addr = src; |
1614 | | |
1615 | | /* 5. proxy protocol */ |
1616 | 0 | if (strm && srv && srv->pp_opts & SRV_PP_ENABLED) { |
1617 | 0 | struct connection *cli_conn = objt_conn(strm_orig(strm)); |
1618 | 0 | int proxy_line_ret = make_proxy_line(trash.area, trash.size, |
1619 | 0 | srv, cli_conn, strm, sess); |
1620 | 0 | if (proxy_line_ret) { |
1621 | 0 | hash_params.proxy_prehash = |
1622 | 0 | conn_hash_prehash(trash.area, proxy_line_ret); |
1623 | 0 | } |
1624 | 0 | } |
1625 | | |
1626 | | /* 6. Custom mark, tos? */ |
1627 | 0 | if (strm && (strm->flags & (SF_BC_MARK | SF_BC_TOS))) { |
1628 | | /* mark: 32bits, tos: 8bits = 40bits |
1629 | | * last 2 bits are there to indicate if mark and/or tos are set |
1630 | | * total: 42bits: |
1631 | | * |
1632 | | * 63==== (unused) ====42 39----32 31-----------------------------0 |
1633 | | * 0000000000000000000000 11 00000111 00000000000000000000000000000011 |
1634 | | * ^^ ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1635 | | * || | | |
1636 | | * / \ \ \ |
1637 | | * / \ \ \ |
1638 | | * tos? mark? \ mark value (32bits) |
1639 | | * tos value (8bits) |
1640 | | * ie: in the above example: |
1641 | | * - mark is set, mark = 3 |
1642 | | * - tos is set, tos = 7 |
1643 | | */ |
1644 | 0 | if (strm->flags & SF_BC_MARK) { |
1645 | 0 | hash_params.mark_tos_prehash |= strm->bc_mark; |
1646 | | /* 41th bit: mark set */ |
1647 | 0 | hash_params.mark_tos_prehash |= 1ULL << 40; |
1648 | 0 | } |
1649 | 0 | if (strm->flags & SF_BC_TOS) { |
1650 | 0 | hash_params.mark_tos_prehash |= (uint64_t)strm->bc_tos << 32; |
1651 | | /* 42th bit: tos set */ |
1652 | 0 | hash_params.mark_tos_prehash |= 1ULL << 41; |
1653 | 0 | } |
1654 | 0 | } |
1655 | |
|
1656 | 0 | return conn_calculate_hash(&hash_params); |
1657 | 0 | } |
1658 | | |
1659 | | /* Try to reuse a connection, first from <sess> session, then to <srv> server |
1660 | | * lists if not NULL, matching <hash> value and <be> reuse policy. If reuse is |
1661 | | * on <be> proxy successful, connection is attached to <sc> stconn instance. |
1662 | | * |
1663 | | * <target> must point either to the server instance, or a stream target on |
1664 | | * dispatch/transparent proxy. |
1665 | | * |
1666 | | * <not_first_req> must be set if the underlying request is not the first one |
1667 | | * conducted on <sess> session. This allows to use a connection not yet |
1668 | | * labelled as safe under http-reuse safe policy. |
1669 | | * |
1670 | | * This function should only be called for backends which supports connection |
1671 | | * reuse. It may be necessary to extend be_supports_conn_reuse() when |
1672 | | * implementing a new proxy mode. |
1673 | | * |
1674 | | * Returns SF_ERR_NONE if a connection has been reused. The connection instance |
1675 | | * can be retrieve via <sc> stconn. SF_ERR_RESOURCE is returned if no matching |
1676 | | * connection found. SF_ERR_INTERNAL is used on internal error. |
1677 | | */ |
1678 | | int be_reuse_connection(int64_t hash, struct session *sess, |
1679 | | struct proxy *be, struct server *srv, |
1680 | | struct stconn *sc, enum obj_type *target, int not_first_req) |
1681 | 0 | { |
1682 | 0 | struct connection *srv_conn; |
1683 | 0 | const int reuse_mode = be_reuse_mode(be, srv); |
1684 | | |
1685 | | /* first, search for a matching connection in the session's idle conns */ |
1686 | 0 | srv_conn = session_get_conn(sess, target, hash); |
1687 | 0 | if (srv_conn) { |
1688 | | //DBG_TRACE_STATE("reuse connection from session", STRM_EV_STRM_PROC|STRM_EV_CS_ST, strm); |
1689 | 0 | } |
1690 | 0 | else if (srv && reuse_mode != PR_O_REUSE_NEVR) { |
1691 | | /* Below we pick connections from the safe, idle or |
1692 | | * available (which are safe too) lists based |
1693 | | * on the strategy, the fact that this is a first or second |
1694 | | * (retryable) request, with the indicated priority (1 or 2) : |
1695 | | * |
1696 | | * SAFE AGGR ALWS |
1697 | | * |
1698 | | * +-----+-----+ +-----+-----+ +-----+-----+ |
1699 | | * req| 1st | 2nd | req| 1st | 2nd | req| 1st | 2nd | |
1700 | | * ----+-----+-----+ ----+-----+-----+ ----+-----+-----+ |
1701 | | * safe| - | 2 | safe| 1 | 2 | safe| 1 | 2 | |
1702 | | * ----+-----+-----+ ----+-----+-----+ ----+-----+-----+ |
1703 | | * idle| - | 1 | idle| - | 1 | idle| 2 | 1 | |
1704 | | * ----+-----+-----+ ----+-----+-----+ ----+-----+-----+ |
1705 | | * |
1706 | | * Idle conns are necessarily looked up on the same thread so |
1707 | | * that there is no concurrency issues. |
1708 | | */ |
1709 | 0 | if (!ceb_isempty(&srv->per_thr[tid].avail_conns)) { |
1710 | 0 | srv_conn = srv_lookup_conn(&srv->per_thr[tid].avail_conns, hash); |
1711 | 0 | if (srv_conn) { |
1712 | | /* connection cannot be in idle list if used as an avail idle conn. */ |
1713 | 0 | BUG_ON(LIST_INLIST(&srv_conn->idle_list)); |
1714 | | //DBG_TRACE_STATE("reuse connection from avail", STRM_EV_STRM_PROC|STRM_EV_CS_ST, strm); |
1715 | 0 | } |
1716 | 0 | } |
1717 | | |
1718 | | /* if no available connections found, search for an idle/safe */ |
1719 | 0 | if (!srv_conn && srv->max_idle_conns && srv->curr_idle_conns > 0) { |
1720 | 0 | const int idle = srv->curr_idle_nb > 0; |
1721 | 0 | const int safe = srv->curr_safe_nb > 0; |
1722 | 0 | const int retry_safe = (be->retry_type & (PR_RE_CONN_FAILED | PR_RE_DISCONNECTED | PR_RE_TIMEOUT)) == |
1723 | 0 | (PR_RE_CONN_FAILED | PR_RE_DISCONNECTED | PR_RE_TIMEOUT); |
1724 | | |
1725 | | /* second column of the tables above, search for an idle then safe conn */ |
1726 | 0 | if (not_first_req || retry_safe) { |
1727 | 0 | if (idle || safe) |
1728 | 0 | srv_conn = conn_backend_get(reuse_mode, srv, sess, 0, hash); |
1729 | 0 | } |
1730 | | /* first column of the tables above */ |
1731 | 0 | else if (reuse_mode >= PR_O_REUSE_AGGR) { |
1732 | | /* search for a safe conn */ |
1733 | 0 | if (safe) |
1734 | 0 | srv_conn = conn_backend_get(reuse_mode, srv, sess, 1, hash); |
1735 | | |
1736 | | /* search for an idle conn if no safe conn found on always reuse mode */ |
1737 | 0 | if (!srv_conn && |
1738 | 0 | reuse_mode == PR_O_REUSE_ALWS && idle) { |
1739 | | /* TODO conn_backend_get should not check the safe list is this case */ |
1740 | 0 | srv_conn = conn_backend_get(reuse_mode, srv, sess, 0, hash); |
1741 | 0 | } |
1742 | 0 | } |
1743 | |
|
1744 | 0 | if (srv_conn) { |
1745 | | //DBG_TRACE_STATE("reuse connection from idle/safe", STRM_EV_STRM_PROC|STRM_EV_CS_ST, strm); |
1746 | 0 | } |
1747 | 0 | } |
1748 | 0 | } |
1749 | |
|
1750 | 0 | if (srv_conn) { |
1751 | 0 | if (srv_conn->mux) { |
1752 | 0 | int avail = srv_conn->mux->avail_streams(srv_conn); |
1753 | |
|
1754 | 0 | if (avail <= 1) { |
1755 | | /* no more streams available, remove it from the list */ |
1756 | 0 | HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); |
1757 | 0 | conn_delete_from_tree(srv_conn, tid); |
1758 | 0 | HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); |
1759 | 0 | } |
1760 | |
|
1761 | 0 | if (avail >= 1) { |
1762 | 0 | if (CALL_MUX_WITH_RET(srv_conn->mux, attach(srv_conn, sc->sedesc, sess)) == -1) { |
1763 | 0 | if (sc_reset_endp(sc) < 0) |
1764 | 0 | goto err; |
1765 | 0 | sc_ep_clr(sc, ~SE_FL_DETACHED); |
1766 | 0 | } |
1767 | 0 | } |
1768 | 0 | else { |
1769 | | /* TODO cannot reuse conn finally due to no more avail |
1770 | | * streams. May be possible to lookup for a new conn |
1771 | | * to improve reuse rate, with a max retry limit. |
1772 | | */ |
1773 | 0 | srv_conn = NULL; |
1774 | 0 | } |
1775 | 0 | } |
1776 | 0 | } |
1777 | | |
1778 | 0 | return srv_conn ? SF_ERR_NONE : SF_ERR_RESOURCE; |
1779 | | |
1780 | 0 | err: |
1781 | 0 | return SF_ERR_INTERNAL; |
1782 | 0 | } |
1783 | | |
1784 | | /* |
1785 | | * This function initiates a connection to the server assigned to this stream |
1786 | | * (s->target, (s->scb)->addr.to). It will assign a server if none |
1787 | | * is assigned yet. |
1788 | | * It can return one of : |
1789 | | * - SF_ERR_NONE if everything's OK |
1790 | | * - SF_ERR_SRVTO if there are no more servers |
1791 | | * - SF_ERR_SRVCL if the connection was refused by the server |
1792 | | * - SF_ERR_PRXCOND if the connection has been limited by the proxy (maxconn) |
1793 | | * - SF_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...) |
1794 | | * - SF_ERR_INTERNAL for any other purely internal errors |
1795 | | * Additionally, in the case of SF_ERR_RESOURCE, an emergency log will be emitted. |
1796 | | * The server-facing stream connector is expected to hold a pre-allocated connection. |
1797 | | */ |
1798 | | int connect_server(struct stream *s) |
1799 | 0 | { |
1800 | 0 | struct connection *cli_conn = objt_conn(strm_orig(s)); |
1801 | 0 | struct connection *srv_conn = NULL; |
1802 | 0 | const struct mux_proto_list *mux_proto = NULL; |
1803 | 0 | struct server *srv; |
1804 | 0 | struct ist name = IST_NULL; |
1805 | 0 | struct sample *name_smp; |
1806 | 0 | int reuse_mode; |
1807 | 0 | int reuse __maybe_unused = 0; |
1808 | 0 | int may_use_early_data __maybe_unused = 1; // are we allowed to use early data ? |
1809 | 0 | int may_start_mux_now = 1; // are we allowed to start the mux now ? |
1810 | 0 | int err; |
1811 | 0 | struct sockaddr_storage *bind_addr = NULL; |
1812 | 0 | int64_t hash = 0; |
1813 | | |
1814 | | /* in standard configuration, srv will be valid |
1815 | | * it can be NULL for dispatch mode or transparent backend */ |
1816 | 0 | srv = objt_server(s->target); |
1817 | 0 | reuse_mode = be_reuse_mode(s->be, srv); |
1818 | |
|
1819 | 0 | err = alloc_dst_address(&s->scb->dst, srv, s); |
1820 | 0 | if (err != SRV_STATUS_OK) |
1821 | 0 | return SF_ERR_INTERNAL; |
1822 | | |
1823 | 0 | err = alloc_bind_address(&bind_addr, srv, s->be, s); |
1824 | 0 | if (err != SRV_STATUS_OK) |
1825 | 0 | return SF_ERR_INTERNAL; |
1826 | | |
1827 | 0 | if (srv && srv->pool_conn_name_expr) { |
1828 | 0 | name_smp = sample_fetch_as_type(s->be, s->sess, s, |
1829 | 0 | SMP_OPT_DIR_REQ | SMP_OPT_FINAL, |
1830 | 0 | srv->pool_conn_name_expr, SMP_T_STR); |
1831 | 0 | if (name_smp) { |
1832 | 0 | name = ist2(name_smp->data.u.str.area, |
1833 | 0 | name_smp->data.u.str.data); |
1834 | 0 | } |
1835 | 0 | } |
1836 | 0 | hash = be_calculate_conn_hash(srv, s, s->sess, bind_addr, s->scb->dst, name); |
1837 | |
|
1838 | 0 | if (!be_supports_conn_reuse(s->be)) |
1839 | 0 | goto skip_reuse; |
1840 | | |
1841 | | /* disable reuse if websocket stream and the protocol to use is not the |
1842 | | * same as the main protocol of the server. |
1843 | | */ |
1844 | 0 | if (unlikely(s->flags & SF_WEBSOCKET) && srv && !srv_check_reuse_ws(srv)) { |
1845 | 0 | DBG_TRACE_STATE("skip idle connections reuse: websocket stream", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
1846 | 0 | } |
1847 | 0 | else { |
1848 | 0 | const int not_first_req = s->txn.http && s->txn.http->flags & TX_NOT_FIRST; |
1849 | |
|
1850 | 0 | err = be_reuse_connection(hash, s->sess, s->be, srv, s->scb, |
1851 | 0 | s->target, not_first_req); |
1852 | 0 | if (err == SF_ERR_INTERNAL) |
1853 | 0 | return err; |
1854 | | |
1855 | 0 | if (err == SF_ERR_NONE) { |
1856 | 0 | srv_conn = sc_conn(s->scb); |
1857 | 0 | reuse = 1; |
1858 | 0 | if (srv_conn && srv_conn->mux) |
1859 | 0 | may_start_mux_now = 0; |
1860 | 0 | } |
1861 | 0 | } |
1862 | | |
1863 | 0 | if (ha_used_fds > global.tune.pool_high_count && srv) { |
1864 | | /* We have more FDs than deemed acceptable, attempt to kill an idling connection. */ |
1865 | 0 | struct connection *tokill_conn = NULL; |
1866 | | /* First, try from our own idle list */ |
1867 | 0 | HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); |
1868 | 0 | if (!LIST_ISEMPTY(&srv->per_thr[tid].idle_conn_list)) { |
1869 | 0 | tokill_conn = LIST_ELEM(srv->per_thr[tid].idle_conn_list.n, struct connection *, idle_list); |
1870 | 0 | conn_delete_from_tree(tokill_conn, tid); |
1871 | 0 | HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); |
1872 | | |
1873 | | /* Release the idle lock before calling mux->destroy. |
1874 | | * It will in turn call srv_release_conn through |
1875 | | * conn_free which also uses it. |
1876 | | */ |
1877 | 0 | CALL_MUX_NO_RET(tokill_conn->mux, destroy(tokill_conn->ctx)); |
1878 | 0 | } |
1879 | 0 | else { |
1880 | 0 | HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); |
1881 | 0 | } |
1882 | | |
1883 | | /* If not, iterate over other thread's idling pool, and try to grab one */ |
1884 | 0 | if (!tokill_conn) { |
1885 | 0 | int i; |
1886 | |
|
1887 | 0 | for (i = tid; (i = ((i + 1 == global.nbthread) ? 0 : i + 1)) != tid;) { |
1888 | | // just silence stupid gcc which reports an absurd |
1889 | | // out-of-bounds warning for <i> which is always |
1890 | | // exactly zero without threads, but it seems to |
1891 | | // see it possibly larger. |
1892 | 0 | ALREADY_CHECKED(i); |
1893 | |
|
1894 | 0 | if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock) != 0) |
1895 | 0 | continue; |
1896 | | |
1897 | 0 | if (!LIST_ISEMPTY(&srv->per_thr[i].idle_conn_list)) { |
1898 | 0 | tokill_conn = LIST_ELEM(srv->per_thr[i].idle_conn_list.n, struct connection *, idle_list); |
1899 | 0 | conn_delete_from_tree(tokill_conn, i); |
1900 | 0 | } |
1901 | 0 | HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock); |
1902 | |
|
1903 | 0 | if (tokill_conn) { |
1904 | | /* We got one, put it into the concerned thread's to kill list, and wake it's kill task */ |
1905 | |
|
1906 | 0 | MT_LIST_APPEND(&idle_conns[i].toremove_conns, |
1907 | 0 | &tokill_conn->toremove_list); |
1908 | 0 | task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER); |
1909 | 0 | break; |
1910 | 0 | } |
1911 | | |
1912 | 0 | if (!(global.tune.options & GTUNE_IDLE_POOL_SHARED)) |
1913 | 0 | break; |
1914 | 0 | } |
1915 | 0 | } |
1916 | 0 | } |
1917 | |
|
1918 | 0 | skip_reuse: |
1919 | | /* no reuse or failed to reuse the connection above, pick a new one */ |
1920 | 0 | if (!srv_conn) { |
1921 | 0 | unsigned int total_conns; |
1922 | |
|
1923 | 0 | if (srv && (srv->flags & SRV_F_RHTTP)) { |
1924 | 0 | DBG_TRACE_USER("cannot open a new connection for reverse server", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
1925 | 0 | s->conn_err_type = STRM_ET_CONN_ERR; |
1926 | 0 | return SF_ERR_INTERNAL; |
1927 | 0 | } |
1928 | | |
1929 | 0 | if (srv && (srv->flags & SRV_F_STRICT_MAXCONN)) { |
1930 | 0 | int kill_tries = 0; |
1931 | | /* |
1932 | | * Before creating a new connection, make sure we still |
1933 | | * have a slot for that |
1934 | | */ |
1935 | 0 | total_conns = srv->curr_total_conns; |
1936 | |
|
1937 | 0 | while (1) { |
1938 | 0 | if (total_conns < srv->maxconn) { |
1939 | 0 | if (_HA_ATOMIC_CAS(&srv->curr_total_conns, |
1940 | 0 | &total_conns, total_conns + 1)) |
1941 | 0 | break; |
1942 | 0 | __ha_cpu_relax(); |
1943 | 0 | } else { |
1944 | 0 | int ret = kill_random_idle_conn(srv); |
1945 | | |
1946 | | /* |
1947 | | * There is no idle connection to kill |
1948 | | * so there is nothing we can do at |
1949 | | * that point but to report an |
1950 | | * error. |
1951 | | */ |
1952 | 0 | if (ret == -1) |
1953 | 0 | return SF_ERR_RESOURCE; |
1954 | 0 | kill_tries++; |
1955 | | /* |
1956 | | * We tried 3 times to kill an idle |
1957 | | * connection, we failed, give up now. |
1958 | | */ |
1959 | 0 | if (ret == 0 && kill_tries == 3) |
1960 | 0 | return SF_ERR_RESOURCE; |
1961 | 0 | } |
1962 | 0 | } |
1963 | 0 | } |
1964 | 0 | srv_conn = conn_new(s->target); |
1965 | 0 | if (srv_conn) { |
1966 | 0 | DBG_TRACE_STATE("alloc new be connection", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
1967 | 0 | srv_conn->owner = s->sess; |
1968 | | |
1969 | | /* connection will be attached to the session if |
1970 | | * http-reuse mode is never or it is not targeted to a |
1971 | | * server */ |
1972 | 0 | if (reuse_mode == PR_O_REUSE_NEVR || !srv) |
1973 | 0 | conn_set_private(srv_conn); |
1974 | | |
1975 | | /* assign bind_addr to srv_conn */ |
1976 | 0 | srv_conn->src = bind_addr; |
1977 | 0 | bind_addr = NULL; |
1978 | | |
1979 | | /* copy the target address into the connection */ |
1980 | 0 | *srv_conn->dst = *s->scb->dst; |
1981 | | |
1982 | | /* mark? */ |
1983 | 0 | if (s->flags & SF_BC_MARK) { |
1984 | 0 | srv_conn->mark = s->bc_mark; |
1985 | 0 | srv_conn->flags |= CO_FL_OPT_MARK; |
1986 | 0 | } |
1987 | | |
1988 | | /* tos? */ |
1989 | 0 | if (s->flags & SF_BC_TOS) { |
1990 | 0 | srv_conn->tos = s->bc_tos; |
1991 | 0 | srv_conn->flags |= CO_FL_OPT_TOS; |
1992 | 0 | } |
1993 | |
|
1994 | 0 | srv_conn->hash_node.key = hash; |
1995 | 0 | } else if (srv && (srv->flags & SRV_F_STRICT_MAXCONN)) |
1996 | 0 | _HA_ATOMIC_DEC(&srv->curr_total_conns); |
1997 | 0 | } |
1998 | | |
1999 | | /* if bind_addr is non NULL free it */ |
2000 | 0 | sockaddr_free(&bind_addr); |
2001 | | |
2002 | | /* srv_conn is still NULL only on allocation failure */ |
2003 | 0 | if (!srv_conn) |
2004 | 0 | return SF_ERR_RESOURCE; |
2005 | | |
2006 | | #if defined(HAVE_SSL_0RTT) |
2007 | | /* We may be allowed to use 0-RTT involving early data, to send |
2008 | | * the request. This may only be done in the following conditions: |
2009 | | * - the SSL ctx does not support early data |
2010 | | * - the connection was not reused (it must be a new one) |
2011 | | * - the client already used early data, or we have L7 retries on |
2012 | | * - 0rtt is configured on the server line and we have not yet failed |
2013 | | * any connection attempt on this stream (in order to avoid failing |
2014 | | * multiple times in a row) |
2015 | | * - there are data to be sent |
2016 | | * otherwise we cannot make use of early data. Let's first eliminate |
2017 | | * the cases which don't match this above. The conditions will tighten |
2018 | | * later in the function when needed. |
2019 | | */ |
2020 | | |
2021 | | if (!srv || !(srv->ssl_ctx.options & SRV_SSL_O_EARLY_DATA)) |
2022 | | may_use_early_data = 0; |
2023 | | |
2024 | | if (reuse) |
2025 | | may_use_early_data = 0; |
2026 | | |
2027 | | if (!(cli_conn && cli_conn->flags & CO_FL_EARLY_DATA) && |
2028 | | (!(s->be->retry_type & PR_RE_EARLY_ERROR) || s->conn_retries > 0)) |
2029 | | may_use_early_data = 0; |
2030 | | |
2031 | | if (!co_data(sc_oc(s->scb))) |
2032 | | may_use_early_data = 0; |
2033 | | #endif |
2034 | | |
2035 | | /* Copy network namespace from client connection */ |
2036 | 0 | srv_conn->proxy_netns = cli_conn ? cli_conn->proxy_netns : NULL; |
2037 | |
|
2038 | 0 | if (!srv_conn->xprt) { |
2039 | | /* set the correct protocol on the output stream connector */ |
2040 | |
|
2041 | 0 | if (srv) { |
2042 | 0 | struct protocol *proto = protocol_lookup(srv_conn->dst->ss_family, srv->addr_type.proto_type, srv->alt_proto); |
2043 | | #ifdef USE_OPENSSL |
2044 | | struct sample *sni_smp = NULL; |
2045 | | struct ist sni = IST_NULL; |
2046 | | |
2047 | | /* Set socket SNI */ |
2048 | | if (srv->xprt->get_ssl_sock_ctx && srv->ssl_ctx.sni) { |
2049 | | sni_smp = sample_fetch_as_type(s->be, s->sess, s, |
2050 | | SMP_OPT_DIR_REQ | SMP_OPT_FINAL, |
2051 | | srv->ssl_ctx.sni, SMP_T_STR); |
2052 | | if (smp_make_safe(sni_smp)) { |
2053 | | sni = ist2(b_orig(&sni_smp->data.u.str), b_data(&sni_smp->data.u.str)); |
2054 | | srv_conn->sni_hash = ssl_sock_sni_hash(sni); |
2055 | | } |
2056 | | } |
2057 | | |
2058 | | #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) |
2059 | | /* Delay mux initialization if SSL and ALPN/NPN is set |
2060 | | * and server cache is not yet populated. Note that in |
2061 | | * TCP mode this check is ignored as only mux-pt is |
2062 | | * available. |
2063 | | * |
2064 | | * This check must be performed before conn_prepare() |
2065 | | * to ensure consistency across the whole stack, in |
2066 | | * particular for QUIC between quic-conn and mux layer. |
2067 | | */ |
2068 | | if (IS_HTX_STRM(s) && srv->use_ssl && |
2069 | | (srv->ssl_ctx.alpn_str || srv->ssl_ctx.npn_str)) { |
2070 | | HA_RWLOCK_RDLOCK(SERVER_LOCK, &srv->path_params.param_lock); |
2071 | | if (srv->path_params.srv_hash != hash || srv->path_params.nego_alpn[0] == 0) |
2072 | | may_start_mux_now = 0; |
2073 | | HA_RWLOCK_RDUNLOCK(SERVER_LOCK, &srv->path_params.param_lock); |
2074 | | } |
2075 | | #endif /* TLSEXT_TYPE_application_layer_protocol_negotiation */ |
2076 | | |
2077 | | #endif /* USE_OPENSSL */ |
2078 | |
|
2079 | 0 | if (conn_prepare(srv_conn, proto, srv->xprt)) { |
2080 | 0 | conn_free(srv_conn); |
2081 | 0 | return SF_ERR_INTERNAL; |
2082 | 0 | } |
2083 | | #ifdef USE_OPENSSL |
2084 | | if (isttest(sni)) |
2085 | | ssl_sock_set_servername(srv_conn, istptr(sni)); |
2086 | | |
2087 | | #endif |
2088 | 0 | } else if (obj_type(s->target) == OBJ_TYPE_PROXY) { |
2089 | 0 | int ret; |
2090 | | |
2091 | | /* proxies exclusively run on raw_sock right now */ |
2092 | 0 | ret = conn_prepare(srv_conn, protocol_lookup(srv_conn->dst->ss_family, PROTO_TYPE_STREAM, 0), xprt_get(XPRT_RAW)); |
2093 | 0 | if (ret < 0 || !(srv_conn->ctrl)) { |
2094 | 0 | conn_free(srv_conn); |
2095 | 0 | return SF_ERR_INTERNAL; |
2096 | 0 | } |
2097 | 0 | } |
2098 | 0 | else { |
2099 | 0 | conn_free(srv_conn); |
2100 | 0 | return SF_ERR_INTERNAL; /* how did we get there ? */ |
2101 | 0 | } |
2102 | | |
2103 | 0 | if (sc_attach_mux(s->scb, NULL, srv_conn) < 0) { |
2104 | 0 | conn_free(srv_conn); |
2105 | 0 | return SF_ERR_INTERNAL; /* how did we get there ? */ |
2106 | 0 | } |
2107 | 0 | srv_conn->ctx = s->scb; |
2108 | | |
2109 | | /* process the case where the server requires the PROXY protocol to be sent */ |
2110 | 0 | srv_conn->send_proxy_ofs = 0; |
2111 | |
|
2112 | 0 | if (srv && (srv->pp_opts & SRV_PP_ENABLED)) { |
2113 | 0 | srv_conn->flags |= CO_FL_SEND_PROXY; |
2114 | 0 | srv_conn->send_proxy_ofs = 1; /* must compute size */ |
2115 | 0 | } |
2116 | |
|
2117 | 0 | if (srv && (srv->flags & SRV_F_SOCKS4_PROXY)) { |
2118 | 0 | srv_conn->send_proxy_ofs = 1; |
2119 | 0 | srv_conn->flags |= CO_FL_SOCKS4; |
2120 | 0 | } |
2121 | |
|
2122 | 0 | if (may_start_mux_now) { |
2123 | | /* Delay MUX init if an XPRT handshake is required prior. */ |
2124 | 0 | mux_proto = conn_select_mux_be(srv_conn); |
2125 | 0 | if (mux_proto && mux_proto->init_xprt) |
2126 | 0 | may_start_mux_now = 0; |
2127 | 0 | } |
2128 | |
|
2129 | | #if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation) |
2130 | | /* if websocket stream, try to update connection ALPN. */ |
2131 | | if (unlikely(s->flags & SF_WEBSOCKET) && |
2132 | | srv && srv->use_ssl && srv->ssl_ctx.alpn_str) { |
2133 | | char *alpn = ""; |
2134 | | int force = 0; |
2135 | | |
2136 | | switch (srv->ws) { |
2137 | | case SRV_WS_AUTO: |
2138 | | alpn = "\x08http/1.1"; |
2139 | | force = 0; |
2140 | | break; |
2141 | | case SRV_WS_H1: |
2142 | | alpn = "\x08http/1.1"; |
2143 | | force = 1; |
2144 | | break; |
2145 | | case SRV_WS_H2: |
2146 | | alpn = "\x02h2"; |
2147 | | force = 1; |
2148 | | break; |
2149 | | } |
2150 | | |
2151 | | if (!conn_update_alpn(srv_conn, ist(alpn), force)) |
2152 | | DBG_TRACE_STATE("update alpn for websocket", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2153 | | } |
2154 | | #endif |
2155 | 0 | } |
2156 | 0 | else { |
2157 | 0 | s->flags |= SF_SRV_REUSED; |
2158 | | |
2159 | | /* Currently there seems to be no known cases of xprt ready |
2160 | | * without the mux installed here. |
2161 | | */ |
2162 | 0 | BUG_ON(!srv_conn->mux); |
2163 | |
|
2164 | 0 | if (!(srv_conn->mux->ctl(srv_conn, MUX_CTL_STATUS, NULL) & MUX_STATUS_READY)) |
2165 | 0 | s->flags |= SF_SRV_REUSED_ANTICIPATED; |
2166 | 0 | } |
2167 | | |
2168 | | /* flag for logging source ip/port */ |
2169 | 0 | if (strm_fe(s)->options2 & PR_O2_SRC_ADDR) |
2170 | 0 | s->flags |= SF_SRC_ADDR; |
2171 | | |
2172 | | /* disable lingering */ |
2173 | 0 | if (s->be->options & PR_O_TCP_NOLING) |
2174 | 0 | s->scb->flags |= SC_FL_NOLINGER; |
2175 | |
|
2176 | 0 | if (s->flags & SF_SRV_REUSED) { |
2177 | 0 | if (s->be_tgcounters) |
2178 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->reuse); |
2179 | 0 | if (s->sv_tgcounters) |
2180 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->reuse); |
2181 | 0 | } else { |
2182 | 0 | if (s->be_tgcounters) |
2183 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->connect); |
2184 | 0 | if (s->sv_tgcounters) |
2185 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->connect); |
2186 | 0 | } |
2187 | |
|
2188 | 0 | err = do_connect_server(s, srv_conn); |
2189 | 0 | if (err != SF_ERR_NONE) |
2190 | 0 | return err; |
2191 | | |
2192 | | /* The CO_FL_SEND_PROXY flag may have been set by the connect method, |
2193 | | * if so, add our handshake pseudo-XPRT now. |
2194 | | */ |
2195 | 0 | if ((srv_conn->flags & CO_FL_HANDSHAKE)) { |
2196 | 0 | if (xprt_add_hs(srv_conn) < 0) { |
2197 | 0 | conn_full_close(srv_conn); |
2198 | 0 | return SF_ERR_INTERNAL; |
2199 | 0 | } |
2200 | 0 | } |
2201 | | |
2202 | | /* We have to defer the mux initialization until after si_connect() |
2203 | | * has been called, as we need the xprt to have been properly |
2204 | | * initialized, or any attempt to recv during the mux init may |
2205 | | * fail, and flag the connection as CO_FL_ERROR. |
2206 | | */ |
2207 | 0 | if (may_start_mux_now) { |
2208 | 0 | const struct mux_ops *alt_mux = |
2209 | 0 | likely(!(s->flags & SF_WEBSOCKET) || !srv) ? NULL : srv_get_ws_proto(srv); |
2210 | 0 | if (conn_install_mux_be(srv_conn, s->scb, s->sess, alt_mux) < 0) { |
2211 | 0 | conn_full_close(srv_conn); |
2212 | 0 | return SF_ERR_INTERNAL; |
2213 | 0 | } |
2214 | 0 | if (IS_HTX_STRM(s)) { |
2215 | | /* If we're doing http-reuse always, and the connection |
2216 | | * is not private with available streams (an http2 |
2217 | | * connection), add it to the available list, so that |
2218 | | * others can use it right away. If the connection is |
2219 | | * private or we're doing http-reuse safe and the mux |
2220 | | * protocol supports multiplexing, add it in the |
2221 | | * session server list. |
2222 | | */ |
2223 | 0 | if (srv && reuse_mode == PR_O_REUSE_ALWS && |
2224 | 0 | !(srv_conn->flags & CO_FL_PRIVATE) && |
2225 | 0 | srv_conn->mux->avail_streams(srv_conn) > 0) { |
2226 | 0 | srv_add_to_avail_list(srv, srv_conn); |
2227 | 0 | } |
2228 | 0 | else if (srv_conn->flags & CO_FL_PRIVATE || |
2229 | 0 | (reuse_mode == PR_O_REUSE_SAFE && |
2230 | 0 | srv_conn->mux->flags & MX_FL_HOL_RISK)) { |
2231 | | /* If it fail now, the same will be done in mux->detach() callback */ |
2232 | 0 | session_add_conn(s->sess, srv_conn); |
2233 | 0 | } |
2234 | 0 | } |
2235 | 0 | } |
2236 | 0 | else if (mux_proto && mux_proto->init_xprt) { |
2237 | | /* Add handshake layer prior to MUX init if required. Does nothing if SSL layer is active though. */ |
2238 | 0 | if (xprt_add_l6hs(srv_conn, mux_proto->init_xprt)) { |
2239 | 0 | conn_full_close(srv_conn); |
2240 | 0 | return SF_ERR_INTERNAL; |
2241 | 0 | } |
2242 | 0 | } |
2243 | | |
2244 | | /* |
2245 | | * Now that the mux may have been created, we can start the xprt. |
2246 | | * We had to wait until then, because the xprt may behave differently |
2247 | | * depending on if a mux already exists, and it can receive data |
2248 | | * from the stream, or not. |
2249 | | */ |
2250 | 0 | conn_xprt_start(srv_conn); |
2251 | |
|
2252 | | #if defined(HAVE_SSL_0RTT) |
2253 | | /* The flags change below deserve some explanation: when we want to |
2254 | | * use early data, we first want to make sure that a mux is installed |
2255 | | * (otherwise we'll have nothing to send), and then we'll temporarily |
2256 | | * pretend that we're done with the SSL handshake. This way the data |
2257 | | * layer of the stack will be able to start sending data. The xprt |
2258 | | * layer will notice that these data are sent in the context of 0-rtt, |
2259 | | * and will produce early data, and then immediately restore these |
2260 | | * flags to say "I was lying, the SSL layer is not ready in fact". This |
2261 | | * effectively allows early data to be sent with the very first SSL |
2262 | | * communication with the server, while still having the ability to |
2263 | | * later wait for the end of the handshake. |
2264 | | */ |
2265 | | if (may_use_early_data && srv && srv_conn->mux && |
2266 | | srv_conn->flags & CO_FL_SSL_WAIT_HS) |
2267 | | srv_conn->flags &= ~(CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN); |
2268 | | #endif |
2269 | | |
2270 | | /* set connect timeout */ |
2271 | 0 | s->conn_exp = tick_add_ifset(now_ms, s->connect_timeout); |
2272 | |
|
2273 | 0 | if (srv) { |
2274 | 0 | int count; |
2275 | |
|
2276 | 0 | s->flags |= SF_CURR_SESS; |
2277 | 0 | count = _HA_ATOMIC_ADD_FETCH(&srv->cur_sess, 1); |
2278 | 0 | COUNTERS_UPDATE_MAX(&srv->counters.cur_sess_max, count); |
2279 | 0 | if (s->be->lbprm.ops && s->be->lbprm.ops->server_take_conn) |
2280 | 0 | s->be->lbprm.ops->server_take_conn(srv); |
2281 | 0 | } |
2282 | | |
2283 | | /* Now handle synchronously connected sockets. We know the stream connector |
2284 | | * is at least in state SC_ST_CON. These ones typically are UNIX |
2285 | | * sockets, socket pairs, andoccasionally TCP connections on the |
2286 | | * loopback on a heavily loaded system. |
2287 | | */ |
2288 | 0 | if (srv_conn->flags & CO_FL_ERROR) |
2289 | 0 | s->scb->flags |= SC_FL_ERROR; |
2290 | | |
2291 | | /* If we had early data, and the handshake ended, then |
2292 | | * we can remove the flag, and attempt to wake the task up, |
2293 | | * in the event there's an analyser waiting for the end of |
2294 | | * the handshake. |
2295 | | */ |
2296 | 0 | if (!(srv_conn->flags & (CO_FL_WAIT_XPRT | CO_FL_EARLY_SSL_HS))) |
2297 | 0 | sc_ep_clr(s->scb, SE_FL_WAIT_FOR_HS); |
2298 | |
|
2299 | 0 | if (!sc_state_in(s->scb->state, SC_SB_EST|SC_SB_DIS|SC_SB_CLO) && |
2300 | 0 | (srv_conn->flags & CO_FL_WAIT_XPRT) == 0) { |
2301 | 0 | s->conn_exp = TICK_ETERNITY; |
2302 | 0 | sc_oc(s->scb)->flags |= CF_WRITE_EVENT; |
2303 | 0 | if (s->scb->state == SC_ST_CON) |
2304 | 0 | s->scb->state = SC_ST_RDY; |
2305 | 0 | } |
2306 | | |
2307 | | /* Report EOI on the channel if it was reached from the mux point of |
2308 | | * view. |
2309 | | * |
2310 | | * Note: This test is only required because si_cs_process is also the SI |
2311 | | * wake callback. Otherwise si_cs_recv()/si_cs_send() already take |
2312 | | * care of it. |
2313 | | */ |
2314 | 0 | if (sc_ep_test(s->scb, SE_FL_EOI) && !(s->scb->flags & SC_FL_EOI)) { |
2315 | 0 | s->scb->flags |= SC_FL_EOI; |
2316 | 0 | sc_ic(s->scb)->flags |= CF_READ_EVENT; |
2317 | 0 | } |
2318 | | |
2319 | | /* catch all sync connect while the mux is not already installed */ |
2320 | 0 | if (!srv_conn->mux && !(srv_conn->flags & CO_FL_WAIT_XPRT)) { |
2321 | 0 | int closed_connection; |
2322 | |
|
2323 | 0 | if (conn_create_mux(srv_conn, &closed_connection) < 0) { |
2324 | 0 | if (closed_connection == 0) |
2325 | 0 | conn_full_close(srv_conn); |
2326 | 0 | return SF_ERR_INTERNAL; |
2327 | 0 | } |
2328 | 0 | } |
2329 | | |
2330 | 0 | return SF_ERR_NONE; /* connection is OK */ |
2331 | 0 | } |
2332 | | |
2333 | | |
2334 | | /* This function performs the "redispatch" part of a connection attempt. It |
2335 | | * will assign a server if required, queue the connection if required, and |
2336 | | * handle errors that might arise at this level. It can change the server |
2337 | | * state. It will return 1 if it encounters an error, switches the server |
2338 | | * state, or has to queue a connection. Otherwise, it will return 0 indicating |
2339 | | * that the connection is ready to use. |
2340 | | */ |
2341 | | |
2342 | | int srv_redispatch_connect(struct stream *s) |
2343 | 0 | { |
2344 | 0 | struct server *srv; |
2345 | 0 | int conn_err; |
2346 | | |
2347 | | /* We know that we don't have any connection pending, so we will |
2348 | | * try to get a new one, and wait in this state if it's queued |
2349 | | */ |
2350 | 0 | redispatch: |
2351 | 0 | conn_err = assign_server_and_queue(s); |
2352 | 0 | srv = objt_server(s->target); |
2353 | |
|
2354 | 0 | switch (conn_err) { |
2355 | 0 | case SRV_STATUS_OK: |
2356 | 0 | break; |
2357 | | |
2358 | 0 | case SRV_STATUS_FULL: |
2359 | | /* The server has reached its maxqueue limit. Either PR_O_REDISP is set |
2360 | | * and we can redispatch to another server, or it is not and we return |
2361 | | * 503. This only makes sense in DIRECT mode however, because normal LB |
2362 | | * algorithms would never select such a server, and hash algorithms |
2363 | | * would bring us on the same server again. Note that s->target is set |
2364 | | * in this case. |
2365 | | */ |
2366 | 0 | if (((s->flags & (SF_DIRECT|SF_FORCE_PRST)) == SF_DIRECT) && |
2367 | 0 | (s->be->options & PR_O_REDISP)) { |
2368 | 0 | s->flags &= ~(SF_DIRECT | SF_ASSIGNED); |
2369 | 0 | sockaddr_free(&s->scb->dst); |
2370 | 0 | goto redispatch; |
2371 | 0 | } |
2372 | | |
2373 | 0 | if (!s->conn_err_type) { |
2374 | 0 | s->conn_err_type = STRM_ET_QUEUE_ERR; |
2375 | 0 | } |
2376 | |
|
2377 | 0 | if (s->sv_tgcounters) |
2378 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->failed_conns); |
2379 | 0 | if (s->be_tgcounters) |
2380 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->failed_conns); |
2381 | 0 | return 1; |
2382 | | |
2383 | 0 | case SRV_STATUS_NOSRV: |
2384 | | /* note: it is guaranteed that srv == NULL here */ |
2385 | 0 | if (!s->conn_err_type) { |
2386 | 0 | s->conn_err_type = STRM_ET_CONN_ERR; |
2387 | 0 | } |
2388 | |
|
2389 | 0 | if (s->be_tgcounters) |
2390 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->failed_conns); |
2391 | 0 | return 1; |
2392 | | |
2393 | 0 | case SRV_STATUS_QUEUED: |
2394 | 0 | s->conn_exp = tick_add_ifset(now_ms, s->queue_timeout); |
2395 | 0 | s->scb->state = SC_ST_QUE; |
2396 | | |
2397 | | /* handle the unlikely event where we added to the server's |
2398 | | * queue just after checking the server was full and before |
2399 | | * it released its last entry (with extremely low maxconn). |
2400 | | * Not needed for backend queues, already handled in |
2401 | | * assign_server_and_queue(). |
2402 | | */ |
2403 | 0 | if (unlikely(srv && may_dequeue_tasks(srv, s->be))) |
2404 | 0 | process_srv_queue(srv); |
2405 | |
|
2406 | 0 | return 1; |
2407 | | |
2408 | 0 | case SRV_STATUS_INTERNAL: |
2409 | 0 | default: |
2410 | 0 | if (!s->conn_err_type) { |
2411 | 0 | s->conn_err_type = STRM_ET_CONN_OTHER; |
2412 | 0 | } |
2413 | |
|
2414 | 0 | if (srv) |
2415 | 0 | srv_inc_sess_ctr(srv); |
2416 | 0 | if (srv) |
2417 | 0 | srv_set_sess_last(srv); |
2418 | 0 | if (s->sv_tgcounters) |
2419 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->failed_conns); |
2420 | 0 | if (s->be_tgcounters) |
2421 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->failed_conns); |
2422 | | |
2423 | | /* release other streams waiting for this server */ |
2424 | 0 | if (may_dequeue_tasks(srv, s->be)) |
2425 | 0 | process_srv_queue(srv); |
2426 | 0 | return 1; |
2427 | 0 | } |
2428 | | /* if we get here, it's because we got SRV_STATUS_OK, which also |
2429 | | * means that the connection has not been queued. |
2430 | | */ |
2431 | 0 | return 0; |
2432 | 0 | } |
2433 | | |
2434 | | /* Check if the connection request is in such a state that it can be aborted. */ |
2435 | | static int back_may_abort_req(struct channel *req, struct stream *s) |
2436 | 0 | { |
2437 | 0 | return ((s->scf->flags & SC_FL_ERROR) || |
2438 | 0 | ((s->scb->flags & (SC_FL_SHUT_WANTED|SC_FL_SHUT_DONE)) && /* empty and client aborted */ |
2439 | 0 | (!co_data(req) || proxy_abrt_close(s->be)))); |
2440 | 0 | } |
2441 | | |
2442 | | /* Update back stream connector status for input states SC_ST_ASS, SC_ST_QUE, |
2443 | | * SC_ST_TAR. Other input states are simply ignored. |
2444 | | * Possible output states are SC_ST_CLO, SC_ST_TAR, SC_ST_ASS, SC_ST_REQ, SC_ST_CON |
2445 | | * and SC_ST_EST. Flags must have previously been updated for timeouts and other |
2446 | | * conditions. |
2447 | | */ |
2448 | | void back_try_conn_req(struct stream *s) |
2449 | 0 | { |
2450 | 0 | struct server *srv = objt_server(s->target); |
2451 | 0 | struct stconn *sc = s->scb; |
2452 | 0 | struct channel *req = &s->req; |
2453 | |
|
2454 | 0 | DBG_TRACE_ENTER(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2455 | |
|
2456 | 0 | if (sc->state == SC_ST_ASS) { |
2457 | | /* Server assigned to connection request, we have to try to connect now */ |
2458 | 0 | int conn_err; |
2459 | | |
2460 | | /* Before we try to initiate the connection, see if the |
2461 | | * request may be aborted instead. |
2462 | | */ |
2463 | 0 | if (back_may_abort_req(req, s)) { |
2464 | 0 | s->conn_err_type |= STRM_ET_CONN_ABRT; |
2465 | 0 | DBG_TRACE_STATE("connection aborted", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2466 | 0 | goto abort_connection; |
2467 | 0 | } |
2468 | | |
2469 | 0 | conn_err = connect_server(s); |
2470 | 0 | srv = objt_server(s->target); |
2471 | |
|
2472 | 0 | if (conn_err == SF_ERR_NONE) { |
2473 | | /* state = SC_ST_CON or SC_ST_EST now */ |
2474 | 0 | if (srv) |
2475 | 0 | srv_inc_sess_ctr(srv); |
2476 | 0 | if (srv) |
2477 | 0 | srv_set_sess_last(srv); |
2478 | 0 | DBG_TRACE_STATE("connection attempt", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2479 | 0 | goto end; |
2480 | 0 | } |
2481 | | |
2482 | | /* We have received a synchronous error. We might have to |
2483 | | * abort, retry immediately or redispatch. |
2484 | | */ |
2485 | 0 | if (conn_err == SF_ERR_INTERNAL) { |
2486 | 0 | if (!s->conn_err_type) { |
2487 | 0 | s->conn_err_type = STRM_ET_CONN_OTHER; |
2488 | 0 | } |
2489 | |
|
2490 | 0 | if (srv) |
2491 | 0 | srv_inc_sess_ctr(srv); |
2492 | 0 | if (srv) |
2493 | 0 | srv_set_sess_last(srv); |
2494 | 0 | if (s->sv_tgcounters) |
2495 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->failed_conns); |
2496 | 0 | if (s->be_tgcounters) |
2497 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->failed_conns); |
2498 | | |
2499 | | /* release other streams waiting for this server */ |
2500 | 0 | sess_change_server(s, NULL); |
2501 | 0 | if (may_dequeue_tasks(srv, s->be)) |
2502 | 0 | process_srv_queue(srv); |
2503 | | |
2504 | | /* Failed and not retryable. */ |
2505 | 0 | sc_abort(sc); |
2506 | 0 | sc_shutdown(sc); |
2507 | 0 | sc->flags |= SC_FL_ERROR; |
2508 | |
|
2509 | 0 | s->logs.t_queue = ns_to_ms(now_ns - s->logs.accept_ts); |
2510 | | |
2511 | | /* we may need to know the position in the queue for logging */ |
2512 | 0 | pendconn_cond_unlink(s->pend_pos); |
2513 | | |
2514 | | /* no stream was ever accounted for this server */ |
2515 | 0 | sc->state = SC_ST_CLO; |
2516 | 0 | if (s->srv_error) |
2517 | 0 | s->srv_error(s, sc); |
2518 | 0 | DBG_TRACE_STATE("internal error during connection", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2519 | 0 | goto end; |
2520 | 0 | } |
2521 | | |
2522 | | /* We are facing a retryable error, but we don't want to run a |
2523 | | * turn-around now, as the problem is likely a source port |
2524 | | * allocation problem, so we want to retry now. |
2525 | | */ |
2526 | 0 | sc->state = SC_ST_CER; |
2527 | 0 | sc->flags &= ~SC_FL_ERROR; |
2528 | 0 | back_handle_st_cer(s); |
2529 | |
|
2530 | 0 | DBG_TRACE_STATE("connection error, retry", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2531 | | /* now sc->state is one of SC_ST_CLO, SC_ST_TAR, SC_ST_ASS, SC_ST_REQ */ |
2532 | 0 | } |
2533 | 0 | else if (sc->state == SC_ST_QUE) { |
2534 | | /* connection request was queued, check for any update */ |
2535 | 0 | if (!pendconn_dequeue(s)) { |
2536 | | /* The connection is not in the queue anymore. Either |
2537 | | * we have a server connection slot available and we |
2538 | | * go directly to the assigned state, or we need to |
2539 | | * load-balance first and go to the INI state. |
2540 | | */ |
2541 | 0 | s->conn_exp = TICK_ETERNITY; |
2542 | 0 | if (unlikely(!(s->flags & SF_ASSIGNED))) |
2543 | 0 | sc->state = SC_ST_REQ; |
2544 | 0 | else { |
2545 | 0 | s->logs.t_queue = ns_to_ms(now_ns - s->logs.accept_ts); |
2546 | 0 | sc->state = SC_ST_ASS; |
2547 | 0 | } |
2548 | 0 | DBG_TRACE_STATE("dequeue connection request", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2549 | 0 | goto end; |
2550 | 0 | } |
2551 | | |
2552 | | /* Connection request still in queue... */ |
2553 | 0 | if (s->flags & SF_CONN_EXP) { |
2554 | | /* ... and timeout expired */ |
2555 | 0 | s->conn_exp = TICK_ETERNITY; |
2556 | 0 | s->flags &= ~SF_CONN_EXP; |
2557 | 0 | s->logs.t_queue = ns_to_ms(now_ns - s->logs.accept_ts); |
2558 | | |
2559 | | /* we may need to know the position in the queue for logging */ |
2560 | 0 | pendconn_cond_unlink(s->pend_pos); |
2561 | |
|
2562 | 0 | if (s->sv_tgcounters) |
2563 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->failed_conns); |
2564 | 0 | if (s->be_tgcounters) |
2565 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->failed_conns); |
2566 | 0 | sc_abort(sc); |
2567 | 0 | sc_shutdown(sc); |
2568 | 0 | req->flags |= CF_WRITE_TIMEOUT; |
2569 | 0 | if (!s->conn_err_type) |
2570 | 0 | s->conn_err_type = STRM_ET_QUEUE_TO; |
2571 | 0 | sc->state = SC_ST_CLO; |
2572 | 0 | if (s->srv_error) |
2573 | 0 | s->srv_error(s, sc); |
2574 | 0 | DBG_TRACE_STATE("connection request still queued", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2575 | 0 | goto end; |
2576 | 0 | } |
2577 | | |
2578 | | /* Connection remains in queue, check if we have to abort it */ |
2579 | 0 | if (back_may_abort_req(req, s)) { |
2580 | 0 | s->logs.t_queue = ns_to_ms(now_ns - s->logs.accept_ts); |
2581 | | |
2582 | | /* we may need to know the position in the queue for logging */ |
2583 | 0 | pendconn_cond_unlink(s->pend_pos); |
2584 | |
|
2585 | 0 | s->conn_err_type |= STRM_ET_QUEUE_ABRT; |
2586 | 0 | DBG_TRACE_STATE("abort queued connection request", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2587 | 0 | goto abort_connection; |
2588 | 0 | } |
2589 | | |
2590 | | /* Nothing changed */ |
2591 | 0 | } |
2592 | 0 | else if (sc->state == SC_ST_TAR) { |
2593 | | /* Connection request might be aborted */ |
2594 | 0 | if (back_may_abort_req(req, s)) { |
2595 | 0 | s->conn_err_type |= STRM_ET_CONN_ABRT; |
2596 | 0 | DBG_TRACE_STATE("connection aborted", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2597 | 0 | goto abort_connection; |
2598 | 0 | } |
2599 | | |
2600 | 0 | if (!(s->flags & SF_CONN_EXP)) |
2601 | 0 | return; /* still in turn-around */ |
2602 | | |
2603 | 0 | s->flags &= ~SF_CONN_EXP; |
2604 | 0 | s->conn_exp = TICK_ETERNITY; |
2605 | | |
2606 | | /* we keep trying on the same server as long as the stream is |
2607 | | * marked "assigned". |
2608 | | * FIXME: Should we force a redispatch attempt when the server is down ? |
2609 | | */ |
2610 | 0 | if (s->flags & SF_ASSIGNED) |
2611 | 0 | sc->state = SC_ST_ASS; |
2612 | 0 | else |
2613 | 0 | sc->state = SC_ST_REQ; |
2614 | |
|
2615 | 0 | DBG_TRACE_STATE("retry connection now", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2616 | 0 | } |
2617 | | |
2618 | 0 | end: |
2619 | 0 | DBG_TRACE_LEAVE(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2620 | 0 | return; |
2621 | | |
2622 | 0 | abort_connection: |
2623 | | /* give up */ |
2624 | 0 | s->conn_exp = TICK_ETERNITY; |
2625 | 0 | s->flags &= ~SF_CONN_EXP; |
2626 | 0 | sc_abort(sc); |
2627 | 0 | sc_shutdown(sc); |
2628 | 0 | sc->state = SC_ST_CLO; |
2629 | 0 | if (s->srv_error) |
2630 | 0 | s->srv_error(s, sc); |
2631 | 0 | DBG_TRACE_DEVEL("leaving on error", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2632 | 0 | return; |
2633 | 0 | } |
2634 | | |
2635 | | /* This function initiates a server connection request on a stream connector |
2636 | | * already in SC_ST_REQ state. Upon success, the state goes to SC_ST_ASS for |
2637 | | * a real connection to a server, indicating that a server has been assigned, |
2638 | | * or SC_ST_RDY for a successful connection to an applet. It may also return |
2639 | | * SC_ST_QUE, or SC_ST_CLO upon error. |
2640 | | */ |
2641 | | void back_handle_st_req(struct stream *s) |
2642 | 0 | { |
2643 | 0 | struct stconn *sc = s->scb; |
2644 | |
|
2645 | 0 | if (sc->state != SC_ST_REQ) |
2646 | 0 | return; |
2647 | | |
2648 | 0 | DBG_TRACE_ENTER(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2649 | |
|
2650 | 0 | if (unlikely(obj_type(s->target) == OBJ_TYPE_APPLET)) { |
2651 | 0 | struct appctx *appctx; |
2652 | | |
2653 | | /* The target is an applet but the SC is in SC_ST_REQ. Thus it |
2654 | | * means no appctx are attached to the SC. Otherwise, it will be |
2655 | | * in SC_ST_RDY state. So, try to create the appctx now. |
2656 | | */ |
2657 | 0 | BUG_ON(sc_appctx(sc)); |
2658 | 0 | appctx = sc_applet_create(sc, objt_applet(s->target)); |
2659 | 0 | if (!appctx) { |
2660 | | /* No more memory, let's immediately abort. Force the |
2661 | | * error code to ignore the ERR_LOCAL which is not a |
2662 | | * real error. |
2663 | | */ |
2664 | 0 | s->flags &= ~(SF_ERR_MASK | SF_FINST_MASK); |
2665 | |
|
2666 | 0 | sc_abort(sc); |
2667 | 0 | sc_shutdown(sc); |
2668 | 0 | sc->flags |= SC_FL_ERROR; |
2669 | 0 | s->conn_err_type = STRM_ET_CONN_RES; |
2670 | 0 | sc->state = SC_ST_CLO; |
2671 | 0 | if (s->srv_error) |
2672 | 0 | s->srv_error(s, sc); |
2673 | 0 | DBG_TRACE_STATE("failed to register applet", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2674 | 0 | goto end; |
2675 | 0 | } |
2676 | | |
2677 | 0 | DBG_TRACE_STATE("applet registered", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2678 | 0 | goto end; |
2679 | 0 | } |
2680 | | |
2681 | | /* Try to assign a server */ |
2682 | 0 | if (srv_redispatch_connect(s) != 0) { |
2683 | | /* We did not get a server. Either we queued the |
2684 | | * connection request, or we encountered an error. |
2685 | | */ |
2686 | 0 | if (sc->state == SC_ST_QUE) { |
2687 | 0 | DBG_TRACE_STATE("connection request queued", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2688 | 0 | goto end; |
2689 | 0 | } |
2690 | | |
2691 | | /* we did not get any server, let's check the cause */ |
2692 | 0 | sc_abort(sc); |
2693 | 0 | sc_shutdown(sc); |
2694 | 0 | sc->flags |= SC_FL_ERROR; |
2695 | 0 | if (!s->conn_err_type) |
2696 | 0 | s->conn_err_type = STRM_ET_CONN_OTHER; |
2697 | 0 | sc->state = SC_ST_CLO; |
2698 | 0 | if (s->srv_error) |
2699 | 0 | s->srv_error(s, sc); |
2700 | 0 | DBG_TRACE_STATE("connection request failed", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2701 | 0 | goto end; |
2702 | 0 | } |
2703 | | |
2704 | | /* The server is assigned */ |
2705 | 0 | s->logs.t_queue = ns_to_ms(now_ns - s->logs.accept_ts); |
2706 | 0 | sc->state = SC_ST_ASS; |
2707 | 0 | be_set_sess_last(s->be); |
2708 | 0 | DBG_TRACE_STATE("connection request assigned to a server", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2709 | |
|
2710 | 0 | end: |
2711 | 0 | DBG_TRACE_LEAVE(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2712 | 0 | } |
2713 | | |
2714 | | /* This function is called with (sc->state == SC_ST_CON) meaning that a |
2715 | | * connection was attempted and that the file descriptor is already allocated. |
2716 | | * We must check for timeout, error and abort. Possible output states are |
2717 | | * SC_ST_CER (error), SC_ST_DIS (abort), and SC_ST_CON (no change). This only |
2718 | | * works with connection-based streams. We know that there were no I/O event |
2719 | | * when reaching this function. Timeouts and errors are *not* cleared. |
2720 | | */ |
2721 | | void back_handle_st_con(struct stream *s) |
2722 | 0 | { |
2723 | 0 | struct stconn *sc = s->scb; |
2724 | 0 | struct channel *req = &s->req; |
2725 | |
|
2726 | 0 | DBG_TRACE_ENTER(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2727 | | |
2728 | | /* the client might want to abort */ |
2729 | 0 | if ((s->scf->flags & SC_FL_SHUT_DONE) || |
2730 | 0 | ((s->scb->flags & SC_FL_SHUT_WANTED) && |
2731 | 0 | (!co_data(req) || proxy_abrt_close(s->be)))) { |
2732 | 0 | sc->flags |= SC_FL_NOLINGER; |
2733 | 0 | sc_shutdown(sc); |
2734 | 0 | s->conn_err_type |= STRM_ET_CONN_ABRT; |
2735 | 0 | if (s->srv_error) |
2736 | 0 | s->srv_error(s, sc); |
2737 | | /* Note: state = SC_ST_DIS now */ |
2738 | 0 | DBG_TRACE_STATE("client abort during connection attempt", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2739 | 0 | goto end; |
2740 | 0 | } |
2741 | | |
2742 | 0 | done: |
2743 | | /* retryable error ? */ |
2744 | 0 | if ((s->flags & SF_CONN_EXP) || (sc->flags & SC_FL_ERROR)) { |
2745 | 0 | if (!s->conn_err_type) { |
2746 | 0 | if ((sc->flags & SC_FL_ERROR)) |
2747 | 0 | s->conn_err_type = STRM_ET_CONN_ERR; |
2748 | 0 | else |
2749 | 0 | s->conn_err_type = STRM_ET_CONN_TO; |
2750 | 0 | } |
2751 | |
|
2752 | 0 | sc->state = SC_ST_CER; |
2753 | 0 | DBG_TRACE_STATE("connection failed, retry", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2754 | 0 | } |
2755 | |
|
2756 | 0 | end: |
2757 | 0 | DBG_TRACE_LEAVE(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2758 | 0 | } |
2759 | | |
2760 | | /* This function is called with (sc->state == SC_ST_CER) meaning that a |
2761 | | * previous connection attempt has failed and that the file descriptor |
2762 | | * has already been released. Possible causes include asynchronous error |
2763 | | * notification and time out. Possible output states are SC_ST_CLO when |
2764 | | * retries are exhausted, SC_ST_TAR when a delay is wanted before a new |
2765 | | * connection attempt, SC_ST_ASS when it's wise to retry on the same server, |
2766 | | * and SC_ST_REQ when an immediate redispatch is wanted. The buffers are |
2767 | | * marked as in error state. Timeouts and errors are cleared before retrying. |
2768 | | */ |
2769 | | void back_handle_st_cer(struct stream *s) |
2770 | 0 | { |
2771 | 0 | struct stconn *sc = s->scb; |
2772 | 0 | int must_tar = !!(sc->flags & SC_FL_ERROR); |
2773 | |
|
2774 | 0 | DBG_TRACE_ENTER(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2775 | |
|
2776 | 0 | s->conn_exp = TICK_ETERNITY; |
2777 | 0 | s->flags &= ~SF_CONN_EXP; |
2778 | | |
2779 | | /* we probably have to release last stream from the server */ |
2780 | 0 | if (objt_server(s->target)) { |
2781 | 0 | struct connection *conn = sc_conn(sc); |
2782 | |
|
2783 | 0 | health_adjust(__objt_server(s->target), HANA_STATUS_L4_ERR); |
2784 | |
|
2785 | 0 | if (s->flags & SF_CURR_SESS) { |
2786 | 0 | s->flags &= ~SF_CURR_SESS; |
2787 | 0 | _HA_ATOMIC_DEC(&__objt_server(s->target)->cur_sess); |
2788 | 0 | } |
2789 | |
|
2790 | 0 | if ((sc->flags & SC_FL_ERROR) && |
2791 | 0 | conn && conn->err_code == CO_ER_SSL_MISMATCH_SNI) { |
2792 | | /* We tried to connect to a server which is configured |
2793 | | * with "verify required" and which doesn't have the |
2794 | | * "verifyhost" directive. The server presented a wrong |
2795 | | * certificate (a certificate for an unexpected name), |
2796 | | * which implies that we have used SNI in the handshake, |
2797 | | * and that the server doesn't have the associated cert |
2798 | | * and presented a default one. |
2799 | | * |
2800 | | * This is a serious enough issue not to retry. It's |
2801 | | * especially important because this wrong name might |
2802 | | * either be the result of a configuration error, and |
2803 | | * retrying will only hammer the server, or is caused |
2804 | | * by the use of a wrong SNI value, most likely |
2805 | | * provided by the client and we don't want to let the |
2806 | | * client provoke retries. |
2807 | | */ |
2808 | 0 | s->conn_retries = s->max_retries; |
2809 | 0 | DBG_TRACE_DEVEL("Bad SSL cert, disable connection retries", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2810 | 0 | } |
2811 | 0 | } |
2812 | | |
2813 | | /* ensure that we have enough retries left */ |
2814 | 0 | if (s->conn_retries >= s->max_retries || !(s->be->retry_type & PR_RE_CONN_FAILED)) { |
2815 | 0 | if (!s->conn_err_type) { |
2816 | 0 | s->conn_err_type = STRM_ET_CONN_ERR; |
2817 | 0 | } |
2818 | |
|
2819 | 0 | if (s->sv_tgcounters) |
2820 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->failed_conns); |
2821 | 0 | if (s->be_tgcounters) |
2822 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->failed_conns); |
2823 | 0 | sess_change_server(s, NULL); |
2824 | 0 | if (may_dequeue_tasks(objt_server(s->target), s->be)) |
2825 | 0 | process_srv_queue(objt_server(s->target)); |
2826 | | |
2827 | | /* shutw is enough to stop a connecting socket */ |
2828 | 0 | sc_shutdown(sc); |
2829 | 0 | sc->flags |= SC_FL_ERROR; |
2830 | |
|
2831 | 0 | sc->state = SC_ST_CLO; |
2832 | 0 | if (s->srv_error) |
2833 | 0 | s->srv_error(s, sc); |
2834 | |
|
2835 | 0 | DBG_TRACE_STATE("connection failed", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2836 | 0 | goto end; |
2837 | 0 | } |
2838 | | |
2839 | | /* At this stage, we will trigger a connection retry (with or without |
2840 | | * redispatch). Thus we must reset the SI endpoint on the server side |
2841 | | * an close the attached connection. It is especially important to do it |
2842 | | * now if the retry is not immediately performed, to be sure to release |
2843 | | * resources as soon as possible and to not catch errors from the lower |
2844 | | * layers in an unexpected state (i.e < ST_CONN). |
2845 | | * |
2846 | | * Note: the stream connector will be switched to ST_REQ, ST_ASS or |
2847 | | * ST_TAR and SC_FL_ERROR and SF_CONN_EXP flags will be unset. |
2848 | | */ |
2849 | 0 | if (sc_reset_endp(sc) < 0) { |
2850 | 0 | if (!s->conn_err_type) |
2851 | 0 | s->conn_err_type = STRM_ET_CONN_OTHER; |
2852 | |
|
2853 | 0 | if (s->sv_tgcounters) |
2854 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->internal_errors); |
2855 | 0 | if (s->be_tgcounters) |
2856 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->internal_errors); |
2857 | 0 | sess_change_server(s, NULL); |
2858 | 0 | if (may_dequeue_tasks(objt_server(s->target), s->be)) |
2859 | 0 | process_srv_queue(objt_server(s->target)); |
2860 | | |
2861 | | /* shutw is enough to stop a connecting socket */ |
2862 | 0 | sc_shutdown(sc); |
2863 | 0 | sc->flags |= SC_FL_ERROR; |
2864 | |
|
2865 | 0 | sc->state = SC_ST_CLO; |
2866 | 0 | if (s->srv_error) |
2867 | 0 | s->srv_error(s, sc); |
2868 | |
|
2869 | 0 | DBG_TRACE_STATE("error resetting endpoint", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2870 | 0 | goto end; |
2871 | 0 | } |
2872 | | |
2873 | 0 | s->conn_retries++; |
2874 | 0 | stream_choose_redispatch(s); |
2875 | |
|
2876 | 0 | if (must_tar) { |
2877 | | /* The error was an asynchronous connection error, and we will |
2878 | | * likely have to retry connecting to the same server, most |
2879 | | * likely leading to the same result. To avoid this, we wait |
2880 | | * MIN(one second, connect timeout) before retrying. We don't |
2881 | | * do it when the failure happened on a reused connection |
2882 | | * though. |
2883 | | */ |
2884 | |
|
2885 | 0 | int delay = 1000; |
2886 | 0 | const int reused = (s->flags & SF_SRV_REUSED) && |
2887 | 0 | !(s->flags & SF_SRV_REUSED_ANTICIPATED); |
2888 | |
|
2889 | 0 | if (s->be->timeout.connect && s->be->timeout.connect < delay) |
2890 | 0 | delay = s->be->timeout.connect; |
2891 | |
|
2892 | 0 | if (!s->conn_err_type) |
2893 | 0 | s->conn_err_type = STRM_ET_CONN_ERR; |
2894 | | |
2895 | | /* only wait when we're retrying on the same server */ |
2896 | 0 | if ((sc->state == SC_ST_ASS || |
2897 | 0 | (s->be->srv_act <= 1)) && !reused) { |
2898 | 0 | sc->state = SC_ST_TAR; |
2899 | 0 | s->conn_exp = tick_add(now_ms, MS_TO_TICKS(delay)); |
2900 | 0 | } |
2901 | 0 | DBG_TRACE_STATE("retry a new connection", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2902 | 0 | } |
2903 | |
|
2904 | 0 | end: |
2905 | 0 | DBG_TRACE_LEAVE(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2906 | 0 | } |
2907 | | |
2908 | | /* This function is called with (sc->state == SC_ST_RDY) meaning that a |
2909 | | * connection was attempted, that the file descriptor is already allocated, |
2910 | | * and that it has succeeded. We must still check for errors and aborts. |
2911 | | * Possible output states are SC_ST_EST (established), SC_ST_CER (error), |
2912 | | * and SC_ST_DIS (abort). This only works with connection-based streams. |
2913 | | * Timeouts and errors are *not* cleared. |
2914 | | */ |
2915 | | void back_handle_st_rdy(struct stream *s) |
2916 | 0 | { |
2917 | 0 | struct stconn *sc = s->scb; |
2918 | 0 | struct channel *req = &s->req; |
2919 | |
|
2920 | 0 | DBG_TRACE_ENTER(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2921 | |
|
2922 | 0 | if (unlikely(obj_type(s->target) == OBJ_TYPE_APPLET)) { |
2923 | | /* Here the appctx must exists because the SC was set to |
2924 | | * SC_ST_RDY state when the appctx was created. |
2925 | | */ |
2926 | 0 | BUG_ON(!sc_appctx(s->scb)); |
2927 | |
|
2928 | 0 | if (!s->logs.request_ts) |
2929 | 0 | s->logs.request_ts = now_ns; |
2930 | 0 | s->logs.t_queue = ns_to_ms(now_ns - s->logs.accept_ts); |
2931 | 0 | be_set_sess_last(s->be); |
2932 | 0 | } |
2933 | | |
2934 | | /* We know the connection at least succeeded, though it could have |
2935 | | * since met an error for any other reason. At least it didn't time out |
2936 | | * even though the timeout might have been reported right after success. |
2937 | | * We need to take care of various situations here : |
2938 | | * - everything might be OK. We have to switch to established. |
2939 | | * - an I/O error might have been reported after a successful transfer, |
2940 | | * which is not retryable and needs to be logged correctly, and needs |
2941 | | * established as well |
2942 | | * - SC_ST_CON implies !CF_WROTE_DATA but not conversely as we could |
2943 | | * have validated a connection with incoming data (e.g. TCP with a |
2944 | | * banner protocol), or just a successful connect() probe. |
2945 | | * - the client might have requested a connection abort, this needs to |
2946 | | * be checked before we decide to retry anything. |
2947 | | */ |
2948 | | |
2949 | | /* it's still possible to handle client aborts or connection retries |
2950 | | * before any data were sent. |
2951 | | */ |
2952 | 0 | if (!(req->flags & CF_WROTE_DATA)) { |
2953 | | /* client abort ? */ |
2954 | 0 | if ((s->scf->flags & SC_FL_SHUT_DONE) || |
2955 | 0 | ((s->scb->flags & SC_FL_SHUT_WANTED) && |
2956 | 0 | (!co_data(req) || proxy_abrt_close(s->be)))) { |
2957 | | /* give up */ |
2958 | 0 | sc->flags |= SC_FL_NOLINGER; |
2959 | 0 | sc_shutdown(sc); |
2960 | 0 | s->conn_err_type |= STRM_ET_CONN_ABRT; |
2961 | 0 | if (s->srv_error) |
2962 | 0 | s->srv_error(s, sc); |
2963 | 0 | DBG_TRACE_STATE("client abort during connection attempt", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2964 | 0 | goto end; |
2965 | 0 | } |
2966 | | |
2967 | | /* retryable error ? */ |
2968 | 0 | if (sc->flags & SC_FL_ERROR) { |
2969 | 0 | if (!s->conn_err_type) |
2970 | 0 | s->conn_err_type = STRM_ET_CONN_ERR; |
2971 | 0 | sc->state = SC_ST_CER; |
2972 | 0 | DBG_TRACE_STATE("connection failed, retry", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); |
2973 | 0 | goto end; |
2974 | 0 | } |
2975 | 0 | } |
2976 | | |
2977 | | /* data were sent and/or we had no error, back_establish() will |
2978 | | * now take over. |
2979 | | */ |
2980 | 0 | DBG_TRACE_STATE("connection established", STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2981 | 0 | s->conn_err_type = STRM_ET_NONE; |
2982 | 0 | sc->state = SC_ST_EST; |
2983 | |
|
2984 | 0 | end: |
2985 | 0 | DBG_TRACE_LEAVE(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); |
2986 | 0 | } |
2987 | | |
2988 | | /* sends a log message when a backend goes down, and also sets last |
2989 | | * change date. |
2990 | | */ |
2991 | | void set_backend_down(struct proxy *be) |
2992 | 0 | { |
2993 | 0 | be->last_change = ns_to_sec(now_ns); |
2994 | 0 | HA_ATOMIC_STORE(&be->be_counters.shared.tg[tgid - 1]->last_state_change, be->last_change); |
2995 | 0 | _HA_ATOMIC_INC(&be->be_counters.shared.tg[tgid - 1]->down_trans); |
2996 | |
|
2997 | 0 | if (!(global.mode & MODE_STARTING)) { |
2998 | 0 | ha_alert("%s '%s' has no server available!\n", proxy_type_str(be), be->id); |
2999 | 0 | send_log(be, LOG_EMERG, "%s %s has no server available!\n", proxy_type_str(be), be->id); |
3000 | 0 | } |
3001 | 0 | } |
3002 | | |
3003 | | /* Apply RDP cookie persistence to the current stream. For this, the function |
3004 | | * tries to extract an RDP cookie from the request buffer, and look for the |
3005 | | * matching server in the list. If the server is found, it is assigned to the |
3006 | | * stream. This always returns 1, and the analyser removes itself from the |
3007 | | * list. Nothing is performed if a server was already assigned. |
3008 | | */ |
3009 | | int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit) |
3010 | 0 | { |
3011 | 0 | struct proxy *px = s->be; |
3012 | 0 | int ret; |
3013 | 0 | struct sample smp; |
3014 | 0 | struct server *srv = px->srv; |
3015 | 0 | uint16_t port; |
3016 | 0 | uint32_t addr; |
3017 | 0 | char *p; |
3018 | |
|
3019 | 0 | DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s); |
3020 | |
|
3021 | 0 | if (s->flags & SF_ASSIGNED) |
3022 | 0 | goto no_cookie; |
3023 | | |
3024 | 0 | memset(&smp, 0, sizeof(smp)); |
3025 | |
|
3026 | 0 | ret = fetch_rdp_cookie_name(s, &smp, s->be->rdp_cookie_name, s->be->rdp_cookie_len); |
3027 | 0 | if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || smp.data.u.str.data == 0) |
3028 | 0 | goto no_cookie; |
3029 | | |
3030 | | /* Considering an rdp cookie detected using acl, str ended with <cr><lf> and should return. |
3031 | | * The cookie format is <ip> "." <port> where "ip" is the integer corresponding to the |
3032 | | * server's IP address in network order, and "port" is the integer corresponding to the |
3033 | | * server's port in network order. Comments please Emeric. |
3034 | | */ |
3035 | 0 | addr = strtoul(smp.data.u.str.area, &p, 10); |
3036 | 0 | if (*p != '.') |
3037 | 0 | goto no_cookie; |
3038 | 0 | p++; |
3039 | |
|
3040 | 0 | port = ntohs(strtoul(p, &p, 10)); |
3041 | 0 | if (*p != '.') |
3042 | 0 | goto no_cookie; |
3043 | | |
3044 | 0 | s->target = NULL; |
3045 | 0 | while (srv) { |
3046 | 0 | if (srv->addr.ss_family == AF_INET && |
3047 | 0 | port == srv->svc_port && |
3048 | 0 | addr == ((struct sockaddr_in *)&srv->addr)->sin_addr.s_addr) { |
3049 | 0 | if ((srv->cur_state != SRV_ST_STOPPED) || (px->options & PR_O_PERSIST)) { |
3050 | | /* we found the server and it is usable */ |
3051 | 0 | s->flags |= SF_DIRECT | SF_ASSIGNED; |
3052 | 0 | stream_set_srv_target(s, srv); |
3053 | 0 | break; |
3054 | 0 | } |
3055 | 0 | } |
3056 | 0 | srv = srv->next; |
3057 | 0 | } |
3058 | |
|
3059 | 0 | no_cookie: |
3060 | 0 | req->analysers &= ~an_bit; |
3061 | 0 | req->analyse_exp = TICK_ETERNITY; |
3062 | 0 | DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s); |
3063 | 0 | return 1; |
3064 | 0 | } |
3065 | | |
3066 | 0 | int be_downtime(struct proxy *px) { |
3067 | 0 | if (px->lbprm.tot_weight && px->last_change < ns_to_sec(now_ns)) // ignore negative time |
3068 | 0 | return px->down_time; |
3069 | | |
3070 | 0 | return ns_to_sec(now_ns) - px->last_change + px->down_time; |
3071 | 0 | } |
3072 | | |
3073 | | /* Checks if <px> backend supports the addition of servers at runtime. Either a |
3074 | | * backend or a defaults proxy are supported. If proxy is incompatible, <msg> |
3075 | | * will be allocated to contain a textual explanation. |
3076 | | */ |
3077 | | int be_supports_dynamic_srv(struct proxy *px, char **msg) |
3078 | 0 | { |
3079 | 0 | if (px->lbprm.algo && !(px->lbprm.algo & BE_LB_PROP_DYN)) { |
3080 | 0 | memprintf(msg, "%s '%s' uses a non dynamic load balancing method", |
3081 | 0 | proxy_cap_str(px->cap), px->id); |
3082 | 0 | return 0; |
3083 | 0 | } |
3084 | | |
3085 | 0 | if (px->mode == PR_MODE_SYSLOG) { |
3086 | 0 | memprintf(msg, "%s '%s' uses mode log", |
3087 | 0 | proxy_cap_str(px->cap), px->id); |
3088 | 0 | return 0; |
3089 | 0 | } |
3090 | | |
3091 | 0 | return 1; |
3092 | 0 | } |
3093 | | |
3094 | | /* |
3095 | | * This function returns a string containing the balancing |
3096 | | * mode of the proxy in a format suitable for stats. |
3097 | | */ |
3098 | | |
3099 | 0 | const char *backend_lb_algo_str(int algo) { |
3100 | |
|
3101 | 0 | if (algo == BE_LB_ALGO_RR) |
3102 | 0 | return "roundrobin"; |
3103 | 0 | else if (algo == BE_LB_ALGO_SRR) |
3104 | 0 | return "static-rr"; |
3105 | 0 | else if (algo == BE_LB_ALGO_FAS) |
3106 | 0 | return "first"; |
3107 | 0 | else if (algo == BE_LB_ALGO_LC) |
3108 | 0 | return "leastconn"; |
3109 | 0 | else if (algo == BE_LB_ALGO_SH) |
3110 | 0 | return "source"; |
3111 | 0 | else if (algo == BE_LB_ALGO_UH) |
3112 | 0 | return "uri"; |
3113 | 0 | else if (algo == BE_LB_ALGO_PH) |
3114 | 0 | return "url_param"; |
3115 | 0 | else if (algo == BE_LB_ALGO_HH) |
3116 | 0 | return "hdr"; |
3117 | 0 | else if (algo == BE_LB_ALGO_RCH) |
3118 | 0 | return "rdp-cookie"; |
3119 | 0 | else if (algo == BE_LB_ALGO_SMP) |
3120 | 0 | return "hash"; |
3121 | 0 | else if (algo == BE_LB_ALGO_NONE) |
3122 | 0 | return "none"; |
3123 | 0 | else |
3124 | 0 | return "unknown"; |
3125 | 0 | } |
3126 | | |
3127 | | /* This function parses a "balance" statement in a backend section describing |
3128 | | * <curproxy>. It returns -1 if there is any error, otherwise zero. If it |
3129 | | * returns -1, it will write an error message into the <err> buffer which will |
3130 | | * automatically be allocated and must be passed as NULL. The trailing '\n' |
3131 | | * will not be written. The function must be called with <args> pointing to the |
3132 | | * first word after "balance". |
3133 | | */ |
3134 | | int backend_parse_balance(const char **args, char **err, struct proxy *curproxy) |
3135 | 0 | { |
3136 | 0 | if (!*(args[0])) { |
3137 | | /* if no option is set, use random by default */ |
3138 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3139 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_RND; |
3140 | 0 | return 0; |
3141 | 0 | } |
3142 | | |
3143 | 0 | if (strcmp(args[0], "roundrobin") == 0) { |
3144 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3145 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_RR; |
3146 | 0 | } |
3147 | 0 | else if (strcmp(args[0], "static-rr") == 0) { |
3148 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3149 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_SRR; |
3150 | 0 | } |
3151 | 0 | else if (strcmp(args[0], "first") == 0) { |
3152 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3153 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_FAS; |
3154 | 0 | } |
3155 | 0 | else if (strcmp(args[0], "leastconn") == 0) { |
3156 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3157 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_LC; |
3158 | 0 | } |
3159 | 0 | else if (!strncmp(args[0], "random", 6)) { |
3160 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3161 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_RND; |
3162 | 0 | curproxy->lbprm.arg_opt1 = 2; |
3163 | |
|
3164 | 0 | if (*(args[0] + 6) == '(' && *(args[0] + 7) != ')') { /* number of draws */ |
3165 | 0 | const char *beg; |
3166 | 0 | char *end; |
3167 | |
|
3168 | 0 | beg = args[0] + 7; |
3169 | 0 | curproxy->lbprm.arg_opt1 = strtol(beg, &end, 0); |
3170 | |
|
3171 | 0 | if (*end != ')') { |
3172 | 0 | if (!*end) |
3173 | 0 | memprintf(err, "random : missing closing parenthesis."); |
3174 | 0 | else |
3175 | 0 | memprintf(err, "random : unexpected character '%c' after argument.", *end); |
3176 | 0 | return -1; |
3177 | 0 | } |
3178 | | |
3179 | 0 | if (curproxy->lbprm.arg_opt1 < 1) { |
3180 | 0 | memprintf(err, "random : number of draws must be at least 1."); |
3181 | 0 | return -1; |
3182 | 0 | } |
3183 | 0 | } |
3184 | 0 | } |
3185 | 0 | else if (strcmp(args[0], "source") == 0) { |
3186 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3187 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_SH; |
3188 | 0 | } |
3189 | 0 | else if (strcmp(args[0], "uri") == 0) { |
3190 | 0 | int arg = 1; |
3191 | |
|
3192 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3193 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_UH; |
3194 | 0 | curproxy->lbprm.arg_opt1 = 0; // "whole", "path-only" |
3195 | 0 | curproxy->lbprm.arg_opt2 = 0; // "len" |
3196 | 0 | curproxy->lbprm.arg_opt3 = 0; // "depth" |
3197 | |
|
3198 | 0 | while (*args[arg]) { |
3199 | 0 | if (strcmp(args[arg], "len") == 0) { |
3200 | 0 | if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) { |
3201 | 0 | memprintf(err, "%s : '%s' expects a positive integer (got '%s').", args[0], args[arg], args[arg+1]); |
3202 | 0 | return -1; |
3203 | 0 | } |
3204 | 0 | curproxy->lbprm.arg_opt2 = atoi(args[arg+1]); |
3205 | 0 | arg += 2; |
3206 | 0 | } |
3207 | 0 | else if (strcmp(args[arg], "depth") == 0) { |
3208 | 0 | if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) { |
3209 | 0 | memprintf(err, "%s : '%s' expects a positive integer (got '%s').", args[0], args[arg], args[arg+1]); |
3210 | 0 | return -1; |
3211 | 0 | } |
3212 | | /* hint: we store the position of the ending '/' (depth+1) so |
3213 | | * that we avoid a comparison while computing the hash. |
3214 | | */ |
3215 | 0 | curproxy->lbprm.arg_opt3 = atoi(args[arg+1]) + 1; |
3216 | 0 | arg += 2; |
3217 | 0 | } |
3218 | 0 | else if (strcmp(args[arg], "whole") == 0) { |
3219 | 0 | curproxy->lbprm.arg_opt1 |= 1; |
3220 | 0 | arg += 1; |
3221 | 0 | } |
3222 | 0 | else if (strcmp(args[arg], "path-only") == 0) { |
3223 | 0 | curproxy->lbprm.arg_opt1 |= 2; |
3224 | 0 | arg += 1; |
3225 | 0 | } |
3226 | 0 | else { |
3227 | 0 | memprintf(err, "%s only accepts parameters 'len', 'depth', 'path-only', and 'whole' (got '%s').", args[0], args[arg]); |
3228 | 0 | return -1; |
3229 | 0 | } |
3230 | 0 | } |
3231 | 0 | } |
3232 | 0 | else if (strcmp(args[0], "url_param") == 0) { |
3233 | 0 | if (!*args[1]) { |
3234 | 0 | memprintf(err, "%s requires an URL parameter name.", args[0]); |
3235 | 0 | return -1; |
3236 | 0 | } |
3237 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3238 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_PH; |
3239 | |
|
3240 | 0 | free(curproxy->lbprm.arg_str); |
3241 | 0 | curproxy->lbprm.arg_str = strdup(args[1]); |
3242 | 0 | curproxy->lbprm.arg_len = strlen(args[1]); |
3243 | 0 | if (*args[2]) { |
3244 | 0 | if (strcmp(args[2], "check_post") != 0) { |
3245 | 0 | memprintf(err, "%s only accepts 'check_post' modifier (got '%s').", args[0], args[2]); |
3246 | 0 | return -1; |
3247 | 0 | } |
3248 | 0 | } |
3249 | 0 | } |
3250 | 0 | else if (strcmp(args[0], "hash") == 0) { |
3251 | 0 | if (!*args[1]) { |
3252 | 0 | memprintf(err, "%s requires a sample expression.", args[0]); |
3253 | 0 | return -1; |
3254 | 0 | } |
3255 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3256 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_SMP; |
3257 | |
|
3258 | 0 | ha_free(&curproxy->lbprm.arg_str); |
3259 | 0 | curproxy->lbprm.arg_str = strdup(args[1]); |
3260 | 0 | curproxy->lbprm.arg_len = strlen(args[1]); |
3261 | |
|
3262 | 0 | if (*args[2]) { |
3263 | 0 | memprintf(err, "%s takes no other argument (got '%s').", args[0], args[2]); |
3264 | 0 | return -1; |
3265 | 0 | } |
3266 | 0 | } |
3267 | 0 | else if (!strncmp(args[0], "hdr(", 4)) { |
3268 | 0 | const char *beg, *end; |
3269 | |
|
3270 | 0 | beg = args[0] + 4; |
3271 | 0 | end = strchr(beg, ')'); |
3272 | |
|
3273 | 0 | if (!end || end == beg) { |
3274 | 0 | memprintf(err, "hdr requires an http header field name."); |
3275 | 0 | return -1; |
3276 | 0 | } |
3277 | | |
3278 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3279 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_HH; |
3280 | |
|
3281 | 0 | free(curproxy->lbprm.arg_str); |
3282 | 0 | curproxy->lbprm.arg_len = end - beg; |
3283 | 0 | curproxy->lbprm.arg_str = my_strndup(beg, end - beg); |
3284 | 0 | curproxy->lbprm.arg_opt1 = 0; |
3285 | |
|
3286 | 0 | if (*args[1]) { |
3287 | 0 | if (strcmp(args[1], "use_domain_only") != 0) { |
3288 | 0 | memprintf(err, "%s only accepts 'use_domain_only' modifier (got '%s').", args[0], args[1]); |
3289 | 0 | return -1; |
3290 | 0 | } |
3291 | 0 | curproxy->lbprm.arg_opt1 = 1; |
3292 | 0 | } |
3293 | 0 | } |
3294 | 0 | else if (!strncmp(args[0], "rdp-cookie", 10)) { |
3295 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3296 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_RCH; |
3297 | |
|
3298 | 0 | if ( *(args[0] + 10 ) == '(' ) { /* cookie name */ |
3299 | 0 | const char *beg, *end; |
3300 | |
|
3301 | 0 | beg = args[0] + 11; |
3302 | 0 | end = strchr(beg, ')'); |
3303 | |
|
3304 | 0 | if (!end || end == beg) { |
3305 | 0 | memprintf(err, "rdp-cookie : missing cookie name."); |
3306 | 0 | return -1; |
3307 | 0 | } |
3308 | | |
3309 | 0 | free(curproxy->lbprm.arg_str); |
3310 | 0 | curproxy->lbprm.arg_str = my_strndup(beg, end - beg); |
3311 | 0 | curproxy->lbprm.arg_len = end - beg; |
3312 | 0 | } |
3313 | 0 | else if ( *(args[0] + 10 ) == '\0' ) { /* default cookie name 'mstshash' */ |
3314 | 0 | free(curproxy->lbprm.arg_str); |
3315 | 0 | curproxy->lbprm.arg_str = strdup("mstshash"); |
3316 | 0 | curproxy->lbprm.arg_len = strlen(curproxy->lbprm.arg_str); |
3317 | 0 | } |
3318 | 0 | else { /* syntax */ |
3319 | 0 | memprintf(err, "rdp-cookie : missing cookie name."); |
3320 | 0 | return -1; |
3321 | 0 | } |
3322 | 0 | } |
3323 | 0 | else if (strcmp(args[0], "log-hash") == 0) { |
3324 | 0 | if (!*args[1]) { |
3325 | 0 | memprintf(err, "%s requires a converter list.", args[0]); |
3326 | 0 | return -1; |
3327 | 0 | } |
3328 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3329 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_LH; |
3330 | |
|
3331 | 0 | ha_free(&curproxy->lbprm.arg_str); |
3332 | 0 | curproxy->lbprm.arg_str = strdup(args[1]); |
3333 | 0 | } |
3334 | 0 | else if (strcmp(args[0], "sticky") == 0) { |
3335 | 0 | curproxy->lbprm.algo &= ~BE_LB_ALGO; |
3336 | 0 | curproxy->lbprm.algo |= BE_LB_ALGO_SS; |
3337 | 0 | } |
3338 | 0 | else { |
3339 | 0 | memprintf(err, "only supports 'roundrobin', 'static-rr', 'leastconn', 'source', 'uri', 'url_param', 'hash', 'hdr(name)', 'rdp-cookie(name)', 'log-hash' and 'sticky' options."); |
3340 | 0 | return -1; |
3341 | 0 | } |
3342 | 0 | return 0; |
3343 | 0 | } |
3344 | | |
3345 | | |
3346 | | /************************************************************************/ |
3347 | | /* All supported sample and ACL keywords must be declared here. */ |
3348 | | /************************************************************************/ |
3349 | | |
3350 | | /* set temp integer to the number of enabled servers on the proxy. |
3351 | | * Accepts exactly 1 argument. Argument is a backend, other types will lead to |
3352 | | * undefined behaviour. |
3353 | | */ |
3354 | | static int |
3355 | | smp_fetch_nbsrv(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3356 | 0 | { |
3357 | 0 | struct proxy *px = args->data.prx; |
3358 | |
|
3359 | 0 | if (px == NULL) |
3360 | 0 | return 0; |
3361 | 0 | if (px->cap & PR_CAP_DEF) |
3362 | 0 | px = smp->px; |
3363 | |
|
3364 | 0 | smp->flags = SMP_F_VOL_TEST; |
3365 | 0 | smp->data.type = SMP_T_SINT; |
3366 | |
|
3367 | 0 | smp->data.u.sint = be_usable_srv(px); |
3368 | |
|
3369 | 0 | return 1; |
3370 | 0 | } |
3371 | | |
3372 | | /* report in smp->flags a success or failure depending on the designated |
3373 | | * server's state. There is no match function involved since there's no pattern. |
3374 | | * Accepts exactly 1 argument. Argument is a server, other types will lead to |
3375 | | * undefined behaviour. |
3376 | | */ |
3377 | | static int |
3378 | | smp_fetch_srv_is_up(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3379 | 0 | { |
3380 | 0 | struct server *srv = args->data.srv; |
3381 | |
|
3382 | 0 | smp->flags = SMP_F_VOL_TEST; |
3383 | 0 | smp->data.type = SMP_T_BOOL; |
3384 | 0 | if (!(srv->cur_admin & SRV_ADMF_MAINT) && |
3385 | 0 | (!(srv->check.state & CHK_ST_CONFIGURED) || (srv->cur_state != SRV_ST_STOPPED))) |
3386 | 0 | smp->data.u.sint = 1; |
3387 | 0 | else |
3388 | 0 | smp->data.u.sint = 0; |
3389 | 0 | return 1; |
3390 | 0 | } |
3391 | | |
3392 | | /* set temp integer to the number of enabled servers on the proxy. |
3393 | | * Accepts exactly 1 argument. Argument is a backend, other types will lead to |
3394 | | * undefined behaviour. |
3395 | | */ |
3396 | | static int |
3397 | | smp_fetch_connslots(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3398 | 0 | { |
3399 | 0 | struct server *iterator; |
3400 | 0 | struct proxy *px = args->data.prx; |
3401 | |
|
3402 | 0 | if (px == NULL) |
3403 | 0 | return 0; |
3404 | 0 | if (px->cap & PR_CAP_DEF) |
3405 | 0 | px = smp->px; |
3406 | |
|
3407 | 0 | smp->flags = SMP_F_VOL_TEST; |
3408 | 0 | smp->data.type = SMP_T_SINT; |
3409 | 0 | smp->data.u.sint = 0; |
3410 | |
|
3411 | 0 | for (iterator = px->srv; iterator; iterator = iterator->next) { |
3412 | 0 | if (iterator->cur_state == SRV_ST_STOPPED) |
3413 | 0 | continue; |
3414 | | |
3415 | 0 | if (iterator->maxconn == 0 || iterator->maxqueue == 0) { |
3416 | | /* configuration is stupid */ |
3417 | 0 | smp->data.u.sint = -1; /* FIXME: stupid value! */ |
3418 | 0 | return 1; |
3419 | 0 | } |
3420 | | |
3421 | 0 | smp->data.u.sint += (iterator->maxconn - iterator->cur_sess) |
3422 | 0 | + (iterator->maxqueue - iterator->queueslength); |
3423 | 0 | } |
3424 | | |
3425 | 0 | return 1; |
3426 | 0 | } |
3427 | | |
3428 | | /* set temp integer to the id of the backend */ |
3429 | | static int |
3430 | | smp_fetch_be_id(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3431 | 0 | { |
3432 | 0 | struct proxy *px = NULL; |
3433 | |
|
3434 | 0 | if (smp->strm) |
3435 | 0 | px = smp->strm->be; |
3436 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3437 | 0 | px = __objt_check(smp->sess->origin)->proxy; |
3438 | 0 | if (!px) |
3439 | 0 | return 0; |
3440 | | |
3441 | 0 | smp->flags = SMP_F_VOL_TXN; |
3442 | 0 | smp->data.type = SMP_T_SINT; |
3443 | 0 | smp->data.u.sint = px->uuid; |
3444 | 0 | return 1; |
3445 | 0 | } |
3446 | | |
3447 | | /* set string to the name of the backend */ |
3448 | | static int |
3449 | | smp_fetch_be_name(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3450 | 0 | { |
3451 | 0 | struct proxy *px = NULL; |
3452 | |
|
3453 | 0 | if (smp->strm) |
3454 | 0 | px = smp->strm->be; |
3455 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3456 | 0 | px = __objt_check(smp->sess->origin)->proxy; |
3457 | 0 | if (!px) |
3458 | 0 | return 0; |
3459 | | |
3460 | 0 | smp->data.u.str.area = (char *)px->id; |
3461 | 0 | if (!smp->data.u.str.area) |
3462 | 0 | return 0; |
3463 | | |
3464 | 0 | smp->data.type = SMP_T_STR; |
3465 | 0 | smp->flags = SMP_F_CONST; |
3466 | 0 | smp->data.u.str.data = strlen(smp->data.u.str.area); |
3467 | |
|
3468 | 0 | return 1; |
3469 | 0 | } |
3470 | | |
3471 | | /* set temp integer to the id of the server */ |
3472 | | static int |
3473 | | smp_fetch_srv_id(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3474 | 0 | { |
3475 | 0 | struct server *srv = NULL; |
3476 | |
|
3477 | 0 | if (smp->strm) |
3478 | 0 | srv = objt_server(smp->strm->target); |
3479 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3480 | 0 | srv = __objt_check(smp->sess->origin)->server; |
3481 | 0 | if (!srv) |
3482 | 0 | return 0; |
3483 | | |
3484 | 0 | smp->data.type = SMP_T_SINT; |
3485 | 0 | smp->data.u.sint = srv->puid; |
3486 | |
|
3487 | 0 | return 1; |
3488 | 0 | } |
3489 | | |
3490 | | /* set string to the name of the server */ |
3491 | | static int |
3492 | | smp_fetch_srv_name(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3493 | 0 | { |
3494 | 0 | struct server *srv = NULL; |
3495 | |
|
3496 | 0 | if (smp->strm) |
3497 | 0 | srv = objt_server(smp->strm->target); |
3498 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3499 | 0 | srv = __objt_check(smp->sess->origin)->server; |
3500 | 0 | if (!srv) |
3501 | 0 | return 0; |
3502 | | |
3503 | 0 | smp->data.u.str.area = srv->id; |
3504 | 0 | if (!smp->data.u.str.area) |
3505 | 0 | return 0; |
3506 | | |
3507 | 0 | smp->data.type = SMP_T_STR; |
3508 | 0 | smp->flags = SMP_F_CONST; |
3509 | 0 | smp->data.u.str.data = strlen(smp->data.u.str.area); |
3510 | |
|
3511 | 0 | return 1; |
3512 | 0 | } |
3513 | | |
3514 | | /* set temp integer to the number of connections per second reaching the backend. |
3515 | | * Accepts exactly 1 argument. Argument is a backend, other types will lead to |
3516 | | * undefined behaviour. |
3517 | | */ |
3518 | | static int |
3519 | | smp_fetch_be_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3520 | 0 | { |
3521 | 0 | struct proxy *px = args->data.prx; |
3522 | |
|
3523 | 0 | if (px == NULL) |
3524 | 0 | return 0; |
3525 | 0 | if (px->cap & PR_CAP_DEF) |
3526 | 0 | px = smp->px; |
3527 | |
|
3528 | 0 | smp->flags = SMP_F_VOL_TEST; |
3529 | 0 | smp->data.type = SMP_T_SINT; |
3530 | 0 | smp->data.u.sint = COUNTERS_SHARED_TOTAL(px->be_counters.shared.tg, sess_per_sec, read_freq_ctr); |
3531 | 0 | return 1; |
3532 | 0 | } |
3533 | | |
3534 | | /* set temp integer to the number of concurrent connections on the backend. |
3535 | | * Accepts exactly 1 argument. Argument is a backend, other types will lead to |
3536 | | * undefined behaviour. |
3537 | | */ |
3538 | | static int |
3539 | | smp_fetch_be_conn(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3540 | 0 | { |
3541 | 0 | struct proxy *px = args->data.prx; |
3542 | |
|
3543 | 0 | if (px == NULL) |
3544 | 0 | return 0; |
3545 | 0 | if (px->cap & PR_CAP_DEF) |
3546 | 0 | px = smp->px; |
3547 | |
|
3548 | 0 | smp->flags = SMP_F_VOL_TEST; |
3549 | 0 | smp->data.type = SMP_T_SINT; |
3550 | 0 | smp->data.u.sint = px->beconn; |
3551 | 0 | return 1; |
3552 | 0 | } |
3553 | | |
3554 | | /* set temp integer to the number of available connections across available |
3555 | | * servers on the backend. |
3556 | | * Accepts exactly 1 argument. Argument is a backend, other types will lead to |
3557 | | * undefined behaviour. |
3558 | | */ |
3559 | | static int |
3560 | | smp_fetch_be_conn_free(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3561 | 0 | { |
3562 | 0 | struct server *iterator; |
3563 | 0 | struct proxy *px = args->data.prx; |
3564 | 0 | unsigned int maxconn; |
3565 | |
|
3566 | 0 | if (px == NULL) |
3567 | 0 | return 0; |
3568 | 0 | if (px->cap & PR_CAP_DEF) |
3569 | 0 | px = smp->px; |
3570 | |
|
3571 | 0 | smp->flags = SMP_F_VOL_TEST; |
3572 | 0 | smp->data.type = SMP_T_SINT; |
3573 | 0 | smp->data.u.sint = 0; |
3574 | |
|
3575 | 0 | for (iterator = px->srv; iterator; iterator = iterator->next) { |
3576 | 0 | if (iterator->cur_state == SRV_ST_STOPPED) |
3577 | 0 | continue; |
3578 | | |
3579 | 0 | px = iterator->proxy; |
3580 | 0 | if (!srv_currently_usable(iterator) || |
3581 | 0 | ((iterator->flags & SRV_F_BACKUP) && |
3582 | 0 | (px->srv_act || (iterator != px->lbprm.fbck && !(px->options & PR_O_USE_ALL_BK))))) |
3583 | 0 | continue; |
3584 | | |
3585 | 0 | if (iterator->maxconn == 0) { |
3586 | | /* one active server is unlimited, return -1 */ |
3587 | 0 | smp->data.u.sint = -1; |
3588 | 0 | return 1; |
3589 | 0 | } |
3590 | | |
3591 | 0 | maxconn = srv_dynamic_maxconn(iterator); |
3592 | 0 | if (maxconn > iterator->cur_sess) |
3593 | 0 | smp->data.u.sint += maxconn - iterator->cur_sess; |
3594 | 0 | } |
3595 | | |
3596 | 0 | return 1; |
3597 | 0 | } |
3598 | | |
3599 | | /* set temp integer to the total number of queued connections on the backend. |
3600 | | * Accepts exactly 1 argument. Argument is a backend, other types will lead to |
3601 | | * undefined behaviour. |
3602 | | */ |
3603 | | static int |
3604 | | smp_fetch_queue_size(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3605 | 0 | { |
3606 | 0 | struct proxy *px = args->data.prx; |
3607 | |
|
3608 | 0 | if (px == NULL) |
3609 | 0 | return 0; |
3610 | 0 | if (px->cap & PR_CAP_DEF) |
3611 | 0 | px = smp->px; |
3612 | |
|
3613 | 0 | smp->flags = SMP_F_VOL_TEST; |
3614 | 0 | smp->data.type = SMP_T_SINT; |
3615 | 0 | smp->data.u.sint = px->totpend; |
3616 | 0 | return 1; |
3617 | 0 | } |
3618 | | |
3619 | | /* set temp integer to the total number of queued connections on the backend divided |
3620 | | * by the number of running servers and rounded up. If there is no running |
3621 | | * server, we return twice the total, just as if we had half a running server. |
3622 | | * This is more or less correct anyway, since we expect the last server to come |
3623 | | * back soon. |
3624 | | * Accepts exactly 1 argument. Argument is a backend, other types will lead to |
3625 | | * undefined behaviour. |
3626 | | */ |
3627 | | static int |
3628 | | smp_fetch_avg_queue_size(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3629 | 0 | { |
3630 | 0 | struct proxy *px = args->data.prx; |
3631 | 0 | int nbsrv; |
3632 | |
|
3633 | 0 | if (px == NULL) |
3634 | 0 | return 0; |
3635 | 0 | if (px->cap & PR_CAP_DEF) |
3636 | 0 | px = smp->px; |
3637 | |
|
3638 | 0 | smp->flags = SMP_F_VOL_TEST; |
3639 | 0 | smp->data.type = SMP_T_SINT; |
3640 | |
|
3641 | 0 | nbsrv = be_usable_srv(px); |
3642 | |
|
3643 | 0 | if (nbsrv > 0) |
3644 | 0 | smp->data.u.sint = (px->totpend + nbsrv - 1) / nbsrv; |
3645 | 0 | else |
3646 | 0 | smp->data.u.sint = px->totpend * 2; |
3647 | |
|
3648 | 0 | return 1; |
3649 | 0 | } |
3650 | | |
3651 | | /* set temp integer to the number of concurrent connections on the server in the backend. |
3652 | | * Accepts exactly 1 argument. Argument is a server, other types will lead to |
3653 | | * undefined behaviour. |
3654 | | */ |
3655 | | static int |
3656 | | smp_fetch_srv_conn(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3657 | 0 | { |
3658 | 0 | smp->flags = SMP_F_VOL_TEST; |
3659 | 0 | smp->data.type = SMP_T_SINT; |
3660 | 0 | smp->data.u.sint = args->data.srv->cur_sess; |
3661 | 0 | return 1; |
3662 | 0 | } |
3663 | | |
3664 | | /* set temp integer to the number of available connections on the server in the backend. |
3665 | | * Accepts exactly 1 argument. Argument is a server, other types will lead to |
3666 | | * undefined behaviour. |
3667 | | */ |
3668 | | static int |
3669 | | smp_fetch_srv_conn_free(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3670 | 0 | { |
3671 | 0 | unsigned int maxconn; |
3672 | |
|
3673 | 0 | smp->flags = SMP_F_VOL_TEST; |
3674 | 0 | smp->data.type = SMP_T_SINT; |
3675 | |
|
3676 | 0 | if (args->data.srv->maxconn == 0) { |
3677 | | /* one active server is unlimited, return -1 */ |
3678 | 0 | smp->data.u.sint = -1; |
3679 | 0 | return 1; |
3680 | 0 | } |
3681 | | |
3682 | 0 | maxconn = srv_dynamic_maxconn(args->data.srv); |
3683 | 0 | if (maxconn > args->data.srv->cur_sess) |
3684 | 0 | smp->data.u.sint = maxconn - args->data.srv->cur_sess; |
3685 | 0 | else |
3686 | 0 | smp->data.u.sint = 0; |
3687 | |
|
3688 | 0 | return 1; |
3689 | 0 | } |
3690 | | |
3691 | | /* set temp integer to the number of connections pending in the server's queue. |
3692 | | * Accepts exactly 1 argument. Argument is a server, other types will lead to |
3693 | | * undefined behaviour. |
3694 | | */ |
3695 | | static int |
3696 | | smp_fetch_srv_queue(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3697 | 0 | { |
3698 | 0 | smp->flags = SMP_F_VOL_TEST; |
3699 | 0 | smp->data.type = SMP_T_SINT; |
3700 | 0 | smp->data.u.sint = args->data.srv->queueslength; |
3701 | 0 | return 1; |
3702 | 0 | } |
3703 | | |
3704 | | /* set temp integer to the number of enabled servers on the proxy. |
3705 | | * Accepts exactly 1 argument. Argument is a server, other types will lead to |
3706 | | * undefined behaviour. |
3707 | | */ |
3708 | | static int |
3709 | | smp_fetch_srv_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3710 | 0 | { |
3711 | 0 | smp->flags = SMP_F_VOL_TEST; |
3712 | 0 | smp->data.type = SMP_T_SINT; |
3713 | 0 | smp->data.u.sint = COUNTERS_SHARED_TOTAL(args->data.srv->counters.shared.tg, sess_per_sec, read_freq_ctr); |
3714 | 0 | return 1; |
3715 | 0 | } |
3716 | | |
3717 | | /* set temp integer to the server weight. |
3718 | | * Accepts exactly 1 argument. Argument is a server, other types will lead to |
3719 | | * undefined behaviour. |
3720 | | */ |
3721 | | static int |
3722 | | smp_fetch_srv_weight(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3723 | 0 | { |
3724 | 0 | struct server *srv = args->data.srv; |
3725 | 0 | struct proxy *px = srv->proxy; |
3726 | |
|
3727 | 0 | smp->flags = SMP_F_VOL_TEST; |
3728 | 0 | smp->data.type = SMP_T_SINT; |
3729 | 0 | smp->data.u.sint = (srv->cur_eweight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv; |
3730 | 0 | return 1; |
3731 | 0 | } |
3732 | | |
3733 | | /* set temp integer to the server initial weight. |
3734 | | * Accepts exactly 1 argument. Argument is a server, other types will lead to |
3735 | | * undefined behaviour. |
3736 | | */ |
3737 | | static int |
3738 | | smp_fetch_srv_iweight(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3739 | 0 | { |
3740 | 0 | smp->flags = SMP_F_VOL_TEST; |
3741 | 0 | smp->data.type = SMP_T_SINT; |
3742 | 0 | smp->data.u.sint = args->data.srv->iweight; |
3743 | 0 | return 1; |
3744 | 0 | } |
3745 | | |
3746 | | /* set temp integer to the server user-specified weight. |
3747 | | * Accepts exactly 1 argument. Argument is a server, other types will lead to |
3748 | | * undefined behaviour. |
3749 | | */ |
3750 | | static int |
3751 | | smp_fetch_srv_uweight(const struct arg *args, struct sample *smp, const char *kw, void *private) |
3752 | 0 | { |
3753 | 0 | smp->flags = SMP_F_VOL_TEST; |
3754 | 0 | smp->data.type = SMP_T_SINT; |
3755 | 0 | smp->data.u.sint = args->data.srv->uweight; |
3756 | 0 | return 1; |
3757 | 0 | } |
3758 | | |
3759 | | static int |
3760 | | smp_fetch_be_max_retries(const struct arg *args, struct sample *smp, const char *km, void *private) |
3761 | 0 | { |
3762 | 0 | struct proxy *px = NULL; |
3763 | |
|
3764 | 0 | if (smp->strm) |
3765 | 0 | px = smp->strm->be; |
3766 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3767 | 0 | px = __objt_check(smp->sess->origin)->proxy; |
3768 | 0 | if (!px) |
3769 | 0 | return 0; |
3770 | | |
3771 | 0 | smp->flags = SMP_F_VOL_TXN; |
3772 | 0 | smp->data.type = SMP_T_SINT; |
3773 | 0 | smp->data.u.sint = px->conn_retries; |
3774 | 0 | return 1; |
3775 | 0 | } |
3776 | | |
3777 | | static int |
3778 | | smp_fetch_be_connect_timeout(const struct arg *args, struct sample *smp, const char *km, void *private) |
3779 | 0 | { |
3780 | 0 | struct proxy *px = NULL; |
3781 | |
|
3782 | 0 | if (smp->strm) |
3783 | 0 | px = smp->strm->be; |
3784 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3785 | 0 | px = __objt_check(smp->sess->origin)->proxy; |
3786 | 0 | if (!px) |
3787 | 0 | return 0; |
3788 | | |
3789 | 0 | smp->flags = SMP_F_VOL_TXN; |
3790 | 0 | smp->data.type = SMP_T_SINT; |
3791 | 0 | smp->data.u.sint = TICKS_TO_MS(px->timeout.connect); |
3792 | 0 | return 1; |
3793 | 0 | } |
3794 | | |
3795 | | static int |
3796 | | smp_fetch_be_queue_timeout(const struct arg *args, struct sample *smp, const char *km, void *private) |
3797 | 0 | { |
3798 | 0 | struct proxy *px = NULL; |
3799 | |
|
3800 | 0 | if (smp->strm) |
3801 | 0 | px = smp->strm->be; |
3802 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3803 | 0 | px = __objt_check(smp->sess->origin)->proxy; |
3804 | 0 | if (!px) |
3805 | 0 | return 0; |
3806 | | |
3807 | 0 | smp->flags = SMP_F_VOL_TXN; |
3808 | 0 | smp->data.type = SMP_T_SINT; |
3809 | 0 | smp->data.u.sint = TICKS_TO_MS(px->timeout.queue); |
3810 | 0 | return 1; |
3811 | 0 | } |
3812 | | |
3813 | | static int |
3814 | | smp_fetch_be_server_timeout(const struct arg *args, struct sample *smp, const char *km, void *private) |
3815 | 0 | { |
3816 | 0 | struct proxy *px = NULL; |
3817 | |
|
3818 | 0 | if (smp->strm) |
3819 | 0 | px = smp->strm->be; |
3820 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3821 | 0 | px = __objt_check(smp->sess->origin)->proxy; |
3822 | 0 | if (!px) |
3823 | 0 | return 0; |
3824 | | |
3825 | 0 | smp->flags = SMP_F_VOL_TXN; |
3826 | 0 | smp->data.type = SMP_T_SINT; |
3827 | 0 | smp->data.u.sint = TICKS_TO_MS(px->timeout.server); |
3828 | 0 | return 1; |
3829 | 0 | } |
3830 | | |
3831 | | static int |
3832 | | smp_fetch_be_tarpit_timeout(const struct arg *args, struct sample *smp, const char *km, void *private) |
3833 | 0 | { |
3834 | 0 | struct proxy *px = NULL; |
3835 | |
|
3836 | 0 | if (smp->strm) |
3837 | 0 | px = smp->strm->be; |
3838 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3839 | 0 | px = __objt_check(smp->sess->origin)->proxy; |
3840 | 0 | if (!px) |
3841 | 0 | return 0; |
3842 | | |
3843 | 0 | smp->flags = SMP_F_VOL_TXN; |
3844 | 0 | smp->data.type = SMP_T_SINT; |
3845 | 0 | smp->data.u.sint = TICKS_TO_MS(px->timeout.tarpit); |
3846 | 0 | return 1; |
3847 | 0 | } |
3848 | | |
3849 | | static int |
3850 | | smp_fetch_be_tunnel_timeout(const struct arg *args, struct sample *smp, const char *km, void *private) |
3851 | 0 | { |
3852 | 0 | struct proxy *px = NULL; |
3853 | |
|
3854 | 0 | if (smp->strm) |
3855 | 0 | px = smp->strm->be; |
3856 | 0 | else if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) |
3857 | 0 | px = __objt_check(smp->sess->origin)->proxy; |
3858 | 0 | if (!px) |
3859 | 0 | return 0; |
3860 | | |
3861 | 0 | smp->flags = SMP_F_VOL_TXN; |
3862 | 0 | smp->data.type = SMP_T_SINT; |
3863 | 0 | smp->data.u.sint = TICKS_TO_MS(px->timeout.tunnel); |
3864 | 0 | return 1; |
3865 | 0 | } |
3866 | | |
3867 | | static int sample_conv_nbsrv(const struct arg *args, struct sample *smp, void *private) |
3868 | 0 | { |
3869 | |
|
3870 | 0 | struct proxy *px; |
3871 | |
|
3872 | 0 | if (!smp_make_safe(smp)) |
3873 | 0 | return 0; |
3874 | | |
3875 | 0 | px = proxy_find_by_name(smp->data.u.str.area, PR_CAP_BE, 0); |
3876 | 0 | if (!px) |
3877 | 0 | return 0; |
3878 | | |
3879 | 0 | smp->data.type = SMP_T_SINT; |
3880 | 0 | smp->data.u.sint = be_usable_srv(px); |
3881 | |
|
3882 | 0 | return 1; |
3883 | 0 | } |
3884 | | |
3885 | | static struct server *sample_conv_srv(struct sample *smp) |
3886 | 0 | { |
3887 | 0 | struct proxy *px; |
3888 | 0 | char *bksep; |
3889 | |
|
3890 | 0 | if (!smp_make_safe(smp)) |
3891 | 0 | return 0; |
3892 | | |
3893 | 0 | bksep = strchr(smp->data.u.str.area, '/'); |
3894 | |
|
3895 | 0 | if (bksep) { |
3896 | 0 | *bksep = '\0'; |
3897 | 0 | px = proxy_find_by_name(smp->data.u.str.area, PR_CAP_BE, 0); |
3898 | 0 | if (!px) |
3899 | 0 | return NULL; |
3900 | 0 | smp->data.u.str.area = bksep + 1; |
3901 | 0 | } else { |
3902 | 0 | if (!(smp->px->cap & PR_CAP_BE)) |
3903 | 0 | return NULL; |
3904 | 0 | px = smp->px; |
3905 | 0 | } |
3906 | | |
3907 | 0 | return server_find(px, smp->data.u.str.area); |
3908 | 0 | } |
3909 | | |
3910 | | static int |
3911 | | sample_conv_srv_is_up(const struct arg *args, struct sample *smp, void *private) |
3912 | 0 | { |
3913 | 0 | struct server *srv = sample_conv_srv(smp); |
3914 | |
|
3915 | 0 | if (!srv) |
3916 | 0 | return 0; |
3917 | | |
3918 | 0 | smp->data.type = SMP_T_BOOL; |
3919 | 0 | if (!(srv->cur_admin & SRV_ADMF_MAINT) && |
3920 | 0 | (!(srv->check.state & CHK_ST_CONFIGURED) || (srv->cur_state != SRV_ST_STOPPED))) |
3921 | 0 | smp->data.u.sint = 1; |
3922 | 0 | else |
3923 | 0 | smp->data.u.sint = 0; |
3924 | 0 | return 1; |
3925 | 0 | } |
3926 | | |
3927 | | static int |
3928 | | sample_conv_srv_queue(const struct arg *args, struct sample *smp, void *private) |
3929 | 0 | { |
3930 | 0 | struct server *srv = sample_conv_srv(smp); |
3931 | |
|
3932 | 0 | if (!srv) |
3933 | 0 | return 0; |
3934 | | |
3935 | 0 | smp->data.type = SMP_T_SINT; |
3936 | 0 | smp->data.u.sint = srv->queueslength; |
3937 | 0 | return 1; |
3938 | 0 | } |
3939 | | |
3940 | | /* Note: must not be declared <const> as its list will be overwritten. |
3941 | | * Please take care of keeping this list alphabetically sorted. |
3942 | | */ |
3943 | | static struct sample_fetch_kw_list smp_kws = {ILH, { |
3944 | | { "avg_queue", smp_fetch_avg_queue_size, ARG1(1,BE), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3945 | | { "be_conn", smp_fetch_be_conn, ARG1(1,BE), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3946 | | { "be_conn_free", smp_fetch_be_conn_free, ARG1(1,BE), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3947 | | { "be_id", smp_fetch_be_id, 0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, |
3948 | | { "be_name", smp_fetch_be_name, 0, NULL, SMP_T_STR, SMP_USE_BKEND, }, |
3949 | | { "be_connect_timeout",smp_fetch_be_connect_timeout,0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, |
3950 | | { "be_max_retries", smp_fetch_be_max_retries, 0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, |
3951 | | { "be_queue_timeout", smp_fetch_be_queue_timeout, 0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, |
3952 | | { "be_server_timeout", smp_fetch_be_server_timeout, 0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, |
3953 | | { "be_sess_rate", smp_fetch_be_sess_rate, ARG1(1,BE), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3954 | | { "be_tarpit_timeout", smp_fetch_be_tarpit_timeout, 0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, |
3955 | | { "be_tunnel_timeout", smp_fetch_be_tunnel_timeout, 0, NULL, SMP_T_SINT, SMP_USE_BKEND, }, |
3956 | | { "connslots", smp_fetch_connslots, ARG1(1,BE), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3957 | | { "nbsrv", smp_fetch_nbsrv, ARG1(1,BE), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3958 | | { "queue", smp_fetch_queue_size, ARG1(1,BE), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3959 | | { "srv_conn", smp_fetch_srv_conn, ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3960 | | { "srv_conn_free", smp_fetch_srv_conn_free, ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3961 | | { "srv_id", smp_fetch_srv_id, 0, NULL, SMP_T_SINT, SMP_USE_SERVR, }, |
3962 | | { "srv_is_up", smp_fetch_srv_is_up, ARG1(1,SRV), NULL, SMP_T_BOOL, SMP_USE_INTRN, }, |
3963 | | { "srv_name", smp_fetch_srv_name, 0, NULL, SMP_T_STR, SMP_USE_SERVR, }, |
3964 | | { "srv_queue", smp_fetch_srv_queue, ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3965 | | { "srv_sess_rate", smp_fetch_srv_sess_rate, ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3966 | | { "srv_weight", smp_fetch_srv_weight, ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3967 | | { "srv_iweight", smp_fetch_srv_iweight, ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3968 | | { "srv_uweight", smp_fetch_srv_uweight, ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, }, |
3969 | | { /* END */ }, |
3970 | | }}; |
3971 | | |
3972 | | INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws); |
3973 | | |
3974 | | /* Note: must not be declared <const> as its list will be overwritten */ |
3975 | | static struct sample_conv_kw_list sample_conv_kws = {ILH, { |
3976 | | { "nbsrv", sample_conv_nbsrv, 0, NULL, SMP_T_STR, SMP_T_SINT }, |
3977 | | { "srv_is_up", sample_conv_srv_is_up, 0, NULL, SMP_T_STR, SMP_T_BOOL }, |
3978 | | { "srv_queue", sample_conv_srv_queue, 0, NULL, SMP_T_STR, SMP_T_SINT }, |
3979 | | { /* END */ }, |
3980 | | }}; |
3981 | | |
3982 | | INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws); |
3983 | | |
3984 | | /* Note: must not be declared <const> as its list will be overwritten. |
3985 | | * Please take care of keeping this list alphabetically sorted. |
3986 | | */ |
3987 | | static struct acl_kw_list acl_kws = {ILH, { |
3988 | | { /* END */ }, |
3989 | | }}; |
3990 | | |
3991 | | INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws); |
3992 | | |
3993 | | /* |
3994 | | * Local variables: |
3995 | | * c-indent-level: 8 |
3996 | | * c-basic-offset: 8 |
3997 | | * End: |
3998 | | */ |