blob: 38f81d284f0bd80e8657e654c4505b7c1da71212 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Backend variables and functions.
3 *
Willy Tarreaue8c66af2008-01-13 18:40:14 +01004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
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 <fcntl.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <syslog.h>
Willy Tarreauf19cf372006-11-14 15:40:51 +010018#include <string.h>
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +020019#include <ctype.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020020
Willy Tarreau2dd0d472006-06-29 17:53:05 +020021#include <common/compat.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020022#include <common/config.h>
Willy Tarreaub625a082007-11-26 01:15:43 +010023#include <common/eb32tree.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020024#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020025
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +010026#include <types/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020027#include <types/buffers.h>
28#include <types/global.h>
29#include <types/polling.h>
30#include <types/proxy.h>
31#include <types/server.h>
32#include <types/session.h>
33
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +010034#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035#include <proto/backend.h>
Willy Tarreau14c8aac2007-05-08 19:46:30 +020036#include <proto/client.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020037#include <proto/fd.h>
Willy Tarreau80587432006-12-24 17:47:20 +010038#include <proto/httperr.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020039#include <proto/log.h>
40#include <proto/proto_http.h>
Willy Tarreaue8c66af2008-01-13 18:40:14 +010041#include <proto/proto_tcp.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020042#include <proto/queue.h>
43#include <proto/stream_sock.h>
44#include <proto/task.h>
45
Willy Tarreau6d1a9882007-01-07 02:03:04 +010046#ifdef CONFIG_HAP_TCPSPLICE
47#include <libtcpsplice.h>
48#endif
49
Willy Tarreaub625a082007-11-26 01:15:43 +010050static inline void fwrr_remove_from_tree(struct server *s);
51static inline void fwrr_queue_by_weight(struct eb_root *root, struct server *s);
52static inline void fwrr_dequeue_srv(struct server *s);
53static void fwrr_get_srv(struct server *s);
54static void fwrr_queue_srv(struct server *s);
55
56/* This function returns non-zero if a server with the given weight and state
57 * is usable for LB, otherwise zero.
58 */
59static inline int srv_is_usable(int state, int weight)
60{
61 if (!weight)
62 return 0;
Willy Tarreau48494c02007-11-30 10:41:39 +010063 if (state & SRV_GOINGDOWN)
64 return 0;
Willy Tarreaub625a082007-11-26 01:15:43 +010065 if (!(state & SRV_RUNNING))
66 return 0;
67 return 1;
68}
69
Willy Tarreaubaaee002006-06-26 02:48:02 +020070/*
71 * This function recounts the number of usable active and backup servers for
72 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
Willy Tarreaub625a082007-11-26 01:15:43 +010073 * This function also recomputes the total active and backup weights. However,
Willy Tarreauf4cca452008-03-08 21:42:54 +010074 * it does not update tot_weight nor tot_used. Use update_backend_weight() for
Willy Tarreaub625a082007-11-26 01:15:43 +010075 * this.
Willy Tarreaubaaee002006-06-26 02:48:02 +020076 */
Willy Tarreaub625a082007-11-26 01:15:43 +010077static void recount_servers(struct proxy *px)
Willy Tarreaubaaee002006-06-26 02:48:02 +020078{
79 struct server *srv;
80
Willy Tarreau20697042007-11-15 23:26:18 +010081 px->srv_act = px->srv_bck = 0;
82 px->lbprm.tot_wact = px->lbprm.tot_wbck = 0;
Willy Tarreaub625a082007-11-26 01:15:43 +010083 px->lbprm.fbck = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +020084 for (srv = px->srv; srv != NULL; srv = srv->next) {
Willy Tarreaub625a082007-11-26 01:15:43 +010085 if (!srv_is_usable(srv->state, srv->eweight))
86 continue;
87
88 if (srv->state & SRV_BACKUP) {
89 if (!px->srv_bck &&
Willy Tarreauf4cca452008-03-08 21:42:54 +010090 !(px->options & PR_O_USE_ALL_BK))
Willy Tarreaub625a082007-11-26 01:15:43 +010091 px->lbprm.fbck = srv;
92 px->srv_bck++;
93 px->lbprm.tot_wbck += srv->eweight;
94 } else {
95 px->srv_act++;
96 px->lbprm.tot_wact += srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +020097 }
98 }
Willy Tarreaub625a082007-11-26 01:15:43 +010099}
Willy Tarreau20697042007-11-15 23:26:18 +0100100
Willy Tarreaub625a082007-11-26 01:15:43 +0100101/* This function simply updates the backend's tot_weight and tot_used values
102 * after servers weights have been updated. It is designed to be used after
103 * recount_servers() or equivalent.
104 */
105static void update_backend_weight(struct proxy *px)
106{
Willy Tarreau20697042007-11-15 23:26:18 +0100107 if (px->srv_act) {
108 px->lbprm.tot_weight = px->lbprm.tot_wact;
109 px->lbprm.tot_used = px->srv_act;
110 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100111 else if (px->lbprm.fbck) {
112 /* use only the first backup server */
113 px->lbprm.tot_weight = px->lbprm.fbck->eweight;
114 px->lbprm.tot_used = 1;
Willy Tarreau20697042007-11-15 23:26:18 +0100115 }
116 else {
Willy Tarreaub625a082007-11-26 01:15:43 +0100117 px->lbprm.tot_weight = px->lbprm.tot_wbck;
118 px->lbprm.tot_used = px->srv_bck;
Willy Tarreau20697042007-11-15 23:26:18 +0100119 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100120}
121
122/* this function updates the map according to server <srv>'s new state */
123static void map_set_server_status_down(struct server *srv)
124{
125 struct proxy *p = srv->proxy;
126
127 if (srv->state == srv->prev_state &&
128 srv->eweight == srv->prev_eweight)
129 return;
130
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100131 if (srv_is_usable(srv->state, srv->eweight))
132 goto out_update_state;
133
Willy Tarreaub625a082007-11-26 01:15:43 +0100134 /* FIXME: could be optimized since we know what changed */
135 recount_servers(p);
136 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100137 p->lbprm.map.state |= PR_MAP_RECALC;
138 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100139 srv->prev_state = srv->state;
140 srv->prev_eweight = srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200141}
142
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100143/* This function updates the map according to server <srv>'s new state */
Willy Tarreaub625a082007-11-26 01:15:43 +0100144static void map_set_server_status_up(struct server *srv)
145{
146 struct proxy *p = srv->proxy;
147
148 if (srv->state == srv->prev_state &&
149 srv->eweight == srv->prev_eweight)
150 return;
151
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100152 if (!srv_is_usable(srv->state, srv->eweight))
153 goto out_update_state;
154
Willy Tarreaub625a082007-11-26 01:15:43 +0100155 /* FIXME: could be optimized since we know what changed */
156 recount_servers(p);
157 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100158 p->lbprm.map.state |= PR_MAP_RECALC;
159 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100160 srv->prev_state = srv->state;
161 srv->prev_eweight = srv->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100162}
163
Willy Tarreau20697042007-11-15 23:26:18 +0100164/* This function recomputes the server map for proxy px. It relies on
165 * px->lbprm.tot_wact, tot_wbck, tot_used, tot_weight, so it must be
166 * called after recount_servers(). It also expects px->lbprm.map.srv
167 * to be allocated with the largest size needed. It updates tot_weight.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200168 */
169void recalc_server_map(struct proxy *px)
170{
171 int o, tot, flag;
172 struct server *cur, *best;
173
Willy Tarreau20697042007-11-15 23:26:18 +0100174 switch (px->lbprm.tot_used) {
175 case 0: /* no server */
176 px->lbprm.map.state &= ~PR_MAP_RECALC;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200177 return;
Willy Tarreau20697042007-11-15 23:26:18 +0100178 case 1: /* only one server, just fill first entry */
179 tot = 1;
180 break;
181 default:
182 tot = px->lbprm.tot_weight;
183 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200184 }
185
Willy Tarreau20697042007-11-15 23:26:18 +0100186 /* here we *know* that we have some servers */
187 if (px->srv_act)
188 flag = SRV_RUNNING;
189 else
190 flag = SRV_RUNNING | SRV_BACKUP;
191
Willy Tarreaubaaee002006-06-26 02:48:02 +0200192 /* this algorithm gives priority to the first server, which means that
193 * it will respect the declaration order for equivalent weights, and
194 * that whatever the weights, the first server called will always be
Willy Tarreau20697042007-11-15 23:26:18 +0100195 * the first declared. This is an important asumption for the backup
Willy Tarreaubaaee002006-06-26 02:48:02 +0200196 * case, where we want the first server only.
197 */
198 for (cur = px->srv; cur; cur = cur->next)
199 cur->wscore = 0;
200
201 for (o = 0; o < tot; o++) {
202 int max = 0;
203 best = NULL;
204 for (cur = px->srv; cur; cur = cur->next) {
Willy Tarreau48494c02007-11-30 10:41:39 +0100205 if (flag == (cur->state &
206 (SRV_RUNNING | SRV_GOINGDOWN | SRV_BACKUP))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200207 int v;
208
209 /* If we are forced to return only one server, we don't want to
210 * go further, because we would return the wrong one due to
211 * divide overflow.
212 */
213 if (tot == 1) {
214 best = cur;
Willy Tarreau20697042007-11-15 23:26:18 +0100215 /* note that best->wscore will be wrong but we don't care */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200216 break;
217 }
218
Willy Tarreau417fae02007-03-25 21:16:40 +0200219 cur->wscore += cur->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200220 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
221 if (best == NULL || v > max) {
222 max = v;
223 best = cur;
224 }
225 }
226 }
Willy Tarreau20697042007-11-15 23:26:18 +0100227 px->lbprm.map.srv[o] = best;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200228 best->wscore -= tot;
229 }
Willy Tarreau20697042007-11-15 23:26:18 +0100230 px->lbprm.map.state &= ~PR_MAP_RECALC;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200231}
232
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100233/* This function is responsible of building the server MAP for map-based LB
234 * algorithms, allocating the map, and setting p->lbprm.wmult to the GCD of the
235 * weights if applicable. It should be called only once per proxy, at config
236 * time.
237 */
238void init_server_map(struct proxy *p)
239{
240 struct server *srv;
241 int pgcd;
242 int act, bck;
243
Willy Tarreaub625a082007-11-26 01:15:43 +0100244 p->lbprm.set_server_status_up = map_set_server_status_up;
245 p->lbprm.set_server_status_down = map_set_server_status_down;
246 p->lbprm.update_server_eweight = NULL;
247
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100248 if (!p->srv)
249 return;
250
251 /* We will factor the weights to reduce the table,
252 * using Euclide's largest common divisor algorithm
253 */
254 pgcd = p->srv->uweight;
255 for (srv = p->srv->next; srv && pgcd > 1; srv = srv->next) {
256 int w = srv->uweight;
257 while (w) {
258 int t = pgcd % w;
259 pgcd = w;
260 w = t;
261 }
262 }
263
264 /* It is sometimes useful to know what factor to apply
265 * to the backend's effective weight to know its real
266 * weight.
267 */
268 p->lbprm.wmult = pgcd;
269
270 act = bck = 0;
271 for (srv = p->srv; srv; srv = srv->next) {
272 srv->eweight = srv->uweight / pgcd;
Willy Tarreaub625a082007-11-26 01:15:43 +0100273 srv->prev_eweight = srv->eweight;
274 srv->prev_state = srv->state;
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100275 if (srv->state & SRV_BACKUP)
276 bck += srv->eweight;
277 else
278 act += srv->eweight;
279 }
280
281 /* this is the largest map we will ever need for this servers list */
282 if (act < bck)
283 act = bck;
284
285 p->lbprm.map.srv = (struct server **)calloc(act, sizeof(struct server *));
286 /* recounts servers and their weights */
287 p->lbprm.map.state = PR_MAP_RECALC;
288 recount_servers(p);
Willy Tarreaub625a082007-11-26 01:15:43 +0100289 update_backend_weight(p);
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100290 recalc_server_map(p);
291}
292
Willy Tarreaub625a082007-11-26 01:15:43 +0100293/* This function updates the server trees according to server <srv>'s new
294 * state. It should be called when server <srv>'s status changes to down.
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100295 * It is not important whether the server was already down or not. It is not
296 * important either that the new state is completely down (the caller may not
297 * know all the variables of a server's state).
Willy Tarreaub625a082007-11-26 01:15:43 +0100298 */
299static void fwrr_set_server_status_down(struct server *srv)
300{
301 struct proxy *p = srv->proxy;
302 struct fwrr_group *grp;
303
304 if (srv->state == srv->prev_state &&
305 srv->eweight == srv->prev_eweight)
306 return;
307
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100308 if (srv_is_usable(srv->state, srv->eweight))
309 goto out_update_state;
310
Willy Tarreaub625a082007-11-26 01:15:43 +0100311 if (!srv_is_usable(srv->prev_state, srv->prev_eweight))
312 /* server was already down */
313 goto out_update_backend;
314
315 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
316 grp->next_weight -= srv->prev_eweight;
317
318 if (srv->state & SRV_BACKUP) {
319 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
320 p->srv_bck--;
321
322 if (srv == p->lbprm.fbck) {
323 /* we lost the first backup server in a single-backup
324 * configuration, we must search another one.
325 */
326 struct server *srv2 = p->lbprm.fbck;
327 do {
328 srv2 = srv2->next;
329 } while (srv2 &&
330 !((srv2->state & SRV_BACKUP) &&
331 srv_is_usable(srv2->state, srv2->eweight)));
332 p->lbprm.fbck = srv2;
333 }
334 } else {
335 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
336 p->srv_act--;
337 }
338
339 fwrr_dequeue_srv(srv);
340 fwrr_remove_from_tree(srv);
341
342out_update_backend:
343 /* check/update tot_used, tot_weight */
344 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100345 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100346 srv->prev_state = srv->state;
347 srv->prev_eweight = srv->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100348}
349
350/* This function updates the server trees according to server <srv>'s new
351 * state. It should be called when server <srv>'s status changes to up.
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100352 * It is not important whether the server was already down or not. It is not
353 * important either that the new state is completely UP (the caller may not
354 * know all the variables of a server's state). This function will not change
Willy Tarreaub625a082007-11-26 01:15:43 +0100355 * the weight of a server which was already up.
356 */
357static void fwrr_set_server_status_up(struct server *srv)
358{
359 struct proxy *p = srv->proxy;
360 struct fwrr_group *grp;
361
362 if (srv->state == srv->prev_state &&
363 srv->eweight == srv->prev_eweight)
364 return;
365
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100366 if (!srv_is_usable(srv->state, srv->eweight))
367 goto out_update_state;
368
Willy Tarreaub625a082007-11-26 01:15:43 +0100369 if (srv_is_usable(srv->prev_state, srv->prev_eweight))
370 /* server was already up */
371 goto out_update_backend;
372
373 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
374 grp->next_weight += srv->eweight;
375
376 if (srv->state & SRV_BACKUP) {
377 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
378 p->srv_bck++;
379
Willy Tarreauf4cca452008-03-08 21:42:54 +0100380 if (!(p->options & PR_O_USE_ALL_BK)) {
381 if (!p->lbprm.fbck) {
382 /* there was no backup server anymore */
Willy Tarreaub625a082007-11-26 01:15:43 +0100383 p->lbprm.fbck = srv;
Willy Tarreauf4cca452008-03-08 21:42:54 +0100384 } else {
385 /* we may have restored a backup server prior to fbck,
386 * in which case it should replace it.
387 */
388 struct server *srv2 = srv;
389 do {
390 srv2 = srv2->next;
391 } while (srv2 && (srv2 != p->lbprm.fbck));
392 if (srv2)
393 p->lbprm.fbck = srv;
394 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100395 }
396 } else {
397 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
398 p->srv_act++;
399 }
400
401 /* note that eweight cannot be 0 here */
402 fwrr_get_srv(srv);
403 srv->npos = grp->curr_pos + (grp->next_weight + grp->curr_weight - grp->curr_pos) / srv->eweight;
404 fwrr_queue_srv(srv);
405
406out_update_backend:
407 /* check/update tot_used, tot_weight */
408 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100409 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100410 srv->prev_state = srv->state;
411 srv->prev_eweight = srv->eweight;
412}
413
414/* This function must be called after an update to server <srv>'s effective
415 * weight. It may be called after a state change too.
416 */
417static void fwrr_update_server_weight(struct server *srv)
418{
419 int old_state, new_state;
420 struct proxy *p = srv->proxy;
421 struct fwrr_group *grp;
422
423 if (srv->state == srv->prev_state &&
424 srv->eweight == srv->prev_eweight)
425 return;
426
427 /* If changing the server's weight changes its state, we simply apply
428 * the procedures we already have for status change. If the state
429 * remains down, the server is not in any tree, so it's as easy as
430 * updating its values. If the state remains up with different weights,
431 * there are some computations to perform to find a new place and
432 * possibly a new tree for this server.
433 */
434
435 old_state = srv_is_usable(srv->prev_state, srv->prev_eweight);
436 new_state = srv_is_usable(srv->state, srv->eweight);
437
438 if (!old_state && !new_state) {
439 srv->prev_state = srv->state;
440 srv->prev_eweight = srv->eweight;
441 return;
442 }
443 else if (!old_state && new_state) {
444 fwrr_set_server_status_up(srv);
445 return;
446 }
447 else if (old_state && !new_state) {
448 fwrr_set_server_status_down(srv);
449 return;
450 }
451
452 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
453 grp->next_weight = grp->next_weight - srv->prev_eweight + srv->eweight;
454
455 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
456 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
457
458 if (srv->lb_tree == grp->init) {
459 fwrr_dequeue_srv(srv);
460 fwrr_queue_by_weight(grp->init, srv);
461 }
462 else if (!srv->lb_tree) {
463 /* FIXME: server was down. This is not possible right now but
464 * may be needed soon for slowstart or graceful shutdown.
465 */
466 fwrr_dequeue_srv(srv);
467 fwrr_get_srv(srv);
468 srv->npos = grp->curr_pos + (grp->next_weight + grp->curr_weight - grp->curr_pos) / srv->eweight;
469 fwrr_queue_srv(srv);
470 } else {
471 /* The server is either active or in the next queue. If it's
472 * still in the active queue and it has not consumed all of its
473 * places, let's adjust its next position.
474 */
475 fwrr_get_srv(srv);
476
477 if (srv->eweight > 0) {
478 int prev_next = srv->npos;
479 int step = grp->next_weight / srv->eweight;
480
481 srv->npos = srv->lpos + step;
482 srv->rweight = 0;
483
484 if (srv->npos > prev_next)
485 srv->npos = prev_next;
486 if (srv->npos < grp->curr_pos + 2)
487 srv->npos = grp->curr_pos + step;
488 } else {
489 /* push it into the next tree */
490 srv->npos = grp->curr_pos + grp->curr_weight;
491 }
492
493 fwrr_dequeue_srv(srv);
494 fwrr_queue_srv(srv);
495 }
496
497 update_backend_weight(p);
498 srv->prev_state = srv->state;
499 srv->prev_eweight = srv->eweight;
500}
501
502/* Remove a server from a tree. It must have previously been dequeued. This
503 * function is meant to be called when a server is going down or has its
504 * weight disabled.
505 */
506static inline void fwrr_remove_from_tree(struct server *s)
507{
508 s->lb_tree = NULL;
509}
510
511/* Queue a server in the weight tree <root>, assuming the weight is >0.
512 * We want to sort them by inverted weights, because we need to place
513 * heavy servers first in order to get a smooth distribution.
514 */
515static inline void fwrr_queue_by_weight(struct eb_root *root, struct server *s)
516{
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100517 s->lb_node.key = SRV_EWGHT_MAX - s->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100518 eb32_insert(root, &s->lb_node);
519 s->lb_tree = root;
520}
521
522/* This function is responsible for building the weight trees in case of fast
523 * weighted round-robin. It also sets p->lbprm.wdiv to the eweight to uweight
524 * ratio. Both active and backup groups are initialized.
525 */
526void fwrr_init_server_groups(struct proxy *p)
527{
528 struct server *srv;
529 struct eb_root init_head = EB_ROOT;
530
531 p->lbprm.set_server_status_up = fwrr_set_server_status_up;
532 p->lbprm.set_server_status_down = fwrr_set_server_status_down;
533 p->lbprm.update_server_eweight = fwrr_update_server_weight;
534
535 p->lbprm.wdiv = BE_WEIGHT_SCALE;
536 for (srv = p->srv; srv; srv = srv->next) {
537 srv->prev_eweight = srv->eweight = srv->uweight * BE_WEIGHT_SCALE;
538 srv->prev_state = srv->state;
539 }
540
541 recount_servers(p);
542 update_backend_weight(p);
543
544 /* prepare the active servers group */
545 p->lbprm.fwrr.act.curr_pos = p->lbprm.fwrr.act.curr_weight =
546 p->lbprm.fwrr.act.next_weight = p->lbprm.tot_wact;
547 p->lbprm.fwrr.act.curr = p->lbprm.fwrr.act.t0 =
548 p->lbprm.fwrr.act.t1 = init_head;
549 p->lbprm.fwrr.act.init = &p->lbprm.fwrr.act.t0;
550 p->lbprm.fwrr.act.next = &p->lbprm.fwrr.act.t1;
551
552 /* prepare the backup servers group */
553 p->lbprm.fwrr.bck.curr_pos = p->lbprm.fwrr.bck.curr_weight =
554 p->lbprm.fwrr.bck.next_weight = p->lbprm.tot_wbck;
555 p->lbprm.fwrr.bck.curr = p->lbprm.fwrr.bck.t0 =
556 p->lbprm.fwrr.bck.t1 = init_head;
557 p->lbprm.fwrr.bck.init = &p->lbprm.fwrr.bck.t0;
558 p->lbprm.fwrr.bck.next = &p->lbprm.fwrr.bck.t1;
559
560 /* queue active and backup servers in two distinct groups */
561 for (srv = p->srv; srv; srv = srv->next) {
562 if (!srv_is_usable(srv->state, srv->eweight))
563 continue;
564 fwrr_queue_by_weight((srv->state & SRV_BACKUP) ?
565 p->lbprm.fwrr.bck.init :
566 p->lbprm.fwrr.act.init,
567 srv);
568 }
569}
570
571/* simply removes a server from a weight tree */
572static inline void fwrr_dequeue_srv(struct server *s)
573{
574 eb32_delete(&s->lb_node);
575}
576
577/* queues a server into the appropriate group and tree depending on its
578 * backup status, and ->npos. If the server is disabled, simply assign
579 * it to the NULL tree.
580 */
581static void fwrr_queue_srv(struct server *s)
582{
583 struct proxy *p = s->proxy;
584 struct fwrr_group *grp;
585
586 grp = (s->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
587
588 /* Delay everything which does not fit into the window and everything
589 * which does not fit into the theorical new window.
590 */
591 if (!srv_is_usable(s->state, s->eweight)) {
592 fwrr_remove_from_tree(s);
593 }
594 else if (s->eweight <= 0 ||
595 s->npos >= 2 * grp->curr_weight ||
596 s->npos >= grp->curr_weight + grp->next_weight) {
597 /* put into next tree, and readjust npos in case we could
598 * finally take this back to current. */
599 s->npos -= grp->curr_weight;
600 fwrr_queue_by_weight(grp->next, s);
601 }
602 else {
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100603 /* The sorting key is stored in units of s->npos * user_weight
604 * in order to avoid overflows. As stated in backend.h, the
605 * lower the scale, the rougher the weights modulation, and the
606 * higher the scale, the lower the number of servers without
607 * overflow. With this formula, the result is always positive,
608 * so we can use eb3é_insert().
Willy Tarreaub625a082007-11-26 01:15:43 +0100609 */
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100610 s->lb_node.key = SRV_UWGHT_RANGE * s->npos +
611 (unsigned)(SRV_EWGHT_MAX + s->rweight - s->eweight) / BE_WEIGHT_SCALE;
612
613 eb32_insert(&grp->curr, &s->lb_node);
Willy Tarreaub625a082007-11-26 01:15:43 +0100614 s->lb_tree = &grp->curr;
615 }
616}
617
618/* prepares a server when extracting it from the "init" tree */
619static inline void fwrr_get_srv_init(struct server *s)
620{
621 s->npos = s->rweight = 0;
622}
623
624/* prepares a server when extracting it from the "next" tree */
625static inline void fwrr_get_srv_next(struct server *s)
626{
627 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
628 &s->proxy->lbprm.fwrr.bck :
629 &s->proxy->lbprm.fwrr.act;
630
631 s->npos += grp->curr_weight;
632}
633
634/* prepares a server when it was marked down */
635static inline void fwrr_get_srv_down(struct server *s)
636{
637 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
638 &s->proxy->lbprm.fwrr.bck :
639 &s->proxy->lbprm.fwrr.act;
640
641 s->npos = grp->curr_pos;
642}
643
644/* prepares a server when extracting it from its tree */
645static void fwrr_get_srv(struct server *s)
646{
647 struct proxy *p = s->proxy;
648 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
649 &p->lbprm.fwrr.bck :
650 &p->lbprm.fwrr.act;
651
652 if (s->lb_tree == grp->init) {
653 fwrr_get_srv_init(s);
654 }
655 else if (s->lb_tree == grp->next) {
656 fwrr_get_srv_next(s);
657 }
658 else if (s->lb_tree == NULL) {
659 fwrr_get_srv_down(s);
660 }
661}
662
663/* switches trees "init" and "next" for FWRR group <grp>. "init" should be empty
664 * when this happens, and "next" filled with servers sorted by weights.
665 */
666static inline void fwrr_switch_trees(struct fwrr_group *grp)
667{
668 struct eb_root *swap;
669 swap = grp->init;
670 grp->init = grp->next;
671 grp->next = swap;
672 grp->curr_weight = grp->next_weight;
673 grp->curr_pos = grp->curr_weight;
674}
675
676/* return next server from the current tree in FWRR group <grp>, or a server
677 * from the "init" tree if appropriate. If both trees are empty, return NULL.
678 */
679static struct server *fwrr_get_server_from_group(struct fwrr_group *grp)
680{
681 struct eb32_node *node;
682 struct server *s;
683
684 node = eb32_first(&grp->curr);
685 s = eb32_entry(node, struct server, lb_node);
686
687 if (!node || s->npos > grp->curr_pos) {
688 /* either we have no server left, or we have a hole */
689 struct eb32_node *node2;
690 node2 = eb32_first(grp->init);
691 if (node2) {
692 node = node2;
693 s = eb32_entry(node, struct server, lb_node);
694 fwrr_get_srv_init(s);
695 if (s->eweight == 0) /* FIXME: is it possible at all ? */
696 node = NULL;
697 }
698 }
699 if (node)
700 return s;
701 else
702 return NULL;
703}
704
705/* Computes next position of server <s> in the group. It is mandatory for <s>
706 * to have a non-zero, positive eweight.
707*/
708static inline void fwrr_update_position(struct fwrr_group *grp, struct server *s)
709{
710 if (!s->npos) {
711 /* first time ever for this server */
712 s->lpos = grp->curr_pos;
713 s->npos = grp->curr_pos + grp->next_weight / s->eweight;
714 s->rweight += grp->next_weight % s->eweight;
715
716 if (s->rweight >= s->eweight) {
717 s->rweight -= s->eweight;
718 s->npos++;
719 }
720 } else {
721 s->lpos = s->npos;
722 s->npos += grp->next_weight / s->eweight;
723 s->rweight += grp->next_weight % s->eweight;
724
725 if (s->rweight >= s->eweight) {
726 s->rweight -= s->eweight;
727 s->npos++;
728 }
729 }
730}
731
732/* Return next server from the current tree in backend <p>, or a server from
733 * the init tree if appropriate. If both trees are empty, return NULL.
734 * Saturated servers are skipped and requeued.
735 */
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100736static struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid)
Willy Tarreaub625a082007-11-26 01:15:43 +0100737{
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100738 struct server *srv, *full, *avoided;
Willy Tarreaub625a082007-11-26 01:15:43 +0100739 struct fwrr_group *grp;
Willy Tarreaub625a082007-11-26 01:15:43 +0100740 int switched;
741
742 if (p->srv_act)
743 grp = &p->lbprm.fwrr.act;
744 else if (p->lbprm.fbck)
745 return p->lbprm.fbck;
746 else if (p->srv_bck)
747 grp = &p->lbprm.fwrr.bck;
748 else
749 return NULL;
750
751 switched = 0;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100752 avoided = NULL;
Willy Tarreaub625a082007-11-26 01:15:43 +0100753 full = NULL; /* NULL-terminated list of saturated servers */
754 while (1) {
755 /* if we see an empty group, let's first try to collect weights
756 * which might have recently changed.
757 */
758 if (!grp->curr_weight)
759 grp->curr_pos = grp->curr_weight = grp->next_weight;
760
761 /* get first server from the "current" tree. When the end of
762 * the tree is reached, we may have to switch, but only once.
763 */
764 while (1) {
765 srv = fwrr_get_server_from_group(grp);
766 if (srv)
767 break;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100768 if (switched) {
769 if (avoided) {
770 srv = avoided;
771 break;
772 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100773 goto requeue_servers;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100774 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100775 switched = 1;
776 fwrr_switch_trees(grp);
777
778 }
779
780 /* OK, we have a server. However, it may be saturated, in which
781 * case we don't want to reconsider it for now. We'll update
782 * its position and dequeue it anyway, so that we can move it
783 * to a better place afterwards.
784 */
785 fwrr_update_position(grp, srv);
786 fwrr_dequeue_srv(srv);
787 grp->curr_pos++;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100788 if (!srv->maxconn || srv->cur_sess < srv_dynamic_maxconn(srv)) {
789 /* make sure it is not the server we are trying to exclude... */
790 if (srv != srvtoavoid || avoided)
791 break;
792
793 avoided = srv; /* ...but remember that is was selected yet avoided */
794 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100795
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100796 /* the server is saturated or avoided, let's chain it for later reinsertion */
Willy Tarreaub625a082007-11-26 01:15:43 +0100797 srv->next_full = full;
798 full = srv;
799 }
800
801 /* OK, we got the best server, let's update it */
802 fwrr_queue_srv(srv);
803
804 requeue_servers:
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100805 /* Requeue all extracted servers. If full==srv then it was
806 * avoided (unsucessfully) and chained, omit it now.
807 */
Willy Tarreau70bcfb72008-01-27 02:21:53 +0100808 if (unlikely(full != NULL)) {
Willy Tarreaub625a082007-11-26 01:15:43 +0100809 if (switched) {
810 /* the tree has switched, requeue all extracted servers
811 * into "init", because their place was lost, and only
812 * their weight matters.
813 */
814 do {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100815 if (likely(full != srv))
816 fwrr_queue_by_weight(grp->init, full);
Willy Tarreaub625a082007-11-26 01:15:43 +0100817 full = full->next_full;
818 } while (full);
819 } else {
820 /* requeue all extracted servers just as if they were consumed
821 * so that they regain their expected place.
822 */
823 do {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100824 if (likely(full != srv))
825 fwrr_queue_srv(full);
Willy Tarreaub625a082007-11-26 01:15:43 +0100826 full = full->next_full;
827 } while (full);
828 }
829 }
830 return srv;
831}
832
Willy Tarreau51406232008-03-10 22:04:20 +0100833/* Remove a server from a tree. It must have previously been dequeued. This
834 * function is meant to be called when a server is going down or has its
835 * weight disabled.
836 */
837static inline void fwlc_remove_from_tree(struct server *s)
838{
839 s->lb_tree = NULL;
840}
841
842/* simply removes a server from a tree */
843static inline void fwlc_dequeue_srv(struct server *s)
844{
845 eb32_delete(&s->lb_node);
846}
847
848/* Queue a server in its associated tree, assuming the weight is >0.
849 * Servers are sorted by #conns/weight. To ensure maximum accuracy,
850 * we use #conns*SRV_EWGHT_MAX/eweight as the sorting key.
851 */
852static inline void fwlc_queue_srv(struct server *s)
853{
854 s->lb_node.key = s->cur_sess * SRV_EWGHT_MAX / s->eweight;
855 eb32_insert(s->lb_tree, &s->lb_node);
856}
857
858/* Re-position the server in the FWLC tree after it has been assigned one
859 * connection or after it has released one. Note that it is possible that
860 * the server has been moved out of the tree due to failed health-checks.
861 */
862static void fwlc_srv_reposition(struct server *s)
863{
864 if (!s->lb_tree)
865 return;
866 fwlc_dequeue_srv(s);
867 fwlc_queue_srv(s);
868}
869
870/* This function updates the server trees according to server <srv>'s new
871 * state. It should be called when server <srv>'s status changes to down.
872 * It is not important whether the server was already down or not. It is not
873 * important either that the new state is completely down (the caller may not
874 * know all the variables of a server's state).
875 */
876static void fwlc_set_server_status_down(struct server *srv)
877{
878 struct proxy *p = srv->proxy;
879
880 if (srv->state == srv->prev_state &&
881 srv->eweight == srv->prev_eweight)
882 return;
883
884 if (srv_is_usable(srv->state, srv->eweight))
885 goto out_update_state;
886
887 if (!srv_is_usable(srv->prev_state, srv->prev_eweight))
888 /* server was already down */
889 goto out_update_backend;
890
891 if (srv->state & SRV_BACKUP) {
892 p->lbprm.tot_wbck -= srv->prev_eweight;
893 p->srv_bck--;
894
895 if (srv == p->lbprm.fbck) {
896 /* we lost the first backup server in a single-backup
897 * configuration, we must search another one.
898 */
899 struct server *srv2 = p->lbprm.fbck;
900 do {
901 srv2 = srv2->next;
902 } while (srv2 &&
903 !((srv2->state & SRV_BACKUP) &&
904 srv_is_usable(srv2->state, srv2->eweight)));
905 p->lbprm.fbck = srv2;
906 }
907 } else {
908 p->lbprm.tot_wact -= srv->prev_eweight;
909 p->srv_act--;
910 }
911
912 fwlc_dequeue_srv(srv);
913 fwlc_remove_from_tree(srv);
914
915out_update_backend:
916 /* check/update tot_used, tot_weight */
917 update_backend_weight(p);
918 out_update_state:
919 srv->prev_state = srv->state;
920 srv->prev_eweight = srv->eweight;
921}
922
923/* This function updates the server trees according to server <srv>'s new
924 * state. It should be called when server <srv>'s status changes to up.
925 * It is not important whether the server was already down or not. It is not
926 * important either that the new state is completely UP (the caller may not
927 * know all the variables of a server's state). This function will not change
928 * the weight of a server which was already up.
929 */
930static void fwlc_set_server_status_up(struct server *srv)
931{
932 struct proxy *p = srv->proxy;
933
934 if (srv->state == srv->prev_state &&
935 srv->eweight == srv->prev_eweight)
936 return;
937
938 if (!srv_is_usable(srv->state, srv->eweight))
939 goto out_update_state;
940
941 if (srv_is_usable(srv->prev_state, srv->prev_eweight))
942 /* server was already up */
943 goto out_update_backend;
944
945 if (srv->state & SRV_BACKUP) {
946 srv->lb_tree = &p->lbprm.fwlc.bck;
947 p->lbprm.tot_wbck += srv->eweight;
948 p->srv_bck++;
949
950 if (!(p->options & PR_O_USE_ALL_BK)) {
951 if (!p->lbprm.fbck) {
952 /* there was no backup server anymore */
953 p->lbprm.fbck = srv;
954 } else {
955 /* we may have restored a backup server prior to fbck,
956 * in which case it should replace it.
957 */
958 struct server *srv2 = srv;
959 do {
960 srv2 = srv2->next;
961 } while (srv2 && (srv2 != p->lbprm.fbck));
962 if (srv2)
963 p->lbprm.fbck = srv;
964 }
965 }
966 } else {
967 srv->lb_tree = &p->lbprm.fwlc.act;
968 p->lbprm.tot_wact += srv->eweight;
969 p->srv_act++;
970 }
971
972 /* note that eweight cannot be 0 here */
973 fwlc_queue_srv(srv);
974
975 out_update_backend:
976 /* check/update tot_used, tot_weight */
977 update_backend_weight(p);
978 out_update_state:
979 srv->prev_state = srv->state;
980 srv->prev_eweight = srv->eweight;
981}
982
983/* This function must be called after an update to server <srv>'s effective
984 * weight. It may be called after a state change too.
985 */
986static void fwlc_update_server_weight(struct server *srv)
987{
988 int old_state, new_state;
989 struct proxy *p = srv->proxy;
990
991 if (srv->state == srv->prev_state &&
992 srv->eweight == srv->prev_eweight)
993 return;
994
995 /* If changing the server's weight changes its state, we simply apply
996 * the procedures we already have for status change. If the state
997 * remains down, the server is not in any tree, so it's as easy as
998 * updating its values. If the state remains up with different weights,
999 * there are some computations to perform to find a new place and
1000 * possibly a new tree for this server.
1001 */
1002
1003 old_state = srv_is_usable(srv->prev_state, srv->prev_eweight);
1004 new_state = srv_is_usable(srv->state, srv->eweight);
1005
1006 if (!old_state && !new_state) {
1007 srv->prev_state = srv->state;
1008 srv->prev_eweight = srv->eweight;
1009 return;
1010 }
1011 else if (!old_state && new_state) {
1012 fwlc_set_server_status_up(srv);
1013 return;
1014 }
1015 else if (old_state && !new_state) {
1016 fwlc_set_server_status_down(srv);
1017 return;
1018 }
1019
1020 if (srv->lb_tree)
1021 fwlc_dequeue_srv(srv);
1022
1023 if (srv->state & SRV_BACKUP) {
1024 p->lbprm.tot_wbck += srv->eweight - srv->prev_eweight;
1025 srv->lb_tree = &p->lbprm.fwlc.bck;
1026 } else {
1027 p->lbprm.tot_wact += srv->eweight - srv->prev_eweight;
1028 srv->lb_tree = &p->lbprm.fwlc.act;
1029 }
1030
1031 fwlc_queue_srv(srv);
1032
1033 update_backend_weight(p);
1034 srv->prev_state = srv->state;
1035 srv->prev_eweight = srv->eweight;
1036}
1037
1038/* This function is responsible for building the trees in case of fast
1039 * weighted least-conns. It also sets p->lbprm.wdiv to the eweight to
1040 * uweight ratio. Both active and backup groups are initialized.
1041 */
1042void fwlc_init_server_tree(struct proxy *p)
1043{
1044 struct server *srv;
1045 struct eb_root init_head = EB_ROOT;
1046
1047 p->lbprm.set_server_status_up = fwlc_set_server_status_up;
1048 p->lbprm.set_server_status_down = fwlc_set_server_status_down;
1049 p->lbprm.update_server_eweight = fwlc_update_server_weight;
1050 p->lbprm.server_take_conn = fwlc_srv_reposition;
1051 p->lbprm.server_drop_conn = fwlc_srv_reposition;
1052
1053 p->lbprm.wdiv = BE_WEIGHT_SCALE;
1054 for (srv = p->srv; srv; srv = srv->next) {
1055 srv->prev_eweight = srv->eweight = srv->uweight * BE_WEIGHT_SCALE;
1056 srv->prev_state = srv->state;
1057 }
1058
1059 recount_servers(p);
1060 update_backend_weight(p);
1061
1062 p->lbprm.fwlc.act = init_head;
1063 p->lbprm.fwlc.bck = init_head;
1064
1065 /* queue active and backup servers in two distinct groups */
1066 for (srv = p->srv; srv; srv = srv->next) {
1067 if (!srv_is_usable(srv->state, srv->eweight))
1068 continue;
1069 srv->lb_tree = (srv->state & SRV_BACKUP) ? &p->lbprm.fwlc.bck : &p->lbprm.fwlc.act;
1070 fwlc_queue_srv(srv);
1071 }
1072}
1073
1074/* Return next server from the FWLC tree in backend <p>. If the tree is empty,
1075 * return NULL. Saturated servers are skipped.
1076 */
1077static struct server *fwlc_get_next_server(struct proxy *p, struct server *srvtoavoid)
1078{
1079 struct server *srv, *avoided;
1080 struct eb32_node *node;
1081
1082 srv = avoided = NULL;
1083
1084 if (p->srv_act)
1085 node = eb32_first(&p->lbprm.fwlc.act);
1086 else if (p->lbprm.fbck)
1087 return p->lbprm.fbck;
1088 else if (p->srv_bck)
1089 node = eb32_first(&p->lbprm.fwlc.bck);
1090 else
1091 return NULL;
1092
1093 while (node) {
1094 /* OK, we have a server. However, it may be saturated, in which
1095 * case we don't want to reconsider it for now, so we'll simply
1096 * skip it. Same if it's the server we try to avoid, in which
1097 * case we simply remember it for later use if needed.
1098 */
1099 struct server *s;
1100
1101 s = eb32_entry(node, struct server, lb_node);
1102 if (!s->maxconn || s->cur_sess < srv_dynamic_maxconn(s)) {
1103 if (s != srvtoavoid) {
1104 srv = s;
1105 break;
1106 }
1107 avoided = s;
1108 }
1109 node = eb32_next(node);
1110 }
1111
1112 if (!srv)
1113 srv = avoided;
1114
1115 return srv;
1116}
1117
Willy Tarreau01732802007-11-01 22:48:15 +01001118/*
1119 * This function tries to find a running server for the proxy <px> following
1120 * the URL parameter hash method. It looks for a specific parameter in the
1121 * URL and hashes it to compute the server ID. This is useful to optimize
1122 * performance by avoiding bounces between servers in contexts where sessions
1123 * are shared but cookies are not usable. If the parameter is not found, NULL
1124 * is returned. If any server is found, it will be returned. If no valid server
1125 * is found, NULL is returned.
Willy Tarreau01732802007-11-01 22:48:15 +01001126 */
1127struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
1128{
1129 unsigned long hash = 0;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001130 const char *p;
1131 const char *params;
Willy Tarreau01732802007-11-01 22:48:15 +01001132 int plen;
1133
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001134 /* when tot_weight is 0 then so is srv_count */
Willy Tarreau20697042007-11-15 23:26:18 +01001135 if (px->lbprm.tot_weight == 0)
Willy Tarreau01732802007-11-01 22:48:15 +01001136 return NULL;
1137
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001138 if ((p = memchr(uri, '?', uri_len)) == NULL)
1139 return NULL;
1140
Willy Tarreau20697042007-11-15 23:26:18 +01001141 if (px->lbprm.map.state & PR_MAP_RECALC)
1142 recalc_server_map(px);
1143
Willy Tarreau01732802007-11-01 22:48:15 +01001144 p++;
1145
1146 uri_len -= (p - uri);
1147 plen = px->url_param_len;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001148 params = p;
Willy Tarreau01732802007-11-01 22:48:15 +01001149
1150 while (uri_len > plen) {
1151 /* Look for the parameter name followed by an equal symbol */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001152 if (params[plen] == '=') {
1153 if (memcmp(params, px->url_param_name, plen) == 0) {
1154 /* OK, we have the parameter here at <params>, and
Willy Tarreau01732802007-11-01 22:48:15 +01001155 * the value after the equal sign, at <p>
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001156 * skip the equal symbol
Willy Tarreau01732802007-11-01 22:48:15 +01001157 */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001158 p += plen + 1;
1159 uri_len -= plen + 1;
1160
Willy Tarreau01732802007-11-01 22:48:15 +01001161 while (uri_len && *p != '&') {
1162 hash = *p + (hash << 6) + (hash << 16) - hash;
1163 uri_len--;
1164 p++;
1165 }
Willy Tarreau20697042007-11-15 23:26:18 +01001166 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
Willy Tarreau01732802007-11-01 22:48:15 +01001167 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001168 }
1169 /* skip to next parameter */
1170 p = memchr(params, '&', uri_len);
1171 if (!p)
1172 return NULL;
1173 p++;
1174 uri_len -= (p - params);
1175 params = p;
1176 }
1177 return NULL;
1178}
1179
1180/*
1181 * this does the same as the previous server_ph, but check the body contents
1182 */
1183struct server *get_server_ph_post(struct session *s)
1184{
1185 unsigned long hash = 0;
1186 struct http_txn *txn = &s->txn;
1187 struct buffer *req = s->req;
1188 struct http_msg *msg = &txn->req;
1189 struct proxy *px = s->be;
1190 unsigned int plen = px->url_param_len;
1191
1192 /* tot_weight appears to mean srv_count */
1193 if (px->lbprm.tot_weight == 0)
1194 return NULL;
1195
1196 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1;
1197 unsigned long len = req->total - body;
1198 const char *params = req->data + body;
1199
1200 if ( len == 0 )
1201 return NULL;
1202
1203 if (px->lbprm.map.state & PR_MAP_RECALC)
1204 recalc_server_map(px);
1205
1206 struct hdr_ctx ctx;
1207 ctx.idx = 0;
1208
1209 /* if the message is chunked, we skip the chunk size, but use the value as len */
1210 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
1211 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
1212 unsigned int chunk = 0;
1213 while ( params < req->rlim && !HTTP_IS_CRLF(*params)) {
1214 char c = *params;
1215 if (ishex(c)) {
1216 unsigned int hex = toupper(c) - '0';
1217 if ( hex > 9 )
1218 hex -= 'A' - '9' - 1;
1219 chunk = (chunk << 4) | hex;
1220 }
1221 else
1222 return NULL;
1223 params++;
1224 len--;
Willy Tarreau01732802007-11-01 22:48:15 +01001225 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001226 /* spec says we get CRLF */
1227 if (HTTP_IS_CRLF(*params) && HTTP_IS_CRLF(params[1]))
1228 params += 2;
1229 else
1230 return NULL;
1231 /* ok we have some encoded length, just inspect the first chunk */
1232 len = chunk;
1233 }
Willy Tarreau01732802007-11-01 22:48:15 +01001234
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001235 const char *p = params;
1236
1237 while (len > plen) {
1238 /* Look for the parameter name followed by an equal symbol */
1239 if (params[plen] == '=') {
1240 if (memcmp(params, px->url_param_name, plen) == 0) {
1241 /* OK, we have the parameter here at <params>, and
1242 * the value after the equal sign, at <p>
1243 * skip the equal symbol
1244 */
1245 p += plen + 1;
1246 len -= plen + 1;
1247
1248 while (len && *p != '&') {
1249 if (unlikely(!HTTP_IS_TOKEN(*p))) {
1250 /* if in a POST, body must be URI encoded or its not a URI.
1251 * Do not interprete any possible binary data as a parameter.
1252 */
1253 if (likely(HTTP_IS_LWS(*p))) /* eol, uncertain uri len */
1254 break;
1255 return NULL; /* oh, no; this is not uri-encoded.
1256 * This body does not contain parameters.
1257 */
1258 }
1259 hash = *p + (hash << 6) + (hash << 16) - hash;
1260 len--;
1261 p++;
1262 /* should we break if vlen exceeds limit? */
1263 }
1264 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
1265 }
1266 }
Willy Tarreau01732802007-11-01 22:48:15 +01001267 /* skip to next parameter */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001268 p = memchr(params, '&', len);
Willy Tarreau01732802007-11-01 22:48:15 +01001269 if (!p)
1270 return NULL;
1271 p++;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001272 len -= (p - params);
1273 params = p;
Willy Tarreau01732802007-11-01 22:48:15 +01001274 }
1275 return NULL;
1276}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001277
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001278
Willy Tarreaubaaee002006-06-26 02:48:02 +02001279/*
1280 * This function marks the session as 'assigned' in direct or dispatch modes,
1281 * or tries to assign one in balance mode, according to the algorithm. It does
1282 * nothing if the session had already been assigned a server.
1283 *
1284 * It may return :
1285 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
1286 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
1287 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
1288 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1289 *
1290 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
1291 * not need to be called anymore. This usually means that s->srv can be trusted
1292 * in balance and direct modes. This flag is not cleared, so it's to the caller
1293 * to clear it if required (eg: redispatch).
1294 *
1295 */
1296
1297int assign_server(struct session *s)
1298{
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001299
1300 struct server *srvtoavoid;
1301
Willy Tarreaubaaee002006-06-26 02:48:02 +02001302#ifdef DEBUG_FULL
1303 fprintf(stderr,"assign_server : s=%p\n",s);
1304#endif
1305
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001306 srvtoavoid = s->srv;
1307 s->srv = NULL;
1308
Willy Tarreaubaaee002006-06-26 02:48:02 +02001309 if (s->pend_pos)
1310 return SRV_STATUS_INTERNAL;
1311
1312 if (!(s->flags & SN_ASSIGNED)) {
Willy Tarreau31682232007-11-29 15:38:04 +01001313 if (s->be->lbprm.algo & BE_LB_ALGO) {
Willy Tarreau1a20a5d2007-11-01 21:08:19 +01001314 int len;
1315
Willy Tarreau5d65bbb2007-01-21 12:47:26 +01001316 if (s->flags & SN_DIRECT) {
1317 s->flags |= SN_ASSIGNED;
1318 return SRV_STATUS_OK;
1319 }
Willy Tarreau1a20a5d2007-11-01 21:08:19 +01001320
Willy Tarreaub625a082007-11-26 01:15:43 +01001321 if (!s->be->lbprm.tot_weight)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001322 return SRV_STATUS_NOSRV;
1323
Willy Tarreau31682232007-11-29 15:38:04 +01001324 switch (s->be->lbprm.algo & BE_LB_ALGO) {
1325 case BE_LB_ALGO_RR:
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001326 s->srv = fwrr_get_next_server(s->be, srvtoavoid);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001327 if (!s->srv)
1328 return SRV_STATUS_FULL;
Willy Tarreau1a20a5d2007-11-01 21:08:19 +01001329 break;
Willy Tarreau51406232008-03-10 22:04:20 +01001330 case BE_LB_ALGO_LC:
1331 s->srv = fwlc_get_next_server(s->be, srvtoavoid);
1332 if (!s->srv)
1333 return SRV_STATUS_FULL;
1334 break;
Willy Tarreau31682232007-11-29 15:38:04 +01001335 case BE_LB_ALGO_SH:
Willy Tarreaubaaee002006-06-26 02:48:02 +02001336 if (s->cli_addr.ss_family == AF_INET)
1337 len = 4;
1338 else if (s->cli_addr.ss_family == AF_INET6)
1339 len = 16;
1340 else /* unknown IP family */
1341 return SRV_STATUS_INTERNAL;
1342
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001343 s->srv = get_server_sh(s->be,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001344 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1345 len);
Willy Tarreau1a20a5d2007-11-01 21:08:19 +01001346 break;
Willy Tarreau31682232007-11-29 15:38:04 +01001347 case BE_LB_ALGO_UH:
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001348 /* URI hashing */
1349 s->srv = get_server_uh(s->be,
1350 s->txn.req.sol + s->txn.req.sl.rq.u,
1351 s->txn.req.sl.rq.u_l);
Willy Tarreau01732802007-11-01 22:48:15 +01001352 break;
Willy Tarreau31682232007-11-29 15:38:04 +01001353 case BE_LB_ALGO_PH:
Willy Tarreau01732802007-11-01 22:48:15 +01001354 /* URL Parameter hashing */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001355 if (s->txn.meth == HTTP_METH_POST &&
1356 memchr(s->txn.req.sol + s->txn.req.sl.rq.u, '&',
1357 s->txn.req.sl.rq.u_l ) == NULL)
1358 s->srv = get_server_ph_post(s);
1359 else
1360 s->srv = get_server_ph(s->be,
1361 s->txn.req.sol + s->txn.req.sl.rq.u,
1362 s->txn.req.sl.rq.u_l);
1363
Willy Tarreau01732802007-11-01 22:48:15 +01001364 if (!s->srv) {
Willy Tarreaub625a082007-11-26 01:15:43 +01001365 /* parameter not found, fall back to round robin on the map */
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001366 s->srv = get_server_rr_with_conns(s->be, srvtoavoid);
Willy Tarreau01732802007-11-01 22:48:15 +01001367 if (!s->srv)
1368 return SRV_STATUS_FULL;
1369 }
Willy Tarreau1a20a5d2007-11-01 21:08:19 +01001370 break;
1371 default:
1372 /* unknown balancing algorithm */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001373 return SRV_STATUS_INTERNAL;
Willy Tarreau1a20a5d2007-11-01 21:08:19 +01001374 }
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001375 if (s->srv != srvtoavoid) {
1376 s->be->cum_lbconn++;
1377 s->srv->cum_lbconn++;
1378 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001379 }
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001380 else if (s->be->options & PR_O_HTTP_PROXY) {
1381 if (!s->srv_addr.sin_addr.s_addr)
1382 return SRV_STATUS_NOSRV;
1383 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001384 else if (!*(int *)&s->be->dispatch_addr.sin_addr &&
Willy Tarreau5d65bbb2007-01-21 12:47:26 +01001385 !(s->fe->options & PR_O_TRANSP)) {
Willy Tarreau1a1158b2007-01-20 11:07:46 +01001386 return SRV_STATUS_NOSRV;
Willy Tarreau5d65bbb2007-01-21 12:47:26 +01001387 }
1388 s->flags |= SN_ASSIGNED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001389 }
1390 return SRV_STATUS_OK;
1391}
1392
1393
1394/*
1395 * This function assigns a server address to a session, and sets SN_ADDR_SET.
1396 * The address is taken from the currently assigned server, or from the
1397 * dispatch or transparent address.
1398 *
1399 * It may return :
1400 * SRV_STATUS_OK if everything is OK.
1401 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1402 *
1403 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
1404 * not cleared, so it's to the caller to clear it if required.
1405 *
1406 */
1407int assign_server_address(struct session *s)
1408{
1409#ifdef DEBUG_FULL
1410 fprintf(stderr,"assign_server_address : s=%p\n",s);
1411#endif
1412
Willy Tarreau31682232007-11-29 15:38:04 +01001413 if ((s->flags & SN_DIRECT) || (s->be->lbprm.algo & BE_LB_ALGO)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001414 /* A server is necessarily known for this session */
1415 if (!(s->flags & SN_ASSIGNED))
1416 return SRV_STATUS_INTERNAL;
1417
1418 s->srv_addr = s->srv->addr;
1419
1420 /* if this server remaps proxied ports, we'll use
1421 * the port the client connected to with an offset. */
1422 if (s->srv->state & SRV_MAPPORTS) {
Willy Tarreau14c8aac2007-05-08 19:46:30 +02001423 if (!(s->fe->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET))
1424 get_frt_addr(s);
1425 if (s->frt_addr.ss_family == AF_INET) {
1426 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) +
1427 ntohs(((struct sockaddr_in *)&s->frt_addr)->sin_port));
1428 } else {
1429 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) +
1430 ntohs(((struct sockaddr_in6 *)&s->frt_addr)->sin6_port));
1431 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001432 }
1433 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001434 else if (*(int *)&s->be->dispatch_addr.sin_addr) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001435 /* connect to the defined dispatch addr */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001436 s->srv_addr = s->be->dispatch_addr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001437 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001438 else if (s->fe->options & PR_O_TRANSP) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001439 /* in transparent mode, use the original dest addr if no dispatch specified */
Willy Tarreaubd414282008-01-19 13:46:35 +01001440 if (!(s->flags & SN_FRT_ADDR_SET))
1441 get_frt_addr(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001442
Willy Tarreaubd414282008-01-19 13:46:35 +01001443 memcpy(&s->srv_addr, &s->frt_addr, MIN(sizeof(s->srv_addr), sizeof(s->frt_addr)));
1444 /* when we support IPv6 on the backend, we may add other tests */
1445 //qfprintf(stderr, "Cannot get original server address.\n");
1446 //return SRV_STATUS_INTERNAL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001447 }
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001448 else if (s->be->options & PR_O_HTTP_PROXY) {
1449 /* If HTTP PROXY option is set, then server is already assigned
1450 * during incoming client request parsing. */
1451 }
Willy Tarreau1a1158b2007-01-20 11:07:46 +01001452 else {
1453 /* no server and no LB algorithm ! */
1454 return SRV_STATUS_INTERNAL;
1455 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001456
1457 s->flags |= SN_ADDR_SET;
1458 return SRV_STATUS_OK;
1459}
1460
1461
1462/* This function assigns a server to session <s> if required, and can add the
1463 * connection to either the assigned server's queue or to the proxy's queue.
1464 *
1465 * Returns :
1466 *
1467 * SRV_STATUS_OK if everything is OK.
1468 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
1469 * SRV_STATUS_QUEUED if the connection has been queued.
1470 * SRV_STATUS_FULL if the server(s) is/are saturated and the
1471 * connection could not be queued.
1472 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1473 *
1474 */
1475int assign_server_and_queue(struct session *s)
1476{
1477 struct pendconn *p;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001478 struct server *srv;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001479 int err;
1480
1481 if (s->pend_pos)
1482 return SRV_STATUS_INTERNAL;
1483
1484 if (s->flags & SN_ASSIGNED) {
Willy Tarreau21d2af32008-02-14 20:25:24 +01001485 if ((s->flags & SN_REDIRECTABLE) && s->srv && s->srv->rdr_len) {
1486 /* server scheduled for redirection, and already assigned. We
1487 * don't want to go further nor check the queue.
1488 */
1489 return SRV_STATUS_OK;
1490 }
1491
Elijah Epifanovacafc5f2007-10-25 20:15:38 +02001492 if (s->srv && s->srv->maxqueue > 0 && s->srv->nbpend >= s->srv->maxqueue) {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001493 /* it's left to the dispatcher to choose a server */
Elijah Epifanovacafc5f2007-10-25 20:15:38 +02001494 s->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Elijah Epifanovacafc5f2007-10-25 20:15:38 +02001495 } else {
1496 /* a server does not need to be assigned, perhaps because we're in
1497 * direct mode, or in dispatch or transparent modes where the server
1498 * is not needed.
1499 */
1500 if (s->srv &&
1501 s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) {
1502 p = pendconn_add(s);
1503 if (p)
1504 return SRV_STATUS_QUEUED;
1505 else
1506 return SRV_STATUS_FULL;
1507 }
1508 return SRV_STATUS_OK;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001509 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001510 }
1511
1512 /* a server needs to be assigned */
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001513 srv = s->srv;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001514 err = assign_server(s);
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001515
1516 if (srv) {
1517 if (srv != s->srv) {
1518 /* This session was previously dispatched to another server:
1519 * - set TX_CK_DOWN if txn.flags was TX_CK_VALID
1520 * - set SN_REDISP if it was successfully redispatched
1521 * - increment srv->redispatches and be->redispatches
1522 */
1523
1524 if ((s->txn.flags & TX_CK_MASK) == TX_CK_VALID) {
1525 s->txn.flags &= ~TX_CK_MASK;
1526 s->txn.flags |= TX_CK_DOWN;
1527 }
1528
1529 s->flags |= SN_REDISP;
1530
1531 srv->redispatches++;
1532 s->be->redispatches++;
1533 } else {
1534 srv->retries++;
1535 s->be->retries++;
1536 }
1537 }
1538
Willy Tarreaubaaee002006-06-26 02:48:02 +02001539 switch (err) {
1540 case SRV_STATUS_OK:
Willy Tarreau21d2af32008-02-14 20:25:24 +01001541 if ((s->flags & SN_REDIRECTABLE) && s->srv && s->srv->rdr_len) {
1542 /* server supporting redirection and it is possible.
1543 * Let's report that and ignore maxconn !
1544 */
1545 return SRV_STATUS_OK;
1546 }
1547
Willy Tarreaubaaee002006-06-26 02:48:02 +02001548 /* in balance mode, we might have servers with connection limits */
1549 if (s->srv &&
1550 s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) {
1551 p = pendconn_add(s);
1552 if (p)
1553 return SRV_STATUS_QUEUED;
1554 else
1555 return SRV_STATUS_FULL;
1556 }
1557 return SRV_STATUS_OK;
1558
1559 case SRV_STATUS_FULL:
1560 /* queue this session into the proxy's queue */
1561 p = pendconn_add(s);
1562 if (p)
1563 return SRV_STATUS_QUEUED;
1564 else
1565 return SRV_STATUS_FULL;
1566
1567 case SRV_STATUS_NOSRV:
1568 case SRV_STATUS_INTERNAL:
1569 return err;
1570 default:
1571 return SRV_STATUS_INTERNAL;
1572 }
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001573}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001574
1575/*
1576 * This function initiates a connection to the server assigned to this session
1577 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
1578 * It can return one of :
1579 * - SN_ERR_NONE if everything's OK
1580 * - SN_ERR_SRVTO if there are no more servers
1581 * - SN_ERR_SRVCL if the connection was refused by the server
1582 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1583 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1584 * - SN_ERR_INTERNAL for any other purely internal errors
1585 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
1586 */
1587int connect_server(struct session *s)
1588{
1589 int fd, err;
1590
1591 if (!(s->flags & SN_ADDR_SET)) {
1592 err = assign_server_address(s);
1593 if (err != SRV_STATUS_OK)
1594 return SN_ERR_INTERNAL;
1595 }
1596
1597 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
1598 qfprintf(stderr, "Cannot get a server socket.\n");
1599
1600 if (errno == ENFILE)
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001601 send_log(s->be, LOG_EMERG,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001602 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001603 s->be->id, maxfd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001604 else if (errno == EMFILE)
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001605 send_log(s->be, LOG_EMERG,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001606 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001607 s->be->id, maxfd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001608 else if (errno == ENOBUFS || errno == ENOMEM)
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001609 send_log(s->be, LOG_EMERG,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001610 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001611 s->be->id, maxfd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001612 /* this is a resource error */
1613 return SN_ERR_RESOURCE;
1614 }
1615
1616 if (fd >= global.maxsock) {
1617 /* do not log anything there, it's a normal condition when this option
1618 * is used to serialize connections to a server !
1619 */
1620 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1621 close(fd);
1622 return SN_ERR_PRXCOND; /* it is a configuration limit */
1623 }
1624
Willy Tarreau6d1a9882007-01-07 02:03:04 +01001625#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001626 if ((s->fe->options & s->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01001627 /* TCP splicing supported by both FE and BE */
1628 tcp_splice_initfd(s->cli_fd, fd);
1629 }
1630#endif
1631
Willy Tarreaubaaee002006-06-26 02:48:02 +02001632 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1633 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
1634 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
1635 close(fd);
1636 return SN_ERR_INTERNAL;
1637 }
1638
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001639 if (s->be->options & PR_O_TCP_SRV_KA)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001640 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1641
Alexandre Cassen87ea5482007-10-11 20:48:58 +02001642 if (s->be->options & PR_O_TCP_NOLING)
1643 setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
1644
Willy Tarreaubaaee002006-06-26 02:48:02 +02001645 /* allow specific binding :
1646 * - server-specific at first
1647 * - proxy-specific next
1648 */
1649 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001650 struct sockaddr_in *remote = NULL;
1651 int ret, flags = 0;
Willy Tarreau77074d52006-11-12 23:57:19 +01001652
Willy Tarreaucf1d5722008-02-14 20:28:18 +01001653#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
Willy Tarreau786d1912008-01-13 18:10:06 +01001654 switch (s->srv->state & SRV_TPROXY_MASK) {
1655 case SRV_TPROXY_ADDR:
1656 remote = (struct sockaddr_in *)&s->srv->tproxy_addr;
1657 flags = 3;
1658 break;
1659 case SRV_TPROXY_CLI:
1660 flags |= 2;
1661 /* fall through */
1662 case SRV_TPROXY_CIP:
1663 /* FIXME: what can we do if the client connects in IPv6 ? */
1664 flags |= 1;
1665 remote = (struct sockaddr_in *)&s->cli_addr;
1666 break;
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001667 }
Willy Tarreaucf1d5722008-02-14 20:28:18 +01001668#endif
Willy Tarreaue8c66af2008-01-13 18:40:14 +01001669 ret = tcpv4_bind_socket(fd, flags, &s->srv->source_addr, remote);
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001670 if (ret) {
1671 close(fd);
1672 if (ret == 1) {
1673 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1674 s->be->id, s->srv->id);
1675 send_log(s->be, LOG_EMERG,
1676 "Cannot bind to source address before connect() for server %s/%s.\n",
1677 s->be->id, s->srv->id);
1678 } else {
Willy Tarreau77074d52006-11-12 23:57:19 +01001679 Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001680 s->be->id, s->srv->id);
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001681 send_log(s->be, LOG_EMERG,
Willy Tarreau77074d52006-11-12 23:57:19 +01001682 "Cannot bind to tproxy source address before connect() for server %s/%s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001683 s->be->id, s->srv->id);
Willy Tarreau77074d52006-11-12 23:57:19 +01001684 }
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001685 return SN_ERR_RESOURCE;
Willy Tarreau77074d52006-11-12 23:57:19 +01001686 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001687 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001688 else if (s->be->options & PR_O_BIND_SRC) {
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001689 struct sockaddr_in *remote = NULL;
1690 int ret, flags = 0;
Willy Tarreau77074d52006-11-12 23:57:19 +01001691
Willy Tarreaucf1d5722008-02-14 20:28:18 +01001692#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
Willy Tarreau786d1912008-01-13 18:10:06 +01001693 switch (s->be->options & PR_O_TPXY_MASK) {
1694 case PR_O_TPXY_ADDR:
1695 remote = (struct sockaddr_in *)&s->be->tproxy_addr;
1696 flags = 3;
1697 break;
1698 case PR_O_TPXY_CLI:
1699 flags |= 2;
1700 /* fall through */
1701 case PR_O_TPXY_CIP:
1702 /* FIXME: what can we do if the client connects in IPv6 ? */
1703 flags |= 1;
1704 remote = (struct sockaddr_in *)&s->cli_addr;
1705 break;
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001706 }
Willy Tarreaucf1d5722008-02-14 20:28:18 +01001707#endif
Willy Tarreaue8c66af2008-01-13 18:40:14 +01001708 ret = tcpv4_bind_socket(fd, flags, &s->be->source_addr, remote);
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001709 if (ret) {
1710 close(fd);
1711 if (ret == 1) {
1712 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
1713 s->be->id);
1714 send_log(s->be, LOG_EMERG,
1715 "Cannot bind to source address before connect() for proxy %s.\n",
1716 s->be->id);
1717 } else {
Willy Tarreau77074d52006-11-12 23:57:19 +01001718 Alert("Cannot bind to tproxy source address before connect() for proxy %s. Aborting.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001719 s->be->id);
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001720 send_log(s->be, LOG_EMERG,
Willy Tarreaufe10a062008-01-12 22:22:34 +01001721 "Cannot bind to tproxy source address before connect() for proxy %s.\n",
1722 s->be->id);
Willy Tarreau77074d52006-11-12 23:57:19 +01001723 }
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001724 return SN_ERR_RESOURCE;
Willy Tarreau77074d52006-11-12 23:57:19 +01001725 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001726 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001727
Willy Tarreaubaaee002006-06-26 02:48:02 +02001728 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1729 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1730
1731 if (errno == EAGAIN || errno == EADDRINUSE) {
1732 char *msg;
1733 if (errno == EAGAIN) /* no free ports left, try again later */
1734 msg = "no free ports";
1735 else
1736 msg = "local address already in use";
1737
1738 qfprintf(stderr,"Cannot connect: %s.\n",msg);
1739 close(fd);
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001740 send_log(s->be, LOG_EMERG,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001741 "Connect() failed for server %s/%s: %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001742 s->be->id, s->srv->id, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001743 return SN_ERR_RESOURCE;
1744 } else if (errno == ETIMEDOUT) {
1745 //qfprintf(stderr,"Connect(): ETIMEDOUT");
1746 close(fd);
1747 return SN_ERR_SRVTO;
1748 } else {
1749 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
1750 //qfprintf(stderr,"Connect(): %d", errno);
1751 close(fd);
1752 return SN_ERR_SRVCL;
1753 }
1754 }
1755
1756 fdtab[fd].owner = s->task;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001757 fdtab[fd].state = FD_STCONN; /* connection in progress */
Willy Tarreaud7971282006-07-29 18:36:34 +02001758 fdtab[fd].cb[DIR_RD].f = &stream_sock_read;
Willy Tarreau54469402006-07-29 16:59:06 +02001759 fdtab[fd].cb[DIR_RD].b = s->rep;
Willy Tarreauf8306d52006-07-29 19:01:31 +02001760 fdtab[fd].cb[DIR_WR].f = &stream_sock_write;
Willy Tarreau54469402006-07-29 16:59:06 +02001761 fdtab[fd].cb[DIR_WR].b = s->req;
Willy Tarreaue94ebd02007-10-09 17:14:37 +02001762
1763 fdtab[fd].peeraddr = (struct sockaddr *)&s->srv_addr;
1764 fdtab[fd].peerlen = sizeof(s->srv_addr);
1765
Willy Tarreauf161a342007-04-08 16:59:42 +02001766 EV_FD_SET(fd, DIR_WR); /* for connect status */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001767
1768 fd_insert(fd);
1769 if (s->srv) {
1770 s->srv->cur_sess++;
1771 if (s->srv->cur_sess > s->srv->cur_sess_max)
1772 s->srv->cur_sess_max = s->srv->cur_sess;
Willy Tarreau51406232008-03-10 22:04:20 +01001773 if (s->be->lbprm.server_take_conn)
1774 s->be->lbprm.server_take_conn(s->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001775 }
1776
Willy Tarreaud7c30f92007-12-03 01:38:36 +01001777 if (!tv_add_ifset(&s->req->cex, &now, &s->be->timeout.connect))
Willy Tarreaud7971282006-07-29 18:36:34 +02001778 tv_eternity(&s->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001779 return SN_ERR_NONE; /* connection is OK */
1780}
1781
1782
1783/*
1784 * This function checks the retry count during the connect() job.
1785 * It updates the session's srv_state and retries, so that the caller knows
1786 * what it has to do. It uses the last connection error to set the log when
1787 * it expires. It returns 1 when it has expired, and 0 otherwise.
1788 */
1789int srv_count_retry_down(struct session *t, int conn_err)
1790{
1791 /* we are in front of a retryable error */
1792 t->conn_retries--;
Krzysztof Oledzki1cf36ba2007-10-18 19:12:30 +02001793
Willy Tarreaubaaee002006-06-26 02:48:02 +02001794 if (t->conn_retries < 0) {
1795 /* if not retryable anymore, let's abort */
Willy Tarreaud7971282006-07-29 18:36:34 +02001796 tv_eternity(&t->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001797 srv_close_with_err(t, conn_err, SN_FINST_C,
Willy Tarreau80587432006-12-24 17:47:20 +01001798 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001799 if (t->srv)
1800 t->srv->failed_conns++;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001801 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001802
1803 /* We used to have a free connection slot. Since we'll never use it,
1804 * we have to inform the server that it may be used by another session.
1805 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001806 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02001807 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001808 return 1;
1809 }
1810 return 0;
1811}
1812
1813
1814/*
1815 * This function performs the retryable part of the connect() job.
1816 * It updates the session's srv_state and retries, so that the caller knows
1817 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
1818 * it needs to redispatch.
1819 */
1820int srv_retryable_connect(struct session *t)
1821{
1822 int conn_err;
1823
1824 /* This loop ensures that we stop before the last retry in case of a
1825 * redispatchable server.
1826 */
1827 do {
1828 /* initiate a connection to the server */
1829 conn_err = connect_server(t);
1830 switch (conn_err) {
1831
1832 case SN_ERR_NONE:
1833 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
1834 t->srv_state = SV_STCONN;
Willy Tarreau98937b82007-12-10 15:05:42 +01001835 if (t->srv)
1836 t->srv->cum_sess++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001837 return 1;
1838
1839 case SN_ERR_INTERNAL:
Willy Tarreaud7971282006-07-29 18:36:34 +02001840 tv_eternity(&t->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001841 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
Willy Tarreau80587432006-12-24 17:47:20 +01001842 500, error_message(t, HTTP_ERR_500));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001843 if (t->srv)
Willy Tarreau98937b82007-12-10 15:05:42 +01001844 t->srv->cum_sess++;
1845 if (t->srv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001846 t->srv->failed_conns++;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001847 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001848 /* release other sessions waiting for this server */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001849 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02001850 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001851 return 1;
1852 }
1853 /* ensure that we have enough retries left */
1854 if (srv_count_retry_down(t, conn_err)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001855 return 1;
1856 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001857 } while (t->srv == NULL || t->conn_retries > 0 || !(t->be->options & PR_O_REDISP));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001858
1859 /* We're on our last chance, and the REDISP option was specified.
1860 * We will ignore cookie and force to balance or use the dispatcher.
1861 */
1862 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001863 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02001864 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001865
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001866 if (t->srv)
1867 t->srv->cum_sess++; //FIXME?
Willy Tarreaubaaee002006-06-26 02:48:02 +02001868
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001869 /* it's left to the dispatcher to choose a server */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001870 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001871 return 0;
1872}
1873
1874
1875/* This function performs the "redispatch" part of a connection attempt. It
1876 * will assign a server if required, queue the connection if required, and
1877 * handle errors that might arise at this level. It can change the server
1878 * state. It will return 1 if it encounters an error, switches the server
1879 * state, or has to queue a connection. Otherwise, it will return 0 indicating
1880 * that the connection is ready to use.
1881 */
1882
1883int srv_redispatch_connect(struct session *t)
1884{
1885 int conn_err;
1886
1887 /* We know that we don't have any connection pending, so we will
1888 * try to get a new one, and wait in this state if it's queued
1889 */
1890 conn_err = assign_server_and_queue(t);
1891 switch (conn_err) {
1892 case SRV_STATUS_OK:
1893 break;
1894
1895 case SRV_STATUS_NOSRV:
1896 /* note: it is guaranteed that t->srv == NULL here */
Willy Tarreaud7971282006-07-29 18:36:34 +02001897 tv_eternity(&t->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001898 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
Willy Tarreau80587432006-12-24 17:47:20 +01001899 503, error_message(t, HTTP_ERR_503));
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001900
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001901 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001902
1903 return 1;
1904
1905 case SRV_STATUS_QUEUED:
Willy Tarreau1fa31262007-12-03 00:36:16 +01001906 /* note: we use the connect expiration date for the queue. */
1907 if (!tv_add_ifset(&t->req->cex, &now, &t->be->timeout.queue))
Willy Tarreaud7971282006-07-29 18:36:34 +02001908 tv_eternity(&t->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001909 t->srv_state = SV_STIDLE;
1910 /* do nothing else and do not wake any other session up */
1911 return 1;
1912
1913 case SRV_STATUS_FULL:
1914 case SRV_STATUS_INTERNAL:
1915 default:
Willy Tarreaud7971282006-07-29 18:36:34 +02001916 tv_eternity(&t->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001917 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
Willy Tarreau80587432006-12-24 17:47:20 +01001918 500, error_message(t, HTTP_ERR_500));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001919 if (t->srv)
Willy Tarreau98937b82007-12-10 15:05:42 +01001920 t->srv->cum_sess++;
1921 if (t->srv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001922 t->srv->failed_conns++;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001923 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001924
1925 /* release other sessions waiting for this server */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001926 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02001927 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001928 return 1;
1929 }
1930 /* if we get here, it's because we got SRV_STATUS_OK, which also
1931 * means that the connection has not been queued.
1932 */
1933 return 0;
1934}
1935
Krzysztof Oledzki85130942007-10-22 16:21:10 +02001936int be_downtime(struct proxy *px) {
Willy Tarreaub625a082007-11-26 01:15:43 +01001937 if (px->lbprm.tot_weight && px->last_change < now.tv_sec) // ignore negative time
Krzysztof Oledzki85130942007-10-22 16:21:10 +02001938 return px->down_time;
1939
1940 return now.tv_sec - px->last_change + px->down_time;
1941}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001942
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001943/* This function parses a "balance" statement in a backend section describing
1944 * <curproxy>. It returns -1 if there is any error, otherwise zero. If it
1945 * returns -1, it may write an error message into ther <err> buffer, for at
1946 * most <errlen> bytes, trailing zero included. The trailing '\n' will not be
1947 * written. The function must be called with <args> pointing to the first word
1948 * after "balance".
1949 */
1950int backend_parse_balance(const char **args, char *err, int errlen, struct proxy *curproxy)
1951{
1952 if (!*(args[0])) {
1953 /* if no option is set, use round-robin by default */
Willy Tarreau31682232007-11-29 15:38:04 +01001954 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1955 curproxy->lbprm.algo |= BE_LB_ALGO_RR;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001956 return 0;
1957 }
1958
1959 if (!strcmp(args[0], "roundrobin")) {
Willy Tarreau31682232007-11-29 15:38:04 +01001960 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1961 curproxy->lbprm.algo |= BE_LB_ALGO_RR;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001962 }
Willy Tarreau51406232008-03-10 22:04:20 +01001963 else if (!strcmp(args[0], "leastconn")) {
1964 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1965 curproxy->lbprm.algo |= BE_LB_ALGO_LC;
1966 }
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001967 else if (!strcmp(args[0], "source")) {
Willy Tarreau31682232007-11-29 15:38:04 +01001968 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1969 curproxy->lbprm.algo |= BE_LB_ALGO_SH;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001970 }
1971 else if (!strcmp(args[0], "uri")) {
Willy Tarreau31682232007-11-29 15:38:04 +01001972 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1973 curproxy->lbprm.algo |= BE_LB_ALGO_UH;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001974 }
Willy Tarreau01732802007-11-01 22:48:15 +01001975 else if (!strcmp(args[0], "url_param")) {
1976 if (!*args[1]) {
1977 snprintf(err, errlen, "'balance url_param' requires an URL parameter name.");
1978 return -1;
1979 }
Willy Tarreau31682232007-11-29 15:38:04 +01001980 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1981 curproxy->lbprm.algo |= BE_LB_ALGO_PH;
Willy Tarreau01732802007-11-01 22:48:15 +01001982 if (curproxy->url_param_name)
1983 free(curproxy->url_param_name);
1984 curproxy->url_param_name = strdup(args[1]);
1985 curproxy->url_param_len = strlen(args[1]);
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001986 if ( *args[2] ) {
1987 if (strcmp(args[2], "check_post")) {
1988 snprintf(err, errlen, "'balance url_param' only accepts check_post modifier.");
1989 return -1;
1990 }
1991 if (*args[3]) {
1992 /* TODO: maybe issue a warning if there is no value, no digits or too long */
1993 curproxy->url_param_post_limit = str2ui(args[3]);
1994 }
1995 /* if no limit, or faul value in args[3], then default to a moderate wordlen */
1996 if (!curproxy->url_param_post_limit)
1997 curproxy->url_param_post_limit = 48;
1998 else if ( curproxy->url_param_post_limit < 3 )
1999 curproxy->url_param_post_limit = 3; /* minimum example: S=3 or \r\nS=6& */
2000 }
Willy Tarreau01732802007-11-01 22:48:15 +01002001 }
Willy Tarreaua0cbda62007-11-01 21:39:54 +01002002 else {
Willy Tarreau51406232008-03-10 22:04:20 +01002003 snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri' and 'url_param' options.");
Willy Tarreaua0cbda62007-11-01 21:39:54 +01002004 return -1;
2005 }
2006 return 0;
2007}
2008
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +01002009
2010/************************************************************************/
2011/* All supported keywords must be declared here. */
2012/************************************************************************/
2013
2014/* set test->i to the number of enabled servers on the proxy */
2015static int
2016acl_fetch_nbsrv(struct proxy *px, struct session *l4, void *l7, int dir,
2017 struct acl_expr *expr, struct acl_test *test)
2018{
2019 test->flags = ACL_TEST_F_VOL_TEST;
2020 if (expr->arg_len) {
2021 /* another proxy was designated, we must look for it */
2022 for (px = proxy; px; px = px->next)
2023 if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
2024 break;
2025 }
2026 if (!px)
2027 return 0;
2028
2029 if (px->srv_act)
2030 test->i = px->srv_act;
2031 else if (px->lbprm.fbck)
2032 test->i = 1;
2033 else
2034 test->i = px->srv_bck;
2035
2036 return 1;
2037}
2038
2039
2040/* Note: must not be declared <const> as its list will be overwritten */
2041static struct acl_kw_list acl_kws = {{ },{
2042 { "nbsrv", acl_parse_int, acl_fetch_nbsrv, acl_match_int },
2043 { NULL, NULL, NULL, NULL },
2044}};
2045
2046
2047__attribute__((constructor))
2048static void __backend_init(void)
2049{
2050 acl_register_keywords(&acl_kws);
2051}
2052
2053
Willy Tarreaubaaee002006-06-26 02:48:02 +02002054/*
2055 * Local variables:
2056 * c-indent-level: 8
2057 * c-basic-offset: 8
2058 * End:
2059 */