blob: 53b7e54881460e835e93b630d7dfa6a7ebc28ff4 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Health-checks functions.
3 *
Willy Tarreaue8c66af2008-01-13 18:40:14 +01004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +01005 * Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
Willy Tarreaubaaee002006-06-26 02:48:02 +02006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
Willy Tarreaub8816082008-01-18 12:18:15 +010014#include <assert.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020015#include <errno.h>
16#include <fcntl.h>
17#include <stdio.h>
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +020018#include <stdlib.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020019#include <string.h>
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +020020#include <time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020021#include <unistd.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25
Willy Tarreau2dd0d472006-06-29 17:53:05 +020026#include <common/compat.h>
27#include <common/config.h>
28#include <common/mini-clist.h>
Willy Tarreau83749182007-04-15 20:56:27 +020029#include <common/standard.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020031
32#include <types/global.h>
33#include <types/polling.h>
34#include <types/proxy.h>
35#include <types/session.h>
36
37#include <proto/backend.h>
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +010038#include <proto/buffers.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020039#include <proto/fd.h>
40#include <proto/log.h>
41#include <proto/queue.h>
Willy Tarreau3d300592007-03-18 18:34:41 +010042#include <proto/proto_http.h>
Willy Tarreaue8c66af2008-01-13 18:40:14 +010043#include <proto/proto_tcp.h>
Willy Tarreau2b5652f2006-12-31 17:46:05 +010044#include <proto/proxy.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020045#include <proto/server.h>
46#include <proto/task.h>
47
Willy Tarreau48494c02007-11-30 10:41:39 +010048/* sends a log message when a backend goes down, and also sets last
49 * change date.
50 */
51static void set_backend_down(struct proxy *be)
52{
53 be->last_change = now.tv_sec;
54 be->down_trans++;
55
56 Alert("%s '%s' has no server available!\n", proxy_type_str(be), be->id);
57 send_log(be, LOG_EMERG, "%s %s has no server available!\n", proxy_type_str(be), be->id);
58}
59
60/* Redistribute pending connections when a server goes down. The number of
61 * connections redistributed is returned.
62 */
63static int redistribute_pending(struct server *s)
64{
65 struct pendconn *pc, *pc_bck, *pc_end;
66 int xferred = 0;
67
68 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
69 struct session *sess = pc->sess;
70 if (sess->be->options & PR_O_REDISP) {
71 /* The REDISP option was specified. We will ignore
72 * cookie and force to balance or use the dispatcher.
73 */
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +010074
75 sess->srv->redispatches++;
76 sess->be->redispatches++;
77
Willy Tarreau48494c02007-11-30 10:41:39 +010078 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +010079 sess->flags |= SN_REDISP;
80
Willy Tarreau48494c02007-11-30 10:41:39 +010081 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
82 http_flush_cookie_flags(&sess->txn);
83 pendconn_free(pc);
84 task_wakeup(sess->task);
85 xferred++;
86 }
87 }
88 return xferred;
89}
90
91/* Check for pending connections at the backend, and assign some of them to
92 * the server coming up. The server's weight is checked before being assigned
93 * connections it may not be able to handle. The total number of transferred
94 * connections is returned.
95 */
96static int check_for_pending(struct server *s)
97{
98 int xferred;
99
100 if (!s->eweight)
101 return 0;
102
103 for (xferred = 0; !s->maxconn || xferred < srv_dynamic_maxconn(s); xferred++) {
104 struct session *sess;
105 struct pendconn *p;
106
107 p = pendconn_from_px(s->proxy);
108 if (!p)
109 break;
110 p->sess->srv = s;
111 sess = p->sess;
112 pendconn_free(p);
113 task_wakeup(sess->task);
114 }
115 return xferred;
116}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200117
118/* Sets server <s> down, notifies by all available means, recounts the
119 * remaining servers on the proxy and transfers queued sessions whenever
Willy Tarreau5af3a692007-07-24 23:32:33 +0200120 * possible to other servers. It automatically recomputes the number of
121 * servers, but not the map.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200122 */
Willy Tarreau83749182007-04-15 20:56:27 +0200123static void set_server_down(struct server *s)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200124{
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100125 struct server *srv;
126 struct chunk msg;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200127 int xferred;
128
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100129 if (s->health == s->rise || s->tracked) {
Willy Tarreau48494c02007-11-30 10:41:39 +0100130 int srv_was_paused = s->state & SRV_GOINGDOWN;
Krzysztof Oledzki85130942007-10-22 16:21:10 +0200131
132 s->last_change = now.tv_sec;
Willy Tarreau48494c02007-11-30 10:41:39 +0100133 s->state &= ~(SRV_RUNNING | SRV_GOINGDOWN);
Willy Tarreaub625a082007-11-26 01:15:43 +0100134 s->proxy->lbprm.set_server_status_down(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200135
136 /* we might have sessions queued on this server and waiting for
137 * a connection. Those which are redispatchable will be queued
138 * to another server or to the proxy itself.
139 */
Willy Tarreau48494c02007-11-30 10:41:39 +0100140 xferred = redistribute_pending(s);
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100141
142 msg.len = 0;
143 msg.str = trash;
144
145 chunk_printf(&msg, sizeof(trash),
146 "%sServer %s/%s is DOWN", s->state & SRV_BACKUP ? "Backup " : "",
147 s->proxy->id, s->id);
148
149 if (s->tracked)
150 chunk_printf(&msg, sizeof(trash), " via %s/%s",
151 s->tracked->proxy->id, s->tracked->id);
152
153 chunk_printf(&msg, sizeof(trash), ". %d active and %d backup servers left.%s"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200154 " %d sessions active, %d requeued, %d remaining in queue.\n",
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100155 s->proxy->srv_act, s->proxy->srv_bck,
Willy Tarreaubaaee002006-06-26 02:48:02 +0200156 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
157 s->cur_sess, xferred, s->nbpend);
158
159 Warning("%s", trash);
Krzysztof Oledzki85130942007-10-22 16:21:10 +0200160
Willy Tarreau48494c02007-11-30 10:41:39 +0100161 /* we don't send an alert if the server was previously paused */
162 if (srv_was_paused)
163 send_log(s->proxy, LOG_NOTICE, "%s", trash);
164 else
165 send_log(s->proxy, LOG_ALERT, "%s", trash);
Krzysztof Oledzki85130942007-10-22 16:21:10 +0200166
Willy Tarreau48494c02007-11-30 10:41:39 +0100167 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
168 set_backend_down(s->proxy);
169
Willy Tarreaubaaee002006-06-26 02:48:02 +0200170 s->down_trans++;
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100171
172 if (s->state && SRV_CHECKED)
173 for(srv = s->tracknext; srv; srv = srv->tracknext)
174 set_server_down(srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200175 }
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100176
Willy Tarreaubaaee002006-06-26 02:48:02 +0200177 s->health = 0; /* failure */
178}
179
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100180static void set_server_up(struct server *s) {
181
182 struct server *srv;
183 struct chunk msg;
184 int xferred;
185
186 if (s->health == s->rise || s->tracked) {
187 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
188 if (s->proxy->last_change < now.tv_sec) // ignore negative times
189 s->proxy->down_time += now.tv_sec - s->proxy->last_change;
190 s->proxy->last_change = now.tv_sec;
191 }
192
193 if (s->last_change < now.tv_sec) // ignore negative times
194 s->down_time += now.tv_sec - s->last_change;
195
196 s->last_change = now.tv_sec;
197 s->state |= SRV_RUNNING;
198
199 if (s->slowstart > 0) {
200 s->state |= SRV_WARMINGUP;
201 if (s->proxy->lbprm.algo & BE_LB_PROP_DYN) {
202 /* For dynamic algorithms, start at the first step of the weight,
203 * without multiplying by BE_WEIGHT_SCALE.
204 */
205 s->eweight = s->uweight;
206 if (s->proxy->lbprm.update_server_eweight)
207 s->proxy->lbprm.update_server_eweight(s);
208 }
209 }
210 s->proxy->lbprm.set_server_status_up(s);
211
212 /* check if we can handle some connections queued at the proxy. We
213 * will take as many as we can handle.
214 */
215 xferred = check_for_pending(s);
216
217 msg.len = 0;
218 msg.str = trash;
219
220 chunk_printf(&msg, sizeof(trash),
221 "%sServer %s/%s is UP", s->state & SRV_BACKUP ? "Backup " : "",
222 s->proxy->id, s->id);
223
224 if (s->tracked)
225 chunk_printf(&msg, sizeof(trash), " via %s/%s",
226 s->tracked->proxy->id, s->tracked->id);
227
228 chunk_printf(&msg, sizeof(trash), ". %d active and %d backup servers online.%s"
229 " %d sessions requeued, %d total in queue.\n",
230 s->proxy->srv_act, s->proxy->srv_bck,
231 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
232 s->cur_sess, xferred, s->nbpend);
233
234 Warning("%s", trash);
235 send_log(s->proxy, LOG_NOTICE, "%s", trash);
236
237 if (s->state && SRV_CHECKED)
238 for(srv = s->tracknext; srv; srv = srv->tracknext)
239 set_server_up(srv);
240 }
241
242 if (s->health >= s->rise)
243 s->health = s->rise + s->fall - 1; /* OK now */
244
245}
246
247static void set_server_disabled(struct server *s) {
248
249 struct server *srv;
250 struct chunk msg;
251 int xferred;
252
253 s->state |= SRV_GOINGDOWN;
254 s->proxy->lbprm.set_server_status_down(s);
255
256 /* we might have sessions queued on this server and waiting for
257 * a connection. Those which are redispatchable will be queued
258 * to another server or to the proxy itself.
259 */
260 xferred = redistribute_pending(s);
261
262 msg.len = 0;
263 msg.str = trash;
264
265 chunk_printf(&msg, sizeof(trash),
266 "Load-balancing on %sServer %s/%s is disabled",
267 s->state & SRV_BACKUP ? "Backup " : "",
268 s->proxy->id, s->id);
269
270 if (s->tracked)
271 chunk_printf(&msg, sizeof(trash), " via %s/%s",
272 s->tracked->proxy->id, s->tracked->id);
273
274
275 chunk_printf(&msg, sizeof(trash),". %d active and %d backup servers online.%s"
276 " %d sessions requeued, %d total in queue.\n",
277 s->proxy->srv_act, s->proxy->srv_bck,
278 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
279 xferred, s->nbpend);
280
281 Warning("%s", trash);
282
283 send_log(s->proxy, LOG_NOTICE, "%s", trash);
284
285 if (!s->proxy->srv_bck && !s->proxy->srv_act)
286 set_backend_down(s->proxy);
287
288 if (s->state && SRV_CHECKED)
289 for(srv = s->tracknext; srv; srv = srv->tracknext)
290 set_server_disabled(srv);
291}
292
293static void set_server_enabled(struct server *s) {
294
295 struct server *srv;
296 struct chunk msg;
297 int xferred;
298
299 s->state &= ~SRV_GOINGDOWN;
300 s->proxy->lbprm.set_server_status_up(s);
301
302 /* check if we can handle some connections queued at the proxy. We
303 * will take as many as we can handle.
304 */
305 xferred = check_for_pending(s);
306
307 msg.len = 0;
308 msg.str = trash;
309
310 chunk_printf(&msg, sizeof(trash),
311 "Load-balancing on %sServer %s/%s is enabled again",
312 s->state & SRV_BACKUP ? "Backup " : "",
313 s->proxy->id, s->id);
314
315 if (s->tracked)
316 chunk_printf(&msg, sizeof(trash), " via %s/%s",
317 s->tracked->proxy->id, s->tracked->id);
318
319 chunk_printf(&msg, sizeof(trash), ". %d active and %d backup servers online.%s"
320 " %d sessions requeued, %d total in queue.\n",
321 s->proxy->srv_act, s->proxy->srv_bck,
322 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
323 xferred, s->nbpend);
324
325 Warning("%s", trash);
326 send_log(s->proxy, LOG_NOTICE, "%s", trash);
327
328 if (s->state && SRV_CHECKED)
329 for(srv = s->tracknext; srv; srv = srv->tracknext)
330 set_server_enabled(srv);
331}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200332
333/*
334 * This function is used only for server health-checks. It handles
335 * the connection acknowledgement. If the proxy requires HTTP health-checks,
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100336 * it sends the request. In other cases, it fills s->result with SRV_CHK_*.
Willy Tarreau83749182007-04-15 20:56:27 +0200337 * The function itself returns 0 if it needs some polling before being called
338 * again, otherwise 1.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200339 */
Willy Tarreau83749182007-04-15 20:56:27 +0200340static int event_srv_chk_w(int fd)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200341{
Willy Tarreau6996e152007-04-30 14:37:43 +0200342 __label__ out_wakeup, out_nowake, out_poll, out_error;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200343 struct task *t = fdtab[fd].owner;
344 struct server *s = t->context;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200345
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100346 //fprintf(stderr, "event_srv_chk_w, state=%ld\n", unlikely(fdtab[fd].state));
Willy Tarreau6996e152007-04-30 14:37:43 +0200347 if (unlikely(fdtab[fd].state == FD_STERROR || (fdtab[fd].ev & FD_POLL_ERR)))
348 goto out_error;
349
350 /* here, we know that the connection is established */
Willy Tarreau83749182007-04-15 20:56:27 +0200351
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100352 if (!(s->result & SRV_CHK_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200353 /* we don't want to mark 'UP' a server on which we detected an error earlier */
Willy Tarreauf3c69202006-07-09 16:42:34 +0200354 if ((s->proxy->options & PR_O_HTTP_CHK) ||
Willy Tarreau23677902007-05-08 23:50:35 +0200355 (s->proxy->options & PR_O_SSL3_CHK) ||
356 (s->proxy->options & PR_O_SMTP_CHK)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200357 int ret;
Willy Tarreauf3c69202006-07-09 16:42:34 +0200358 /* we want to check if this host replies to HTTP or SSLv3 requests
Willy Tarreaubaaee002006-06-26 02:48:02 +0200359 * so we'll send the request, and won't wake the checker up now.
360 */
Willy Tarreauf3c69202006-07-09 16:42:34 +0200361
362 if (s->proxy->options & PR_O_SSL3_CHK) {
363 /* SSL requires that we put Unix time in the request */
364 int gmt_time = htonl(now.tv_sec);
365 memcpy(s->proxy->check_req + 11, &gmt_time, 4);
366 }
367
Willy Tarreaubaaee002006-06-26 02:48:02 +0200368#ifndef MSG_NOSIGNAL
369 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
370#else
371 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
372#endif
373 if (ret == s->proxy->check_len) {
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100374 /* we allow up to <timeout.check> if nonzero for a responce */
375 //fprintf(stderr, "event_srv_chk_w, ms=%lu\n", __tv_to_ms(&s->proxy->timeout.check));
376 tv_add_ifset(&t->expire, &now, &s->proxy->timeout.check);
377
Willy Tarreauf161a342007-04-08 16:59:42 +0200378 EV_FD_SET(fd, DIR_RD); /* prepare for reading reply */
Willy Tarreau83749182007-04-15 20:56:27 +0200379 goto out_nowake;
380 }
Willy Tarreau6996e152007-04-30 14:37:43 +0200381 else if (ret == 0 || errno == EAGAIN)
382 goto out_poll;
383 else
384 goto out_error;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200385 }
386 else {
Willy Tarreau6996e152007-04-30 14:37:43 +0200387 /* We have no data to send to check the connection, and
388 * getsockopt() will not inform us whether the connection
389 * is still pending. So we'll reuse connect() to check the
390 * state of the socket. This has the advantage of givig us
391 * the following info :
392 * - error
393 * - connecting (EALREADY, EINPROGRESS)
394 * - connected (EISCONN, 0)
395 */
396
397 struct sockaddr_in sa;
398
399 sa = (s->check_addr.sin_addr.s_addr) ? s->check_addr : s->addr;
400 sa.sin_port = htons(s->check_port);
401
402 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == 0)
403 errno = 0;
404
405 if (errno == EALREADY || errno == EINPROGRESS)
406 goto out_poll;
407
408 if (errno && errno != EISCONN)
409 goto out_error;
410
Willy Tarreaubaaee002006-06-26 02:48:02 +0200411 /* good TCP connection is enough */
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100412 s->result |= SRV_CHK_RUNNING;
Willy Tarreau6996e152007-04-30 14:37:43 +0200413 goto out_wakeup;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200414 }
415 }
Willy Tarreau83749182007-04-15 20:56:27 +0200416 out_wakeup:
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200417 task_wakeup(t);
Willy Tarreau83749182007-04-15 20:56:27 +0200418 out_nowake:
419 EV_FD_CLR(fd, DIR_WR); /* nothing more to write */
Willy Tarreaud6f087e2008-01-18 17:20:13 +0100420 fdtab[fd].ev &= ~FD_POLL_OUT;
Willy Tarreau83749182007-04-15 20:56:27 +0200421 return 1;
Willy Tarreau6996e152007-04-30 14:37:43 +0200422 out_poll:
423 /* The connection is still pending. We'll have to poll it
424 * before attempting to go further. */
Willy Tarreaud6f087e2008-01-18 17:20:13 +0100425 fdtab[fd].ev &= ~FD_POLL_OUT;
Willy Tarreau6996e152007-04-30 14:37:43 +0200426 return 0;
427 out_error:
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100428 s->result |= SRV_CHK_ERROR;
Willy Tarreau6996e152007-04-30 14:37:43 +0200429 fdtab[fd].state = FD_STERROR;
430 goto out_wakeup;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200431}
432
433
434/*
Willy Tarreauf3c69202006-07-09 16:42:34 +0200435 * This function is used only for server health-checks. It handles the server's
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100436 * reply to an HTTP request or SSL HELLO. It sets s->result to SRV_CHK_RUNNING
437 * if an HTTP server replies HTTP 2xx or 3xx (valid responses), if an SMTP
438 * server returns 2xx, or if an SSL server returns at least 5 bytes in response
439 * to an SSL HELLO (the principle is that this is enough to distinguish between
440 * an SSL server and a pure TCP relay). All other cases will set s->result to
441 * SRV_CHK_ERROR. The function returns 0 if it needs to be called again after
442 * some polling, otherwise non-zero..
Willy Tarreaubaaee002006-06-26 02:48:02 +0200443 */
Willy Tarreau83749182007-04-15 20:56:27 +0200444static int event_srv_chk_r(int fd)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200445{
Willy Tarreau83749182007-04-15 20:56:27 +0200446 __label__ out_wakeup;
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100447 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200448 struct task *t = fdtab[fd].owner;
449 struct server *s = t->context;
450 int skerr;
451 socklen_t lskerr = sizeof(skerr);
452
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100453 len = -1;
Willy Tarreau83749182007-04-15 20:56:27 +0200454
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100455 if (unlikely((s->result & SRV_CHK_ERROR) ||
456 (fdtab[fd].state == FD_STERROR) ||
Willy Tarreau83749182007-04-15 20:56:27 +0200457 (fdtab[fd].ev & FD_POLL_ERR) ||
458 (getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1) ||
459 (skerr != 0))) {
460 /* in case of TCP only, this tells us if the connection failed */
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100461 s->result |= SRV_CHK_ERROR;
Willy Tarreau83749182007-04-15 20:56:27 +0200462 goto out_wakeup;
463 }
464
Willy Tarreaubaaee002006-06-26 02:48:02 +0200465#ifndef MSG_NOSIGNAL
Krzysztof Oledzki6b3f8b42007-10-11 18:41:08 +0200466 len = recv(fd, trash, sizeof(trash), 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200467#else
Willy Tarreau83749182007-04-15 20:56:27 +0200468 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
469 * but the connection was closed on the remote end. Fortunately, recv still
470 * works correctly and we don't need to do the getsockopt() on linux.
471 */
Krzysztof Oledzki6b3f8b42007-10-11 18:41:08 +0200472 len = recv(fd, trash, sizeof(trash), MSG_NOSIGNAL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200473#endif
Willy Tarreau83749182007-04-15 20:56:27 +0200474 if (unlikely(len < 0 && errno == EAGAIN)) {
475 /* we want some polling to happen first */
Willy Tarreaud6f087e2008-01-18 17:20:13 +0100476 fdtab[fd].ev &= ~FD_POLL_IN;
Willy Tarreau83749182007-04-15 20:56:27 +0200477 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200478 }
479
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100480 /* Note: the response will only be accepted if read at once */
481 if (s->proxy->options & PR_O_HTTP_CHK) {
482 /* Check if the server speaks HTTP 1.X */
483 if ((len < strlen("HTTP/1.0 000\r")) ||
484 (memcmp(trash, "HTTP/1.", 7) != 0)) {
485 s->result |= SRV_CHK_ERROR;
486 goto out_wakeup;
487 }
488
489 /* check the reply : HTTP/1.X 2xx and 3xx are OK */
490 if (trash[9] == '2' || trash[9] == '3')
491 s->result |= SRV_CHK_RUNNING;
Willy Tarreau48494c02007-11-30 10:41:39 +0100492 else if ((s->proxy->options & PR_O_DISABLE404) &&
493 (s->state & SRV_RUNNING) &&
494 (memcmp(&trash[9], "404", 3) == 0)) {
495 /* 404 may be accepted as "stopping" only if the server was up */
496 s->result |= SRV_CHK_RUNNING | SRV_CHK_DISABLE;
497 }
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100498 else
499 s->result |= SRV_CHK_ERROR;
500 }
501 else if (s->proxy->options & PR_O_SSL3_CHK) {
502 /* Check for SSLv3 alert or handshake */
503 if ((len >= 5) && (trash[0] == 0x15 || trash[0] == 0x16))
504 s->result |= SRV_CHK_RUNNING;
505 else
506 s->result |= SRV_CHK_ERROR;
Willy Tarreau6996e152007-04-30 14:37:43 +0200507 }
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100508 else if (s->proxy->options & PR_O_SMTP_CHK) {
509 /* Check for SMTP code 2xx (should be 250) */
510 if ((len >= 3) && (trash[0] == '2'))
511 s->result |= SRV_CHK_RUNNING;
512 else
513 s->result |= SRV_CHK_ERROR;
Willy Tarreau6996e152007-04-30 14:37:43 +0200514 }
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100515 else {
516 /* other checks are valid if the connection succeeded anyway */
517 s->result |= SRV_CHK_RUNNING;
Willy Tarreau23677902007-05-08 23:50:35 +0200518 }
Willy Tarreau83749182007-04-15 20:56:27 +0200519
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100520 out_wakeup:
521 if (s->result & SRV_CHK_ERROR)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200522 fdtab[fd].state = FD_STERROR;
523
Willy Tarreauf161a342007-04-08 16:59:42 +0200524 EV_FD_CLR(fd, DIR_RD);
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200525 task_wakeup(t);
Willy Tarreaud6f087e2008-01-18 17:20:13 +0100526 fdtab[fd].ev &= ~FD_POLL_IN;
Willy Tarreau83749182007-04-15 20:56:27 +0200527 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200528}
529
530/*
531 * manages a server health-check. Returns
532 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
533 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200534void process_chk(struct task *t, struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200535{
Willy Tarreau7317eb52007-05-09 00:54:10 +0200536 __label__ new_chk, out;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200537 struct server *s = t->context;
538 struct sockaddr_in sa;
539 int fd;
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200540 int rv;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200541
542 //fprintf(stderr, "process_chk: task=%p\n", t);
543
544 new_chk:
545 fd = s->curfd;
546 if (fd < 0) { /* no check currently running */
547 //fprintf(stderr, "process_chk: 2\n");
Willy Tarreaua8b55e32007-05-13 16:08:19 +0200548 if (!tv_isle(&t->expire, &now)) { /* not good time yet */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200549 task_queue(t); /* restore t to its place in the task list */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200550 *next = t->expire;
Willy Tarreau7317eb52007-05-09 00:54:10 +0200551 goto out;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200552 }
553
554 /* we don't send any health-checks when the proxy is stopped or when
555 * the server should not be checked.
556 */
557 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
Willy Tarreaua8b55e32007-05-13 16:08:19 +0200558 while (tv_isle(&t->expire, &now))
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200559 tv_ms_add(&t->expire, &t->expire, s->inter);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200560 task_queue(t); /* restore t to its place in the task list */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200561 *next = t->expire;
Willy Tarreau7317eb52007-05-09 00:54:10 +0200562 goto out;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200563 }
564
565 /* we'll initiate a new check */
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100566 s->result = SRV_CHK_UNKNOWN; /* no result yet */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200567 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
568 if ((fd < global.maxsock) &&
569 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
570 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
571 //fprintf(stderr, "process_chk: 3\n");
572
Willy Tarreau9edd1612007-10-18 18:07:48 +0200573 if (s->proxy->options & PR_O_TCP_NOLING) {
574 /* We don't want to useless data */
575 setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
576 }
Willy Tarreau2ea3abb2007-03-25 16:45:16 +0200577
Willy Tarreau0f03c6f2007-03-25 20:46:19 +0200578 if (s->check_addr.sin_addr.s_addr)
579 /* we'll connect to the check addr specified on the server */
Willy Tarreau2ea3abb2007-03-25 16:45:16 +0200580 sa = s->check_addr;
Willy Tarreau2ea3abb2007-03-25 16:45:16 +0200581 else
Willy Tarreau0f03c6f2007-03-25 20:46:19 +0200582 /* we'll connect to the addr on the server */
Willy Tarreau2ea3abb2007-03-25 16:45:16 +0200583 sa = s->addr;
Willy Tarreau0f03c6f2007-03-25 20:46:19 +0200584
Willy Tarreaubaaee002006-06-26 02:48:02 +0200585 /* we'll connect to the check port on the server */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200586 sa.sin_port = htons(s->check_port);
587
588 /* allow specific binding :
589 * - server-specific at first
590 * - proxy-specific next
591 */
592 if (s->state & SRV_BIND_SRC) {
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100593 struct sockaddr_in *remote = NULL;
594 int ret, flags = 0;
Willy Tarreau163c5322006-11-14 16:18:41 +0100595
Willy Tarreaucf1d5722008-02-14 20:28:18 +0100596#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100597 if ((s->state & SRV_TPROXY_MASK) == SRV_TPROXY_ADDR) {
598 remote = (struct sockaddr_in *)&s->tproxy_addr;
599 flags = 3;
600 }
Willy Tarreaucf1d5722008-02-14 20:28:18 +0100601#endif
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100602 ret = tcpv4_bind_socket(fd, flags, &s->source_addr, remote);
603 if (ret) {
604 s->result |= SRV_CHK_ERROR;
605 switch (ret) {
606 case 1:
607 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
608 s->proxy->id, s->id);
609 break;
610 case 2:
Willy Tarreau163c5322006-11-14 16:18:41 +0100611 Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
612 s->proxy->id, s->id);
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100613 break;
Willy Tarreau163c5322006-11-14 16:18:41 +0100614 }
615 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200616 }
617 else if (s->proxy->options & PR_O_BIND_SRC) {
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100618 struct sockaddr_in *remote = NULL;
619 int ret, flags = 0;
620
Willy Tarreaucf1d5722008-02-14 20:28:18 +0100621#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
Willy Tarreau163c5322006-11-14 16:18:41 +0100622 if ((s->proxy->options & PR_O_TPXY_MASK) == PR_O_TPXY_ADDR) {
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100623 remote = (struct sockaddr_in *)&s->proxy->tproxy_addr;
624 flags = 3;
625 }
Willy Tarreaucf1d5722008-02-14 20:28:18 +0100626#endif
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100627 ret = tcpv4_bind_socket(fd, flags, &s->proxy->source_addr, remote);
628 if (ret) {
629 s->result |= SRV_CHK_ERROR;
630 switch (ret) {
631 case 1:
632 Alert("Cannot bind to source address before connect() for %s '%s'. Aborting.\n",
633 proxy_type_str(s->proxy), s->proxy->id);
634 break;
635 case 2:
Willy Tarreau2b5652f2006-12-31 17:46:05 +0100636 Alert("Cannot bind to tproxy source address before connect() for %s '%s'. Aborting.\n",
637 proxy_type_str(s->proxy), s->proxy->id);
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100638 break;
Willy Tarreau163c5322006-11-14 16:18:41 +0100639 }
640 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200641 }
642
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100643 if (s->result == SRV_CHK_UNKNOWN) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200644 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100645 struct timeval tv_con;
646
Willy Tarreaubaaee002006-06-26 02:48:02 +0200647 /* OK, connection in progress or established */
648
649 //fprintf(stderr, "process_chk: 4\n");
650
651 s->curfd = fd; /* that's how we know a test is in progress ;-) */
Willy Tarreau7a966482007-04-15 10:58:02 +0200652 fd_insert(fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200653 fdtab[fd].owner = t;
Willy Tarreau54469402006-07-29 16:59:06 +0200654 fdtab[fd].cb[DIR_RD].f = &event_srv_chk_r;
655 fdtab[fd].cb[DIR_RD].b = NULL;
656 fdtab[fd].cb[DIR_WR].f = &event_srv_chk_w;
657 fdtab[fd].cb[DIR_WR].b = NULL;
Willy Tarreaue94ebd02007-10-09 17:14:37 +0200658 fdtab[fd].peeraddr = (struct sockaddr *)&sa;
659 fdtab[fd].peerlen = sizeof(sa);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200660 fdtab[fd].state = FD_STCONN; /* connection in progress */
Willy Tarreauf161a342007-04-08 16:59:42 +0200661 EV_FD_SET(fd, DIR_WR); /* for connect status */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200662#ifdef DEBUG_FULL
Willy Tarreauf161a342007-04-08 16:59:42 +0200663 assert (!EV_FD_ISSET(fd, DIR_RD));
Willy Tarreaubaaee002006-06-26 02:48:02 +0200664#endif
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100665 //fprintf(stderr, "process_chk: 4+, %lu\n", __tv_to_ms(&s->proxy->timeout.connect));
666 /* we allow up to min(inter, timeout.connect) for a connection
667 * to establish but only when timeout.check is set
668 * as it may be to short for a full check otherwise
669 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200670 tv_ms_add(&t->expire, &now, s->inter);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100671
Willy Tarreau60548192008-02-17 11:34:10 +0100672 if (tv_isset(&s->proxy->timeout.check) && tv_isset(&s->proxy->timeout.connect)) {
673 tv_add(&tv_con, &now, &s->proxy->timeout.connect);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100674 tv_bound(&t->expire, &tv_con);
Willy Tarreau60548192008-02-17 11:34:10 +0100675 }
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100676
Willy Tarreaubaaee002006-06-26 02:48:02 +0200677 task_queue(t); /* restore t to its place in the task list */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200678 *next = t->expire;
Willy Tarreau8eee9c82007-05-14 03:40:11 +0200679 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200680 }
681 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100682 s->result |= SRV_CHK_ERROR; /* a real error */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200683 }
684 }
685 }
686 close(fd); /* socket creation error */
687 }
688
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100689 if (s->result == SRV_CHK_UNKNOWN) { /* nothing done */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200690 //fprintf(stderr, "process_chk: 6\n");
Willy Tarreaua8b55e32007-05-13 16:08:19 +0200691 while (tv_isle(&t->expire, &now))
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200692 tv_ms_add(&t->expire, &t->expire, s->inter);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200693 goto new_chk; /* may be we should initialize a new check */
694 }
695
696 /* here, we have seen a failure */
697 if (s->health > s->rise) {
698 s->health--; /* still good */
699 s->failed_checks++;
700 }
701 else
702 set_server_down(s);
703
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100704 //fprintf(stderr, "process_chk: 7, %lu\n", __tv_to_ms(&s->proxy->timeout.connect));
705 /* we allow up to min(inter, timeout.connect) for a connection
706 * to establish but only when timeout.check is set
707 * as it may be to short for a full check otherwise
708 */
709 while (tv_isle(&t->expire, &now)) {
710 struct timeval tv_con;
711
712 tv_add(&tv_con, &t->expire, &s->proxy->timeout.connect);
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200713 tv_ms_add(&t->expire, &t->expire, s->inter);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100714
715 if (tv_isset(&s->proxy->timeout.check))
716 tv_bound(&t->expire, &tv_con);
717 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200718 goto new_chk;
719 }
720 else {
721 //fprintf(stderr, "process_chk: 8\n");
722 /* there was a test running */
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100723 if ((s->result & (SRV_CHK_ERROR|SRV_CHK_RUNNING)) == SRV_CHK_RUNNING) { /* good server detected */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200724 //fprintf(stderr, "process_chk: 9\n");
Krzysztof Oledzki85130942007-10-22 16:21:10 +0200725
Willy Tarreau9909fc12007-11-30 17:42:05 +0100726 if (s->state & SRV_WARMINGUP) {
727 if (now.tv_sec < s->last_change || now.tv_sec >= s->last_change + s->slowstart) {
728 s->state &= ~SRV_WARMINGUP;
729 if (s->proxy->lbprm.algo & BE_LB_PROP_DYN)
730 s->eweight = s->uweight * BE_WEIGHT_SCALE;
731 if (s->proxy->lbprm.update_server_eweight)
732 s->proxy->lbprm.update_server_eweight(s);
733 }
734 else if (s->proxy->lbprm.algo & BE_LB_PROP_DYN) {
735 /* for dynamic algorithms, let's update the weight */
Willy Tarreau5542af62007-12-03 02:04:00 +0100736 s->eweight = (BE_WEIGHT_SCALE * (now.tv_sec - s->last_change) +
737 s->slowstart - 1) / s->slowstart;
Willy Tarreau9909fc12007-11-30 17:42:05 +0100738 s->eweight *= s->uweight;
739 if (s->proxy->lbprm.update_server_eweight)
740 s->proxy->lbprm.update_server_eweight(s);
741 }
742 /* probably that we can refill this server with a bit more connections */
743 check_for_pending(s);
744 }
745
Willy Tarreau48494c02007-11-30 10:41:39 +0100746 /* we may have to add/remove this server from the LB group */
747 if ((s->state & SRV_RUNNING) && (s->proxy->options & PR_O_DISABLE404)) {
748 if ((s->state & SRV_GOINGDOWN) &&
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100749 ((s->result & (SRV_CHK_RUNNING|SRV_CHK_DISABLE)) == SRV_CHK_RUNNING))
750 set_server_enabled(s);
Willy Tarreau48494c02007-11-30 10:41:39 +0100751 else if (!(s->state & SRV_GOINGDOWN) &&
752 ((s->result & (SRV_CHK_RUNNING | SRV_CHK_DISABLE)) ==
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100753 (SRV_CHK_RUNNING | SRV_CHK_DISABLE)))
754 set_server_disabled(s);
Willy Tarreau48494c02007-11-30 10:41:39 +0100755 }
756
Krzysztof Oledzki85130942007-10-22 16:21:10 +0200757 if (s->health < s->rise + s->fall - 1) {
758 s->health++; /* was bad, stays for a while */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200759
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +0100760 set_server_up(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200761 }
762 s->curfd = -1; /* no check running anymore */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200763 fd_delete(fd);
Willy Tarreau44ec0f02007-10-14 23:47:04 +0200764
765 rv = 0;
766 if (global.spread_checks > 0) {
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100767 rv = srv_getinter(s) * global.spread_checks / 100;
Willy Tarreau44ec0f02007-10-14 23:47:04 +0200768 rv -= (int) (2 * rv * (rand() / (RAND_MAX + 1.0)));
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100769 //fprintf(stderr, "process_chk(%p): (%d+/-%d%%) random=%d\n", s, srv_getinter(s), global.spread_checks, rv);
Willy Tarreau44ec0f02007-10-14 23:47:04 +0200770 }
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100771 tv_ms_add(&t->expire, &now, srv_getinter(s) + rv);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200772 goto new_chk;
773 }
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100774 else if ((s->result & SRV_CHK_ERROR) || tv_isle(&t->expire, &now)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200775 //fprintf(stderr, "process_chk: 10\n");
776 /* failure or timeout detected */
777 if (s->health > s->rise) {
778 s->health--; /* still good */
779 s->failed_checks++;
780 }
781 else
782 set_server_down(s);
783 s->curfd = -1;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200784 fd_delete(fd);
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200785
786 rv = 0;
787 if (global.spread_checks > 0) {
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100788 rv = srv_getinter(s) * global.spread_checks / 100;
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200789 rv -= (int) (2 * rv * (rand() / (RAND_MAX + 1.0)));
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100790 //fprintf(stderr, "process_chk(%p): (%d+/-%d%%) random=%d\n", s, srv_getinter(s), global.spread_checks, rv);
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200791 }
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100792 tv_ms_add(&t->expire, &now, srv_getinter(s) + rv);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200793 goto new_chk;
794 }
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100795 /* if result is unknown and there's no timeout, we have to wait again */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200796 }
797 //fprintf(stderr, "process_chk: 11\n");
Willy Tarreauc7dd71a2007-11-30 08:33:21 +0100798 s->result = SRV_CHK_UNKNOWN;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200799 task_queue(t); /* restore t to its place in the task list */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200800 *next = t->expire;
Willy Tarreau7317eb52007-05-09 00:54:10 +0200801 out:
Willy Tarreaud825eef2007-05-12 22:35:00 +0200802 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200803}
804
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200805/*
806 * Start health-check.
807 * Returns 0 if OK, -1 if error, and prints the error in this case.
808 */
809int start_checks() {
810
811 struct proxy *px;
812 struct server *s;
813 struct task *t;
814 int nbchk=0, mininter=0, srvpos=0;
815
Willy Tarreau2c43a1e2007-10-14 23:05:39 +0200816 /* 1- count the checkers to run simultaneously.
817 * We also determine the minimum interval among all of those which
818 * have an interval larger than SRV_CHK_INTER_THRES. This interval
819 * will be used to spread their start-up date. Those which have
820 * a shorter interval will start independantly and will not dictate
821 * too short an interval for all others.
822 */
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200823 for (px = proxy; px; px = px->next) {
824 for (s = px->srv; s; s = s->next) {
825 if (!(s->state & SRV_CHECKED))
826 continue;
827
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100828 if ((srv_getinter(s) >= SRV_CHK_INTER_THRES) &&
829 (!mininter || mininter > srv_getinter(s)))
830 mininter = srv_getinter(s);
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200831
832 nbchk++;
833 }
834 }
835
836 if (!nbchk)
837 return 0;
838
839 srand((unsigned)time(NULL));
840
841 /*
842 * 2- start them as far as possible from each others. For this, we will
843 * start them after their interval set to the min interval divided by
844 * the number of servers, weighted by the server's position in the list.
845 */
846 for (px = proxy; px; px = px->next) {
847 for (s = px->srv; s; s = s->next) {
848 if (!(s->state & SRV_CHECKED))
849 continue;
850
851 if ((t = pool_alloc2(pool2_task)) == NULL) {
852 Alert("Starting [%s:%s] check: out of memory.\n", px->id, s->id);
853 return -1;
854 }
855
856 t->wq = NULL;
857 t->qlist.p = NULL;
858 t->state = TASK_IDLE;
859 t->process = process_chk;
860 t->context = s;
861
862 /* check this every ms */
Willy Tarreau2c43a1e2007-10-14 23:05:39 +0200863 tv_ms_add(&t->expire, &now,
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100864 ((mininter && mininter >= srv_getinter(s)) ? mininter : srv_getinter(s)) * srvpos / nbchk);
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +0200865 task_queue(t);
866
867 srvpos++;
868 }
869 }
870 return 0;
871}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200872
873/*
874 * Local variables:
875 * c-indent-level: 8
876 * c-basic-offset: 8
877 * End:
878 */