blob: 34cb0bb76db410df9eed54b8488c6813582cb3d6 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau726618c2006-01-29 22:42:06 +01003 * 2000-2006 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
willy tarreau0f7af912005-12-17 12:21:26 +010055#include <syslog.h>
willy tarreau77bc8542005-12-18 01:31:43 +010056
57#ifdef USE_PCRE
58#include <pcre.h>
59#include <pcreposix.h>
60#else
61#include <regex.h>
62#endif
63
willy tarreaua1598082005-12-17 13:08:06 +010064#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010065#include <linux/netfilter_ipv4.h>
66#endif
willy tarreau0f7af912005-12-17 12:21:26 +010067
willy tarreau12350152005-12-18 01:03:27 +010068#if defined(__dietlibc__)
69#include <strings.h>
70#endif
71
willy tarreau1c2ad212005-12-18 01:11:29 +010072#if defined(ENABLE_POLL)
73#include <sys/poll.h>
74#endif
75
76#if defined(ENABLE_EPOLL)
77#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010078#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010079#else
80#include "include/epoll.h"
81#endif
82#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010083
willy tarreau779dc892006-03-19 19:32:29 +010084#ifdef DEBUG_FULL
85#include <assert.h>
86#endif
87
willy tarreau9e138862006-05-14 23:06:28 +020088#include <include/base64.h>
89#include <include/uri_auth.h>
willy tarreau598da412005-12-18 01:07:29 +010090#include "include/appsession.h"
willy tarreau18a957c2006-04-12 19:26:23 +020091#include "include/mini-clist.h"
willy tarreau12350152005-12-18 01:03:27 +010092
willy tarreaubfad5742006-03-23 14:19:11 +010093#ifndef HAPROXY_VERSION
willy tarreau7e6328d2006-05-21 23:26:20 +020094#define HAPROXY_VERSION "1.2.14"
willy tarreaubfad5742006-03-23 14:19:11 +010095#endif
96
97#ifndef HAPROXY_DATE
willy tarreau7e6328d2006-05-21 23:26:20 +020098#define HAPROXY_DATE "2006/05/21"
willy tarreaubfad5742006-03-23 14:19:11 +010099#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100100
101/* this is for libc5 for example */
102#ifndef TCP_NODELAY
103#define TCP_NODELAY 1
104#endif
105
106#ifndef SHUT_RD
107#define SHUT_RD 0
108#endif
109
110#ifndef SHUT_WR
111#define SHUT_WR 1
112#endif
113
willy tarreau0174f312005-12-18 01:02:42 +0100114/*
115 * BUFSIZE defines the size of a read and write buffer. It is the maximum
116 * amount of bytes which can be stored by the proxy for each session. However,
117 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
118 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
119 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
120 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
121 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
122 */
123#ifndef BUFSIZE
124#define BUFSIZE 16384
125#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100126
127// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100128#ifndef MAXREWRITE
129#define MAXREWRITE (BUFSIZE / 2)
130#endif
131
willy tarreau9fe663a2005-12-17 13:02:59 +0100132#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100133#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100134
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100136#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100137
willy tarreaue39cd132005-12-17 13:00:18 +0100138// max # of added headers per request
139#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100140
141// max # of matches per regexp
142#define MAX_MATCH 10
143
willy tarreau0174f312005-12-18 01:02:42 +0100144// cookie delimitor in "prefix" mode. This character is inserted between the
145// persistence cookie and the original value. The '~' is allowed by RFC2965,
146// and should not be too common in server names.
147#ifndef COOKIE_DELIM
148#define COOKIE_DELIM '~'
149#endif
150
willy tarreau0f7af912005-12-17 12:21:26 +0100151#define CONN_RETRIES 3
152
willy tarreau5cbea6f2005-12-17 12:48:26 +0100153#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100154#define DEF_CHKINTR 2000
155#define DEF_FALLTIME 3
156#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100157#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100158
Willy TARREAU13032e72006-03-12 17:31:45 +0100159/* Default connections limit.
160 *
161 * A system limit can be enforced at build time in order to avoid using haproxy
162 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
163 * absolute limit accepted by the system. If the configuration specifies a
164 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
165 * emitted. The only way to override this limit will be to set it via the
166 * command-line '-n' argument.
167 */
168#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100169#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100170#else
171#define DEFAULT_MAXCONN SYSTEM_MAXCONN
172#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100173
willy tarreaue0331262006-05-15 03:02:46 +0200174#ifdef CONFIG_PRODUCT_NAME
175#define PRODUCT_NAME CONFIG_PRODUCT_NAME
176#else
177#define PRODUCT_NAME "HAProxy"
178#endif
179
willy tarreau0f7af912005-12-17 12:21:26 +0100180/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
181#define INTBITS 5
182
183/* show stats this every millisecond, 0 to disable */
184#ifndef STATTIME
185#define STATTIME 2000
186#endif
187
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188/* this reduces the number of calls to select() by choosing appropriate
189 * sheduler precision in milliseconds. It should be near the minimum
190 * time that is needed by select() to collect all events. All timeouts
191 * are rounded up by adding this value prior to pass it to select().
192 */
193#define SCHEDULER_RESOLUTION 9
194
willy tarreaub952e1d2005-12-18 01:31:20 +0100195#define TIME_ETERNITY -1
196/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100197#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
198#define SETNOW(a) (*a=now)
199
willy tarreau9da061b2005-12-17 12:29:56 +0100200/****** string-specific macros and functions ******/
201/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
202#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
203
204/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
205#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
206
willy tarreau0174f312005-12-18 01:02:42 +0100207/* returns 1 only if only zero or one bit is set in X, which means that X is a
208 * power of 2, and 0 otherwise */
209#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100210/*
211 * copies at most <size-1> chars from <src> to <dst>. Last char is always
212 * set to 0, unless <size> is 0. The number of chars copied is returned
213 * (excluding the terminating zero).
214 * This code has been optimized for size and speed : on x86, it's 45 bytes
215 * long, uses only registers, and consumes only 4 cycles per char.
216 */
willy tarreau750a4722005-12-17 13:21:24 +0100217int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100218 char *orig = dst;
219 if (size) {
220 while (--size && (*dst = *src)) {
221 src++; dst++;
222 }
223 *dst = 0;
224 }
225 return dst - orig;
226}
willy tarreau9da061b2005-12-17 12:29:56 +0100227
willy tarreau4302f492005-12-18 01:00:37 +0100228/*
willy tarreaucb406512006-05-18 00:52:35 +0200229 * This function simply returns a statically allocated string containing
230 * the ascii representation for number 'n' in decimal.
231 */
232char *ultoa(unsigned long n) {
233 /* enough to store 2^63=18446744073709551615 */
234 static char itoa_str[21];
235 char *pos;
236
237 pos = itoa_str + sizeof(itoa_str) - 1;
238 *pos-- = '\0';
239
240 do {
241 *pos-- = '0' + n % 10;
242 n /= 10;
243 } while (n && pos >= itoa_str);
244 return pos + 1;
245}
246
247/*
willy tarreau4302f492005-12-18 01:00:37 +0100248 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
249 * dynamically allocated. In the first case, <__pool> is updated to point to
250 * the next element in the list.
251 */
252#define pool_alloc_from(__pool, __len) ({ \
253 void *__p; \
254 if ((__p = (__pool)) == NULL) \
255 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
256 else { \
257 __pool = *(void **)(__pool); \
258 } \
259 __p; \
260})
261
262/*
263 * Puts a memory area back to the corresponding pool.
264 * Items are chained directly through a pointer that
265 * is written in the beginning of the memory area, so
266 * there's no need for any carrier cell. This implies
267 * that each memory area is at least as big as one
268 * pointer.
269 */
270#define pool_free_to(__pool, __ptr) ({ \
271 *(void **)(__ptr) = (void *)(__pool); \
272 __pool = (void *)(__ptr); \
273})
274
275
willy tarreau0f7af912005-12-17 12:21:26 +0100276#define MEM_OPTIM
277#ifdef MEM_OPTIM
278/*
279 * Returns a pointer to type <type> taken from the
280 * pool <pool_type> or dynamically allocated. In the
281 * first case, <pool_type> is updated to point to the
282 * next element in the list.
283 */
284#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100285 void *__p; \
286 if ((__p = pool_##type) == NULL) \
287 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100288 else { \
289 pool_##type = *(void **)pool_##type; \
290 } \
willy tarreau4302f492005-12-18 01:00:37 +0100291 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100292})
293
294/*
295 * Puts a memory area back to the corresponding pool.
296 * Items are chained directly through a pointer that
297 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100298 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100299 * that each memory area is at least as big as one
300 * pointer.
301 */
302#define pool_free(type, ptr) ({ \
303 *(void **)ptr = (void *)pool_##type; \
304 pool_##type = (void *)ptr; \
305})
306
307#else
308#define pool_alloc(type) (calloc(1,sizeof_##type));
309#define pool_free(type, ptr) (free(ptr));
310#endif /* MEM_OPTIM */
311
willy tarreau5cbea6f2005-12-17 12:48:26 +0100312#define sizeof_task sizeof(struct task)
313#define sizeof_session sizeof(struct session)
willy tarreau18a957c2006-04-12 19:26:23 +0200314#define sizeof_pendconn sizeof(struct pendconn)
willy tarreau0f7af912005-12-17 12:21:26 +0100315#define sizeof_buffer sizeof(struct buffer)
316#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100317#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100318#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100319#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100320#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100321
willy tarreau5cbea6f2005-12-17 12:48:26 +0100322/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100323#define FD_STCLOSE 0
324#define FD_STLISTEN 1
325#define FD_STCONN 2
326#define FD_STREADY 3
327#define FD_STERROR 4
328
willy tarreau5cbea6f2005-12-17 12:48:26 +0100329/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100330#define TASK_IDLE 0
331#define TASK_RUNNING 1
332
willy tarreau5cbea6f2005-12-17 12:48:26 +0100333/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100334#define PR_STNEW 0
335#define PR_STIDLE 1
336#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100337#define PR_STSTOPPED 3
338#define PR_STPAUSED 4
willy tarreaufac1a862006-05-21 10:20:28 +0200339#define PR_STERROR 5
willy tarreau0f7af912005-12-17 12:21:26 +0100340
willy tarreau5cbea6f2005-12-17 12:48:26 +0100341/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100342#define PR_MODE_TCP 0
343#define PR_MODE_HTTP 1
344#define PR_MODE_HEALTH 2
345
willy tarreau1c2ad212005-12-18 01:11:29 +0100346/* possible actions for the *poll() loops */
347#define POLL_LOOP_ACTION_INIT 0
348#define POLL_LOOP_ACTION_RUN 1
349#define POLL_LOOP_ACTION_CLEAN 2
350
willy tarreau64a3cc32005-12-18 01:13:11 +0100351/* poll mechanisms available */
352#define POLL_USE_SELECT (1<<0)
353#define POLL_USE_POLL (1<<1)
354#define POLL_USE_EPOLL (1<<2)
355
willy tarreau5cbea6f2005-12-17 12:48:26 +0100356/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100357#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
358#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
359#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
360#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
361#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
362#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
363#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
364#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100365#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
366#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
367#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
368#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
369#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
370#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
371#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
372#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
373#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
374#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
375#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100376#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
377#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100378#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100379#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100380#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
381#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau03a92de2006-05-21 18:26:53 +0200382#define PR_O_ABRT_CLOSE 0x00800000 /* immediately abort request when client closes */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100383
willy tarreaua5e8c662006-04-29 10:43:46 +0200384/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100385#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
386#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
387#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
388#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
389#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
390#define SN_POST 0x00000020 /* the request was an HTTP POST */
391
willy tarreaua5e8c662006-04-29 10:43:46 +0200392/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100393#define SN_CK_NONE 0x00000000 /* this session had no cookie */
394#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
395#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
396#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
397#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
398#define SN_CK_SHIFT 6 /* bit shift */
399
willy tarreaua5e8c662006-04-29 10:43:46 +0200400/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100401#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100402#define SN_ERR_CLITO 0x00000100 /* client time-out */
403#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
404#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
405#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
406#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100407#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
408#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100409#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
410#define SN_ERR_SHIFT 8 /* bit shift */
411
willy tarreaua5e8c662006-04-29 10:43:46 +0200412/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100413#define SN_FINST_R 0x00001000 /* session ended during client request */
414#define SN_FINST_C 0x00002000 /* session ended during server connect */
415#define SN_FINST_H 0x00003000 /* session ended during server headers */
416#define SN_FINST_D 0x00004000 /* session ended during data phase */
417#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
willy tarreau078c79a2006-05-13 12:23:58 +0200418#define SN_FINST_Q 0x00006000 /* session ended while waiting in queue for a server slot */
willy tarreau036e1ce2005-12-17 13:46:33 +0100419#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
420#define SN_FINST_SHIFT 12 /* bit shift */
421
willy tarreaua5e8c662006-04-29 10:43:46 +0200422/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100423#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
424#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
425#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
426#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
427#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100428#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100429#define SN_SCK_SHIFT 16 /* bit shift */
430
willy tarreaua5e8c662006-04-29 10:43:46 +0200431/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100432#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
433#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
434#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100435
willy tarreaua5e8c662006-04-29 10:43:46 +0200436/* various other session flags, bits values 0x400000 and above */
437#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200438#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
439#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaue0331262006-05-15 03:02:46 +0200440#define SN_SELF_GEN 0x02000000 /* the proxy generates data for the client (eg: stats) */
willy tarreaua5e8c662006-04-29 10:43:46 +0200441
willy tarreaue0331262006-05-15 03:02:46 +0200442/* various data sources for the responses */
443#define DATA_SRC_NONE 0
444#define DATA_SRC_STATS 1
willy tarreaua5e8c662006-04-29 10:43:46 +0200445
willy tarreau1f431b52006-05-21 14:46:15 +0200446/* data transmission states for the responses */
447#define DATA_ST_INIT 0
448#define DATA_ST_DATA 1
449
willy tarreau5cbea6f2005-12-17 12:48:26 +0100450/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100451#define CL_STHEADERS 0
452#define CL_STDATA 1
453#define CL_STSHUTR 2
454#define CL_STSHUTW 3
455#define CL_STCLOSE 4
456
willy tarreau5cbea6f2005-12-17 12:48:26 +0100457/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100458#define SV_STIDLE 0
willy tarreau9fea1942006-05-12 19:46:40 +0200459#define SV_STCONN 1
460#define SV_STHEADERS 2
461#define SV_STDATA 3
462#define SV_STSHUTR 4
463#define SV_STSHUTW 5
464#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100465
466/* result of an I/O event */
467#define RES_SILENT 0 /* didn't happen */
468#define RES_DATA 1 /* data were sent or received */
469#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
470#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
471
willy tarreau9fe663a2005-12-17 13:02:59 +0100472/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100473#define MODE_DEBUG 1
474#define MODE_STATS 2
475#define MODE_LOG 4
476#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100477#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100478#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100479#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100480#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100481#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100482
483/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100484#define SRV_RUNNING 1 /* the server is UP */
485#define SRV_BACKUP 2 /* this server is a backup server */
486#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100487#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100488#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100489
willy tarreaudfece232006-05-02 00:19:57 +0200490/* function which act on servers need to return various errors */
491#define SRV_STATUS_OK 0 /* everything is OK. */
492#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
493#define SRV_STATUS_NOSRV 2 /* no server is available */
494#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
495#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
496
willy tarreaue39cd132005-12-17 13:00:18 +0100497/* what to do when a header matches a regex */
498#define ACT_ALLOW 0 /* allow the request */
499#define ACT_REPLACE 1 /* replace the matching header */
500#define ACT_REMOVE 2 /* remove the matching header */
501#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100502#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100503
willy tarreau9fe663a2005-12-17 13:02:59 +0100504/* configuration sections */
505#define CFG_NONE 0
506#define CFG_GLOBAL 1
507#define CFG_LISTEN 2
508
willy tarreaua1598082005-12-17 13:08:06 +0100509/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100510#define LW_DATE 1 /* date */
511#define LW_CLIP 2 /* CLient IP */
512#define LW_SVIP 4 /* SerVer IP */
513#define LW_SVID 8 /* server ID */
514#define LW_REQ 16 /* http REQuest */
515#define LW_RESP 32 /* http RESPonse */
516#define LW_PXIP 64 /* proxy IP */
517#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100518#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100519#define LW_COOKIE 512 /* captured cookie */
520#define LW_REQHDR 1024 /* request header(s) */
521#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100522
willy tarreau41310e72006-03-25 18:17:56 +0100523#define ERR_NONE 0 /* no error */
524#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
525#define ERR_FATAL 2 /* fatal error, may be cumulated */
526
willy tarreau0f7af912005-12-17 12:21:26 +0100527/*********************************************************************/
528
529#define LIST_HEAD(a) ((void *)(&(a)))
530
531/*********************************************************************/
532
willy tarreau9e138862006-05-14 23:06:28 +0200533/* describes a chunk of string */
534struct chunk {
535 char *str; /* beginning of the string itself. Might not be 0-terminated */
536 int len; /* size of the string from first to last char. <0 = uninit. */
537};
538
willy tarreau4302f492005-12-18 01:00:37 +0100539struct cap_hdr {
540 struct cap_hdr *next;
541 char *name; /* header name, case insensitive */
542 int namelen; /* length of the header name, to speed-up lookups */
543 int len; /* capture length, not including terminal zero */
544 int index; /* index in the output array */
545 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
546};
547
willy tarreau0f7af912005-12-17 12:21:26 +0100548struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100549 struct hdr_exp *next;
550 regex_t *preg; /* expression to look for */
551 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
552 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100553};
554
555struct buffer {
556 unsigned int l; /* data length */
557 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100558 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100559 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100560 char data[BUFSIZE];
561};
562
willy tarreau18a957c2006-04-12 19:26:23 +0200563struct pendconn {
564 struct list list; /* chaining ... */
565 struct session *sess; /* the session waiting for a connection */
566 struct server *srv; /* the server we are waiting for */
567};
568
willy tarreau0f7af912005-12-17 12:21:26 +0100569struct server {
570 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100571 int state; /* server state (SRV_*) */
572 int cklen; /* the len of the cookie, to speed up checks */
573 char *cookie; /* the id set in the cookie */
574 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200575 struct list pendconns; /* pending connections */
willy tarreaucb406512006-05-18 00:52:35 +0200576 int nbpend, nbpend_max; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200577 struct task *queue_mgt; /* the task associated to the queue processing */
willy tarreau0f7af912005-12-17 12:21:26 +0100578 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100579 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100580 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100581 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100582 int rise, fall; /* time in iterations */
583 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100584 int result; /* 0 = connect OK, -1 = connect KO */
585 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200586 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200587 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaucb406512006-05-18 00:52:35 +0200588 int cur_sess, cur_sess_max; /* number of currently active sessions (including syn_sent) */
willy tarreaua647c702006-04-15 22:45:52 +0200589 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreauf76e6ca2006-05-21 21:09:55 +0200590 unsigned int maxconn, minconn; /* max # of active sessions (0 = unlimited), min# for dynamic limit. */
willy tarreaucb406512006-05-18 00:52:35 +0200591 unsigned failed_checks, down_trans; /* failed checks and up-down transitions */
willy tarreaue3b30652006-05-21 16:23:22 +0200592 unsigned failed_conns, failed_resp; /* failed connect() and responses */
593 unsigned failed_secu; /* blocked responses because of security concerns */
willy tarreau535ae7a2005-12-17 12:58:00 +0100594 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100595};
596
willy tarreau5cbea6f2005-12-17 12:48:26 +0100597/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100598struct task {
599 struct task *next, *prev; /* chaining ... */
600 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100601 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100602 int state; /* task state : IDLE or RUNNING */
603 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100604 int (*process)(struct task *t); /* the function which processes the task */
605 void *context; /* the task's context */
606};
607
608/* WARNING: if new fields are added, they must be initialized in event_accept() */
609struct session {
610 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100611 /* application specific below */
612 struct timeval crexpire; /* expiration date for a client read */
613 struct timeval cwexpire; /* expiration date for a client write */
614 struct timeval srexpire; /* expiration date for a server read */
615 struct timeval swexpire; /* expiration date for a server write */
616 struct timeval cnexpire; /* expiration date for a connect */
617 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
618 struct proxy *proxy; /* the proxy this socket belongs to */
619 int cli_fd; /* the client side fd */
620 int srv_fd; /* the server side fd */
621 int cli_state; /* state of the client side */
622 int srv_state; /* state of the server side */
623 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100624 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100625 struct buffer *req; /* request buffer */
626 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100627 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100628 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100629 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200630 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100631 char **req_cap; /* array of captured request headers (may be NULL) */
632 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreau9e138862006-05-14 23:06:28 +0200633 struct chunk req_line; /* points to first line */
634 struct chunk auth_hdr; /* points to 'Authorization:' header */
willy tarreaua1598082005-12-17 13:08:06 +0100635 struct {
636 int logwait; /* log fields waiting to be collected : LW_* */
637 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
638 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200639 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100640 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
641 long t_data; /* delay before the first data byte from the server ... */
642 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200643 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
644 unsigned long prx_queue_size; /* overall number of sessions waiting for a connect slot on this instance at accept() time */
willy tarreaua1598082005-12-17 13:08:06 +0100645 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100646 char *cli_cookie; /* cookie presented by the client, in capture mode */
647 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100648 int status; /* HTTP status from the server, negative if from proxy */
649 long long bytes; /* number of bytes transferred from the server */
650 } logs;
willy tarreau1f431b52006-05-21 14:46:15 +0200651 short int data_source; /* where to get the data we generate ourselves */
652 short int data_state; /* where to get the data we generate ourselves */
willy tarreaue0331262006-05-15 03:02:46 +0200653 union {
654 struct {
655 struct proxy *px;
656 struct server *sv;
willy tarreau1f431b52006-05-21 14:46:15 +0200657 short px_st, sv_st; /* DATA_ST_INIT or DATA_ST_DATA */
willy tarreaue0331262006-05-15 03:02:46 +0200658 } stats;
659 } data_ctx;
willy tarreau2f6ba652005-12-17 13:57:42 +0100660 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100661};
662
willy tarreaua41a8b42005-12-17 14:02:24 +0100663struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100664 int fd; /* the listen socket */
665 struct sockaddr_storage addr; /* the address we listen to */
666 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100667};
willy tarreauf32f5242006-05-02 22:54:52 +0200668
willy tarreau0f7af912005-12-17 12:21:26 +0100669struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100670 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100671 struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */
willy tarreau0f7af912005-12-17 12:21:26 +0100672 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100673 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200674 struct server *srv; /* known servers */
675 int srv_act, srv_bck; /* # of running servers */
676 int tot_wact, tot_wbck; /* total weights of active and backup servers */
677 struct server **srv_map; /* the server map used to apply weights */
678 int srv_map_sz; /* the size of the effective server map */
679 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100680 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100681 int cookie_len; /* strlen(cookie_name), computed only once */
682 char *appsession_name; /* name of the cookie to look for */
683 int appsession_name_len; /* strlen(appsession_name), computed only once */
684 int appsession_len; /* length of the appsession cookie value to be used */
685 int appsession_timeout;
686 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100687 char *capture_name; /* beginning of the name of the cookie to capture */
688 int capture_namelen; /* length of the cookie name to match */
689 int capture_len; /* length of the string to be captured */
willy tarreau9e138862006-05-14 23:06:28 +0200690 struct uri_auth *uri_auth; /* if non-NULL, the (list of) per-URI authentications */
willy tarreau0f7af912005-12-17 12:21:26 +0100691 int clitimeout; /* client I/O timeout (in milliseconds) */
692 int srvtimeout; /* server I/O timeout (in milliseconds) */
693 int contimeout; /* connect timeout (in milliseconds) */
694 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200695 struct list pendconns; /* pending connections with no server assigned yet */
willy tarreaucb406512006-05-18 00:52:35 +0200696 int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200697 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreauf76e6ca2006-05-21 21:09:55 +0200698 unsigned int nbconn, nbconn_max; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200699 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreauf76e6ca2006-05-21 21:09:55 +0200700 unsigned int maxconn; /* max # of active sessions */
willy tarreaue3b30652006-05-21 16:23:22 +0200701 unsigned failed_conns, failed_resp; /* failed connect() and responses */
702 unsigned failed_secu; /* blocked responses because of security concerns */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100703 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100704 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100705 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100706 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100707 struct proxy *next;
708 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100709 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100710 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100711 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100712 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100713 int nb_reqadd, nb_rspadd;
714 struct hdr_exp *req_exp; /* regular expressions for request headers */
715 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100716 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
717 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
718 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
719 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100720 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100721 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100722 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
723 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100724 struct {
725 char *msg400; /* message for error 400 */
726 int len400; /* message length for error 400 */
727 char *msg403; /* message for error 403 */
728 int len403; /* message length for error 403 */
729 char *msg408; /* message for error 408 */
730 int len408; /* message length for error 408 */
731 char *msg500; /* message for error 500 */
732 int len500; /* message length for error 500 */
733 char *msg502; /* message for error 502 */
734 int len502; /* message length for error 502 */
735 char *msg503; /* message for error 503 */
736 int len503; /* message length for error 503 */
737 char *msg504; /* message for error 504 */
738 int len504; /* message length for error 504 */
739 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100740};
741
742/* info about one given fd */
743struct fdtab {
744 int (*read)(int fd); /* read function */
745 int (*write)(int fd); /* write function */
746 struct task *owner; /* the session (or proxy) associated with this fd */
747 int state; /* the state of this fd */
748};
749
750/*********************************************************************/
751
willy tarreaub952e1d2005-12-18 01:31:20 +0100752int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100753int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100754char *cfg_cfgfile = NULL; /* configuration file */
755char *progname = NULL; /* program name */
756int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100757
758/* global options */
759static struct {
760 int uid;
761 int gid;
762 int nbproc;
763 int maxconn;
764 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100765 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100766 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100767 int mode;
768 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100769 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100770 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100771 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100772 struct sockaddr_in logsrv1, logsrv2;
773} global = {
774 logfac1 : -1,
775 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100776 loglev1 : 7, /* max syslog level : debug */
777 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100778 /* others NULL OK */
779};
780
willy tarreau0f7af912005-12-17 12:21:26 +0100781/*********************************************************************/
782
willy tarreau1c2ad212005-12-18 01:11:29 +0100783fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100784 *StaticWriteEvent;
785
willy tarreau64a3cc32005-12-18 01:13:11 +0100786int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100787
willy tarreau0f7af912005-12-17 12:21:26 +0100788void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200789 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100790 **pool_buffer = NULL,
791 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100792 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100793 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100794 **pool_capture = NULL,
795 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100796
797struct proxy *proxy = NULL; /* list of all existing proxies */
798struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100799struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200800struct task wait_queue[2] = { /* global wait queue */
801 {
802 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
803 next:LIST_HEAD(wait_queue[0]),
804 },
805 {
806 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
807 next:LIST_HEAD(wait_queue[1]),
808 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100809};
willy tarreau0f7af912005-12-17 12:21:26 +0100810
willy tarreau0f7af912005-12-17 12:21:26 +0100811static int totalconn = 0; /* total # of terminated sessions */
812static int actconn = 0; /* # of active sessions */
813static int maxfd = 0; /* # of the highest fd + 1 */
814static int listeners = 0; /* # of listeners */
815static int stopping = 0; /* non zero means stopping in progress */
816static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaue0331262006-05-15 03:02:46 +0200817static struct timeval start_date; /* the process's start date */
willy tarreaua41a8b42005-12-17 14:02:24 +0100818static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100819
willy tarreau53e99702006-03-25 18:53:50 +0100820/* Here we store informations about the pids of the processes we may pause
821 * or kill. We will send them a signal every 10 ms until we can bind to all
822 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100823 */
willy tarreau53e99702006-03-25 18:53:50 +0100824#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100825static int nb_oldpids = 0;
826static int *oldpids = NULL;
827static int oldpids_sig; /* use USR1 or TERM */
828
willy tarreau08dedbe2005-12-18 01:13:48 +0100829#if defined(ENABLE_EPOLL)
830/* FIXME: this is dirty, but at the moment, there's no other solution to remove
831 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
832 * structure with pointers to functions such as init_fd() and close_fd(), plus
833 * a private structure with several pointers to places such as below.
834 */
835
836static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
837#endif
838
willy tarreau0f7af912005-12-17 12:21:26 +0100839static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100840/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100841static char trash[BUFSIZE];
842
willy tarreaudd07e972005-12-18 00:48:48 +0100843const int zero = 0;
844const int one = 1;
845
willy tarreau0f7af912005-12-17 12:21:26 +0100846/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100847 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100848 */
849
850#define MAX_SYSLOG_LEN 1024
851#define NB_LOG_FACILITIES 24
852const char *log_facilities[NB_LOG_FACILITIES] = {
853 "kern", "user", "mail", "daemon",
854 "auth", "syslog", "lpr", "news",
855 "uucp", "cron", "auth2", "ftp",
856 "ntp", "audit", "alert", "cron2",
857 "local0", "local1", "local2", "local3",
858 "local4", "local5", "local6", "local7"
859};
860
861
862#define NB_LOG_LEVELS 8
863const char *log_levels[NB_LOG_LEVELS] = {
864 "emerg", "alert", "crit", "err",
865 "warning", "notice", "info", "debug"
866};
867
868#define SYSLOG_PORT 514
869
870const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
871 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100872
willy tarreaub1285d52005-12-18 01:20:14 +0100873const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200874const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100875const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
876const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
877 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
878 unknown, Set-cookie Rewritten */
879
willy tarreau0f7af912005-12-17 12:21:26 +0100880#define MAX_HOSTNAME_LEN 32
881static char hostname[MAX_HOSTNAME_LEN] = "";
882
willy tarreau8337c6b2005-12-17 13:41:01 +0100883const char *HTTP_302 =
884 "HTTP/1.0 302 Found\r\n"
885 "Cache-Control: no-cache\r\n"
886 "Connection: close\r\n"
887 "Location: "; /* not terminated since it will be concatenated with the URL */
888
willy tarreauc1f47532005-12-18 01:08:26 +0100889/* same as 302 except that the browser MUST retry with the GET method */
890const char *HTTP_303 =
891 "HTTP/1.0 303 See Other\r\n"
892 "Cache-Control: no-cache\r\n"
893 "Connection: close\r\n"
894 "Location: "; /* not terminated since it will be concatenated with the URL */
895
willy tarreaua1598082005-12-17 13:08:06 +0100896const char *HTTP_400 =
897 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100898 "Cache-Control: no-cache\r\n"
899 "Connection: close\r\n"
900 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100901 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100902
willy tarreau9e138862006-05-14 23:06:28 +0200903/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
904const char *HTTP_401_fmt =
905 "HTTP/1.0 401 Unauthorized\r\n"
906 "Cache-Control: no-cache\r\n"
907 "Connection: close\r\n"
908 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
909 "\r\n"
910 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
911
willy tarreaua1598082005-12-17 13:08:06 +0100912const char *HTTP_403 =
913 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100914 "Cache-Control: no-cache\r\n"
915 "Connection: close\r\n"
916 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100917 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
918
willy tarreau8337c6b2005-12-17 13:41:01 +0100919const char *HTTP_408 =
920 "HTTP/1.0 408 Request Time-out\r\n"
921 "Cache-Control: no-cache\r\n"
922 "Connection: close\r\n"
923 "\r\n"
924 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
925
willy tarreau750a4722005-12-17 13:21:24 +0100926const char *HTTP_500 =
927 "HTTP/1.0 500 Server Error\r\n"
928 "Cache-Control: no-cache\r\n"
929 "Connection: close\r\n"
930 "\r\n"
931 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100932
933const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100934 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100935 "Cache-Control: no-cache\r\n"
936 "Connection: close\r\n"
937 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100938 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
939
940const char *HTTP_503 =
941 "HTTP/1.0 503 Service Unavailable\r\n"
942 "Cache-Control: no-cache\r\n"
943 "Connection: close\r\n"
944 "\r\n"
945 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
946
947const char *HTTP_504 =
948 "HTTP/1.0 504 Gateway Time-out\r\n"
949 "Cache-Control: no-cache\r\n"
950 "Connection: close\r\n"
951 "\r\n"
952 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100953
willy tarreau0f7af912005-12-17 12:21:26 +0100954/*********************************************************************/
955/* statistics ******************************************************/
956/*********************************************************************/
957
willy tarreau750a4722005-12-17 13:21:24 +0100958#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100959static int stats_tsk_lsrch, stats_tsk_rsrch,
960 stats_tsk_good, stats_tsk_right, stats_tsk_left,
961 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100962#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100963
964
965/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100966/* debugging *******************************************************/
967/*********************************************************************/
968#ifdef DEBUG_FULL
969static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau3504a012006-05-14 23:20:07 +0200970static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100971#endif
972
973/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100974/* function prototypes *********************************************/
975/*********************************************************************/
976
977int event_accept(int fd);
978int event_cli_read(int fd);
979int event_cli_write(int fd);
980int event_srv_read(int fd);
981int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100982int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100983
willy tarreau12350152005-12-18 01:03:27 +0100984static int appsession_task_init(void);
985static int appsession_init(void);
986static int appsession_refresh(struct task *t);
987
willy tarreau0f7af912005-12-17 12:21:26 +0100988/*********************************************************************/
989/* general purpose functions ***************************************/
990/*********************************************************************/
991
992void display_version() {
993 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100994 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100995}
996
997/*
998 * This function prints the command line usage and exits
999 */
1000void usage(char *name) {
1001 display_version();
1002 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +01001003 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +01001004#if STATTIME > 0
1005 "sl"
1006#endif
willy tarreau746e26b2006-03-25 11:14:35 +01001007 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
1008 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001009 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +01001010 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +01001011 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001012#if STATTIME > 0
1013 " -s enables statistics output\n"
1014 " -l enables long statistics format\n"
1015#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001016 " -D goes daemon ; implies -q\n"
1017 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +01001018 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001019 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +01001020 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +01001021 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001022 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001023#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001024 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001025#endif
1026#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001027 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001028#endif
willy tarreau53e99702006-03-25 18:53:50 +01001029 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001030 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01001031 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +01001032 exit(1);
1033}
1034
1035
1036/*
willy tarreaud0fb4652005-12-18 01:32:04 +01001037 * Displays the message on stderr with the date and pid. Overrides the quiet
1038 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +01001039 */
1040void Alert(char *fmt, ...) {
1041 va_list argp;
1042 struct timeval tv;
1043 struct tm *tm;
1044
willy tarreaud0fb4652005-12-18 01:32:04 +01001045 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001046 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001047
willy tarreau5cbea6f2005-12-17 12:48:26 +01001048 gettimeofday(&tv, NULL);
1049 tm=localtime(&tv.tv_sec);
1050 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001051 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001052 vfprintf(stderr, fmt, argp);
1053 fflush(stderr);
1054 va_end(argp);
1055 }
willy tarreau0f7af912005-12-17 12:21:26 +01001056}
1057
1058
1059/*
1060 * Displays the message on stderr with the date and pid.
1061 */
1062void Warning(char *fmt, ...) {
1063 va_list argp;
1064 struct timeval tv;
1065 struct tm *tm;
1066
willy tarreau982249e2005-12-18 00:57:06 +01001067 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001068 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001069
willy tarreau5cbea6f2005-12-17 12:48:26 +01001070 gettimeofday(&tv, NULL);
1071 tm=localtime(&tv.tv_sec);
1072 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001073 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001074 vfprintf(stderr, fmt, argp);
1075 fflush(stderr);
1076 va_end(argp);
1077 }
1078}
1079
1080/*
1081 * Displays the message on <out> only if quiet mode is not set.
1082 */
1083void qfprintf(FILE *out, char *fmt, ...) {
1084 va_list argp;
1085
willy tarreau982249e2005-12-18 00:57:06 +01001086 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001087 va_start(argp, fmt);
1088 vfprintf(out, fmt, argp);
1089 fflush(out);
1090 va_end(argp);
1091 }
willy tarreau0f7af912005-12-17 12:21:26 +01001092}
1093
1094
1095/*
1096 * converts <str> to a struct sockaddr_in* which is locally allocated.
1097 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1098 * INADDR_ANY.
1099 */
1100struct sockaddr_in *str2sa(char *str) {
1101 static struct sockaddr_in sa;
1102 char *c;
1103 int port;
1104
willy tarreaua1598082005-12-17 13:08:06 +01001105 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001106 str=strdup(str);
1107
1108 if ((c=strrchr(str,':')) != NULL) {
1109 *c++=0;
1110 port=atol(c);
1111 }
1112 else
1113 port=0;
1114
1115 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1116 sa.sin_addr.s_addr = INADDR_ANY;
1117 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001118 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001119 struct hostent *he;
1120
1121 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001122 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001123 }
1124 else
1125 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1126 }
1127 sa.sin_port=htons(port);
1128 sa.sin_family=AF_INET;
1129
1130 free(str);
1131 return &sa;
1132}
1133
willy tarreaub1285d52005-12-18 01:20:14 +01001134/*
1135 * converts <str> to a two struct in_addr* which are locally allocated.
1136 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1137 * is optionnal and either in the dotted or CIDR notation.
1138 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1139 */
1140int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1141 char *c;
1142 unsigned long len;
1143
1144 memset(mask, 0, sizeof(*mask));
1145 memset(addr, 0, sizeof(*addr));
1146 str=strdup(str);
1147
1148 if ((c = strrchr(str, '/')) != NULL) {
1149 *c++ = 0;
1150 /* c points to the mask */
1151 if (strchr(c, '.') != NULL) { /* dotted notation */
1152 if (!inet_pton(AF_INET, c, mask))
1153 return 0;
1154 }
1155 else { /* mask length */
1156 char *err;
1157 len = strtol(c, &err, 10);
1158 if (!*c || (err && *err) || (unsigned)len > 32)
1159 return 0;
1160 if (len)
1161 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1162 else
1163 mask->s_addr = 0;
1164 }
1165 }
1166 else {
1167 mask->s_addr = 0xFFFFFFFF;
1168 }
1169 if (!inet_pton(AF_INET, str, addr)) {
1170 struct hostent *he;
1171
1172 if ((he = gethostbyname(str)) == NULL) {
1173 return 0;
1174 }
1175 else
1176 *addr = *(struct in_addr *) *(he->h_addr_list);
1177 }
1178 free(str);
1179 return 1;
1180}
1181
willy tarreau9fe663a2005-12-17 13:02:59 +01001182
1183/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001184 * converts <str> to a list of listeners which are dynamically allocated.
1185 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1186 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1187 * - <port> is a numerical port from 1 to 65535 ;
1188 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1189 * This can be repeated as many times as necessary, separated by a coma.
1190 * The <tail> argument is a pointer to a current list which should be appended
1191 * to the tail of the new list. The pointer to the new list is returned.
1192 */
1193struct listener *str2listener(char *str, struct listener *tail) {
1194 struct listener *l;
1195 char *c, *next, *range, *dupstr;
1196 int port, end;
1197
1198 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001199
willy tarreaua41a8b42005-12-17 14:02:24 +01001200 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001201 struct sockaddr_storage ss;
1202
willy tarreaua41a8b42005-12-17 14:02:24 +01001203 str = next;
1204 /* 1) look for the end of the first address */
1205 if ((next = strrchr(str, ',')) != NULL) {
1206 *next++ = 0;
1207 }
1208
willy tarreau8a86dbf2005-12-18 00:45:59 +01001209 /* 2) look for the addr/port delimiter, it's the last colon. */
1210 if ((range = strrchr(str, ':')) == NULL) {
1211 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001212 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001213 }
1214
1215 *range++ = 0;
1216
1217 if (strrchr(str, ':') != NULL) {
1218 /* IPv6 address contains ':' */
1219 memset(&ss, 0, sizeof(ss));
1220 ss.ss_family = AF_INET6;
1221
1222 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1223 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001224 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001225 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001226 }
1227 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001228 memset(&ss, 0, sizeof(ss));
1229 ss.ss_family = AF_INET;
1230
1231 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1232 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1233 }
1234 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1235 struct hostent *he;
1236
1237 if ((he = gethostbyname(str)) == NULL) {
1238 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001239 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001240 }
1241 else
1242 ((struct sockaddr_in *)&ss)->sin_addr =
1243 *(struct in_addr *) *(he->h_addr_list);
1244 }
1245 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001246
1247 /* 3) look for the port-end delimiter */
1248 if ((c = strchr(range, '-')) != NULL) {
1249 *c++ = 0;
1250 end = atol(c);
1251 }
1252 else {
1253 end = atol(range);
1254 }
1255
willy tarreaud0fb4652005-12-18 01:32:04 +01001256 port = atol(range);
1257
1258 if (port < 1 || port > 65535) {
1259 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1260 goto fail;
1261 }
1262
1263 if (end < 1 || end > 65535) {
1264 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1265 goto fail;
1266 }
1267
1268 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001269 l = (struct listener *)calloc(1, sizeof(struct listener));
1270 l->next = tail;
1271 tail = l;
1272
willy tarreau41310e72006-03-25 18:17:56 +01001273 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001274 l->addr = ss;
1275 if (ss.ss_family == AF_INET6)
1276 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1277 else
1278 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1279
willy tarreaua41a8b42005-12-17 14:02:24 +01001280 } /* end for(port) */
1281 } /* end while(next) */
1282 free(dupstr);
1283 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001284 fail:
1285 free(dupstr);
1286 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001287}
1288
willy tarreau4302f492005-12-18 01:00:37 +01001289
1290#define FD_SETS_ARE_BITFIELDS
1291#ifdef FD_SETS_ARE_BITFIELDS
1292/*
1293 * This map is used with all the FD_* macros to check whether a particular bit
1294 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1295 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1296 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1297 * exclusively to the macros.
1298 */
1299fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1300fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1301
1302#else
1303#error "Check if your OS uses bitfields for fd_sets"
1304#endif
1305
1306/* will try to encode the string <string> replacing all characters tagged in
1307 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1308 * prefixed by <escape>, and will store the result between <start> (included
1309 *) and <stop> (excluded), and will always terminate the string with a '\0'
1310 * before <stop>. The position of the '\0' is returned if the conversion
1311 * completes. If bytes are missing between <start> and <stop>, then the
1312 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1313 * cannot even be stored so we return <start> without writing the 0.
1314 * The input string must also be zero-terminated.
1315 */
1316char hextab[16] = "0123456789ABCDEF";
1317char *encode_string(char *start, char *stop,
1318 const char escape, const fd_set *map,
1319 const char *string)
1320{
1321 if (start < stop) {
1322 stop--; /* reserve one byte for the final '\0' */
1323 while (start < stop && *string != 0) {
1324 if (!FD_ISSET((unsigned char)(*string), map))
1325 *start++ = *string;
1326 else {
1327 if (start + 3 >= stop)
1328 break;
1329 *start++ = escape;
1330 *start++ = hextab[(*string >> 4) & 15];
1331 *start++ = hextab[*string & 15];
1332 }
1333 string++;
1334 }
1335 *start = '\0';
1336 }
1337 return start;
1338}
willy tarreaua41a8b42005-12-17 14:02:24 +01001339
1340/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001341 * This function sends a syslog message to both log servers of a proxy,
1342 * or to global log servers if the proxy is NULL.
1343 * It also tries not to waste too much time computing the message header.
1344 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001345 */
1346void send_log(struct proxy *p, int level, char *message, ...) {
1347 static int logfd = -1; /* syslog UDP socket */
1348 static long tvsec = -1; /* to force the string to be initialized */
1349 struct timeval tv;
1350 va_list argp;
1351 static char logmsg[MAX_SYSLOG_LEN];
1352 static char *dataptr = NULL;
1353 int fac_level;
1354 int hdr_len, data_len;
1355 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001356 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001357 int nbloggers = 0;
1358 char *log_ptr;
1359
1360 if (logfd < 0) {
1361 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1362 return;
1363 }
1364
1365 if (level < 0 || progname == NULL || message == NULL)
1366 return;
1367
1368 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001369 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001370 /* this string is rebuild only once a second */
1371 struct tm *tm = localtime(&tv.tv_sec);
1372 tvsec = tv.tv_sec;
1373
willy tarreauc29948c2005-12-17 13:10:27 +01001374 hdr_len = snprintf(logmsg, sizeof(logmsg),
1375 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1376 monthname[tm->tm_mon],
1377 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1378 progname, pid);
1379 /* WARNING: depending upon implementations, snprintf may return
1380 * either -1 or the number of bytes that would be needed to store
1381 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001382 */
willy tarreauc29948c2005-12-17 13:10:27 +01001383 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1384 hdr_len = sizeof(logmsg);
1385
1386 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001387 }
1388
1389 va_start(argp, message);
1390 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001391 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1392 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001393 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001394 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001395
1396 if (p == NULL) {
1397 if (global.logfac1 >= 0) {
1398 sa[nbloggers] = &global.logsrv1;
1399 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001400 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001401 nbloggers++;
1402 }
1403 if (global.logfac2 >= 0) {
1404 sa[nbloggers] = &global.logsrv2;
1405 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001406 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001407 nbloggers++;
1408 }
1409 } else {
1410 if (p->logfac1 >= 0) {
1411 sa[nbloggers] = &p->logsrv1;
1412 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001413 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001414 nbloggers++;
1415 }
1416 if (p->logfac2 >= 0) {
1417 sa[nbloggers] = &p->logsrv2;
1418 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001419 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001420 nbloggers++;
1421 }
1422 }
1423
1424 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001425 /* we can filter the level of the messages that are sent to each logger */
1426 if (level > loglevel[nbloggers])
1427 continue;
1428
willy tarreauc29948c2005-12-17 13:10:27 +01001429 /* For each target, we may have a different facility.
1430 * We can also have a different log level for each message.
1431 * This induces variations in the message header length.
1432 * Since we don't want to recompute it each time, nor copy it every
1433 * time, we only change the facility in the pre-computed header,
1434 * and we change the pointer to the header accordingly.
1435 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001436 fac_level = (facilities[nbloggers] << 3) + level;
1437 log_ptr = logmsg + 3; /* last digit of the log level */
1438 do {
1439 *log_ptr = '0' + fac_level % 10;
1440 fac_level /= 10;
1441 log_ptr--;
1442 } while (fac_level && log_ptr > logmsg);
1443 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001444
willy tarreauc29948c2005-12-17 13:10:27 +01001445 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001446
1447#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001448 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001449 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1450#else
willy tarreauc29948c2005-12-17 13:10:27 +01001451 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001452 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1453#endif
1454 }
willy tarreau0f7af912005-12-17 12:21:26 +01001455}
1456
1457
1458/* sets <tv> to the current time */
1459static inline struct timeval *tv_now(struct timeval *tv) {
1460 if (tv)
1461 gettimeofday(tv, NULL);
1462 return tv;
1463}
1464
1465/*
1466 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1467 */
willy tarreaudab722b2006-05-04 19:23:38 +02001468static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001469 if (!tv || !from)
1470 return NULL;
1471 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1472 tv->tv_sec = from->tv_sec + (ms/1000);
1473 while (tv->tv_usec >= 1000000) {
1474 tv->tv_usec -= 1000000;
1475 tv->tv_sec++;
1476 }
1477 return tv;
1478}
1479
1480/*
1481 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001482 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001483 */
1484static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001485 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001486 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001487 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001488 return 1;
1489 else if (tv1->tv_usec < tv2->tv_usec)
1490 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001491 else if (tv1->tv_usec > tv2->tv_usec)
1492 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001493 else
1494 return 0;
1495}
1496
1497/*
1498 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001499 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001500 */
1501unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1502 int cmp;
1503 unsigned long ret;
1504
1505
willy tarreauef900ab2005-12-17 12:52:52 +01001506 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001507 if (!cmp)
1508 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001509 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001510 struct timeval *tmp = tv1;
1511 tv1 = tv2;
1512 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001513 }
willy tarreauef900ab2005-12-17 12:52:52 +01001514 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001515 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001516 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001517 else
willy tarreauef900ab2005-12-17 12:52:52 +01001518 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001519 return (unsigned long) ret;
1520}
1521
1522/*
willy tarreau750a4722005-12-17 13:21:24 +01001523 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001524 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001525 */
1526static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1527 unsigned long ret;
1528
willy tarreau6e682ce2005-12-17 13:26:49 +01001529 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1530 if (tv2->tv_usec > tv1->tv_usec)
1531 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001532 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001533 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001534 return (unsigned long) ret;
1535}
1536
1537/*
willy tarreau0f7af912005-12-17 12:21:26 +01001538 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001539 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001540 */
willy tarreaudab722b2006-05-04 19:23:38 +02001541static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001542 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001543 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001544 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001545 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001546 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001547 else
1548 return 0;
1549 }
willy tarreau0f7af912005-12-17 12:21:26 +01001550 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001551 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001552 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001553 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001554 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001555 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001556 else
1557 return 0;
1558}
1559
1560/*
1561 * returns the remaining time between tv1=now and event=tv2
1562 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001563 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001564 */
1565static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1566 unsigned long ret;
1567
willy tarreau0f7af912005-12-17 12:21:26 +01001568 if (tv_cmp_ms(tv1, tv2) >= 0)
1569 return 0; /* event elapsed */
1570
willy tarreauef900ab2005-12-17 12:52:52 +01001571 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001572 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001573 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001574 else
willy tarreauef900ab2005-12-17 12:52:52 +01001575 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001576 return (unsigned long) ret;
1577}
1578
1579
1580/*
1581 * zeroes a struct timeval
1582 */
1583
1584static inline struct timeval *tv_eternity(struct timeval *tv) {
1585 tv->tv_sec = tv->tv_usec = 0;
1586 return tv;
1587}
1588
1589/*
1590 * returns 1 if tv is null, else 0
1591 */
1592static inline int tv_iseternity(struct timeval *tv) {
1593 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1594 return 1;
1595 else
1596 return 0;
1597}
1598
1599/*
1600 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1601 * considering that 0 is the eternity.
1602 */
willy tarreaudab722b2006-05-04 19:23:38 +02001603static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001604 if (tv_iseternity(tv1))
1605 if (tv_iseternity(tv2))
1606 return 0; /* same */
1607 else
1608 return 1; /* tv1 later than tv2 */
1609 else if (tv_iseternity(tv2))
1610 return -1; /* tv2 later than tv1 */
1611
1612 if (tv1->tv_sec > tv2->tv_sec)
1613 return 1;
1614 else if (tv1->tv_sec < tv2->tv_sec)
1615 return -1;
1616 else if (tv1->tv_usec > tv2->tv_usec)
1617 return 1;
1618 else if (tv1->tv_usec < tv2->tv_usec)
1619 return -1;
1620 else
1621 return 0;
1622}
1623
1624/*
1625 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1626 * considering that 0 is the eternity.
1627 */
willy tarreaudab722b2006-05-04 19:23:38 +02001628static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001629 if (tv_iseternity(tv1))
1630 if (tv_iseternity(tv2))
1631 return 0; /* same */
1632 else
1633 return 1; /* tv1 later than tv2 */
1634 else if (tv_iseternity(tv2))
1635 return -1; /* tv2 later than tv1 */
1636
willy tarreauefae1842005-12-17 12:51:03 +01001637 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001638 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001639 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001640 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001641 return -1;
1642 else
1643 return 0;
1644 }
1645 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001646 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001647 return 1;
1648 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001649 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001650 return -1;
1651 else
1652 return 0;
1653}
1654
1655/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001656 * returns the remaining time between tv1=now and event=tv2
1657 * if tv2 is passed, 0 is returned.
1658 * Returns TIME_ETERNITY if tv2 is eternity.
1659 */
willy tarreaudab722b2006-05-04 19:23:38 +02001660static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001661 unsigned long ret;
1662
1663 if (tv_iseternity(tv2))
1664 return TIME_ETERNITY;
1665
1666 if (tv_cmp_ms(tv1, tv2) >= 0)
1667 return 0; /* event elapsed */
1668
1669 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1670 if (tv2->tv_usec > tv1->tv_usec)
1671 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1672 else
1673 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1674 return (unsigned long) ret;
1675}
1676
1677/*
willy tarreau0f7af912005-12-17 12:21:26 +01001678 * returns the first event between tv1 and tv2 into tvmin.
1679 * a zero tv is ignored. tvmin is returned.
1680 */
1681static inline struct timeval *tv_min(struct timeval *tvmin,
1682 struct timeval *tv1, struct timeval *tv2) {
1683
1684 if (tv_cmp2(tv1, tv2) <= 0)
1685 *tvmin = *tv1;
1686 else
1687 *tvmin = *tv2;
1688
1689 return tvmin;
1690}
1691
1692
1693
1694/***********************************************************/
1695/* fd management ***************************************/
1696/***********************************************************/
1697
1698
1699
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1701 * The file descriptor is also closed.
1702 */
willy tarreaudab722b2006-05-04 19:23:38 +02001703static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001704 FD_CLR(fd, StaticReadEvent);
1705 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001706#if defined(ENABLE_EPOLL)
1707 if (PrevReadEvent) {
1708 FD_CLR(fd, PrevReadEvent);
1709 FD_CLR(fd, PrevWriteEvent);
1710 }
1711#endif
1712
willy tarreau5cbea6f2005-12-17 12:48:26 +01001713 close(fd);
1714 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001715
1716 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1717 maxfd--;
1718}
1719
1720/* recomputes the maxfd limit from the fd */
1721static inline void fd_insert(int fd) {
1722 if (fd+1 > maxfd)
1723 maxfd = fd+1;
1724}
1725
1726/*************************************************************/
1727/* task management ***************************************/
1728/*************************************************************/
1729
willy tarreau5cbea6f2005-12-17 12:48:26 +01001730/* puts the task <t> in run queue <q>, and returns <t> */
1731static inline struct task *task_wakeup(struct task **q, struct task *t) {
1732 if (t->state == TASK_RUNNING)
1733 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001734 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001735 t->rqnext = *q;
1736 t->state = TASK_RUNNING;
1737 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001738 }
1739}
1740
willy tarreau5cbea6f2005-12-17 12:48:26 +01001741/* removes the task <t> from the queue <q>
1742 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001743 * set the run queue to point to the next one, and return it
1744 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001745static inline struct task *task_sleep(struct task **q, struct task *t) {
1746 if (t->state == TASK_RUNNING) {
1747 *q = t->rqnext;
1748 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001749 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001750 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001751}
1752
1753/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001754 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001755 * from the run queue. A pointer to the task itself is returned.
1756 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001757static inline struct task *task_delete(struct task *t) {
1758 t->prev->next = t->next;
1759 t->next->prev = t->prev;
1760 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001761}
1762
1763/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001764 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001765 */
1766static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001767 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001768}
1769
willy tarreau5cbea6f2005-12-17 12:48:26 +01001770/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001771 * may be only moved or left where it was, depending on its timing requirements.
1772 * <task> is returned.
1773 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001774struct task *task_queue(struct task *task) {
1775 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001776 struct task *start_from;
1777
willy tarreau5e698ef2006-05-02 14:51:00 +02001778 /* This is a very dirty hack to queue non-expirable tasks in another queue
1779 * in order to avoid pulluting the tail of the standard queue. This will go
1780 * away with the new O(log(n)) scheduler anyway.
1781 */
1782 if (tv_iseternity(&task->expire)) {
1783 /* if the task was queued in the standard wait queue, we must dequeue it */
1784 if (task->prev) {
1785 if (task->wq == LIST_HEAD(wait_queue[1]))
1786 return task;
1787 else {
1788 task_delete(task);
1789 task->prev = NULL;
1790 }
1791 }
1792 list = task->wq = LIST_HEAD(wait_queue[1]);
1793 } else {
1794 /* if the task was queued in the eternity queue, we must dequeue it */
1795 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1796 task_delete(task);
1797 task->prev = NULL;
1798 list = task->wq = LIST_HEAD(wait_queue[0]);
1799 }
1800 }
1801
1802 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001803 if (task->prev == NULL) {
1804 // start_from = list;
1805 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001806#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001807 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001808#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001809 /* insert the unlinked <task> into the list, searching back from the last entry */
1810 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1811 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001812#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001813 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001814#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001815 }
1816
1817 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1818 // start_from = start_from->next;
1819 // stats_tsk_nsrch++;
1820 // }
1821 }
1822 else if (task->prev == list ||
1823 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1824 start_from = task->next;
1825 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001826#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001827 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001828#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001829 return task; /* it's already in the right place */
1830 }
1831
willy tarreau750a4722005-12-17 13:21:24 +01001832#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001833 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001834#endif
1835
1836 /* if the task is not at the right place, there's little chance that
1837 * it has only shifted a bit, and it will nearly always be queued
1838 * at the end of the list because of constant timeouts
1839 * (observed in real case).
1840 */
1841#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1842 start_from = list->prev; /* assume we'll queue to the end of the list */
1843 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1844 start_from = start_from->prev;
1845#if STATTIME > 0
1846 stats_tsk_lsrch++;
1847#endif
1848 }
1849#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001850 /* insert the unlinked <task> into the list, searching after position <start_from> */
1851 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1852 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001853#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001854 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001855#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001856 }
willy tarreau750a4722005-12-17 13:21:24 +01001857#endif /* WE_REALLY_... */
1858
willy tarreau0f7af912005-12-17 12:21:26 +01001859 /* we need to unlink it now */
1860 task_delete(task);
1861 }
1862 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001863#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001864 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001865#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001866#ifdef LEFT_TO_TOP /* not very good */
1867 start_from = list;
1868 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1869 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001870#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001871 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001872#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001873 }
1874#else
1875 start_from = task->prev->prev; /* valid because of the previous test above */
1876 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1877 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001878#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001879 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001880#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001881 }
1882#endif
1883 /* we need to unlink it now */
1884 task_delete(task);
1885 }
1886 task->prev = start_from;
1887 task->next = start_from->next;
1888 task->next->prev = task;
1889 start_from->next = task;
1890 return task;
1891}
1892
1893
1894/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001895/* pending connections queues **************************************/
1896/*********************************************************************/
1897
1898/*
willy tarreaudfece232006-05-02 00:19:57 +02001899 * Detaches pending connection <p>, decreases the pending count, and frees
1900 * the pending connection. The connection might have been queued to a specific
1901 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001902 */
willy tarreaudfece232006-05-02 00:19:57 +02001903static void pendconn_free(struct pendconn *p) {
1904 LIST_DEL(&p->list);
1905 p->sess->pend_pos = NULL;
1906 if (p->srv)
1907 p->srv->nbpend--;
1908 else
1909 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001910 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001911 pool_free(pendconn, p);
1912}
1913
1914/* Returns the first pending connection for server <s>, which may be NULL if
1915 * nothing is pending.
1916 */
1917static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001918 if (!s->nbpend)
1919 return NULL;
1920
1921 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1922}
1923
willy tarreaudfece232006-05-02 00:19:57 +02001924/* Returns the first pending connection for proxy <px>, which may be NULL if
1925 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001926 */
willy tarreaudfece232006-05-02 00:19:57 +02001927static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1928 if (!px->nbpend)
1929 return NULL;
1930
1931 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001932}
1933
willy tarreaubc2eda62006-05-04 15:16:23 +02001934/* Detaches the next pending connection from either a server or a proxy, and
1935 * returns its associated session. If no pending connection is found, NULL is
1936 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001937 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001938static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001939 struct pendconn *p;
1940 struct session *sess;
1941
willy tarreaubc2eda62006-05-04 15:16:23 +02001942 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001943 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001944 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001945 if (!p)
1946 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001947 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001948 }
willy tarreau18a957c2006-04-12 19:26:23 +02001949 sess = p->sess;
1950 pendconn_free(p);
1951 return sess;
1952}
1953
willy tarreaudfece232006-05-02 00:19:57 +02001954/* Adds the session <sess> to the pending connection list of server <sess>->srv
1955 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1956 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1957 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001958 */
willy tarreaudfece232006-05-02 00:19:57 +02001959static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001960 struct pendconn *p;
1961
1962 p = pool_alloc(pendconn);
1963 if (!p)
1964 return NULL;
1965
willy tarreau18a957c2006-04-12 19:26:23 +02001966 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001967 p->sess = sess;
1968 p->srv = sess->srv;
1969 if (sess->srv) {
1970 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001971 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001972 sess->srv->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001973 if (sess->srv->nbpend > sess->srv->nbpend_max)
1974 sess->srv->nbpend_max = sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001975 } else {
1976 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001977 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001978 sess->proxy->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001979 if (sess->proxy->nbpend > sess->proxy->nbpend_max)
1980 sess->proxy->nbpend_max = sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001981 }
willy tarreauf32f5242006-05-02 22:54:52 +02001982 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001983 return p;
1984}
1985
willy tarreauf76e6ca2006-05-21 21:09:55 +02001986/* returns the effective dynamic maxconn for a server, considering the minconn
1987 * and the proxy's usage relative to its saturation.
1988 */
1989static unsigned int srv_dynamic_maxconn(struct server *s) {
1990 return s->minconn ?
1991 ((s->maxconn * s->proxy->nbconn / s->proxy->maxconn) < s->minconn) ? s->minconn :
1992 (s->maxconn * s->proxy->nbconn / s->proxy->maxconn) : s->maxconn;
1993}
1994
willy tarreau59a6cc22006-05-12 01:29:08 +02001995/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1996 * and non-zero otherwise. Suited for and if/else usage.
1997 */
1998static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1999 return (s && (s->nbpend || p->nbpend) &&
willy tarreauf76e6ca2006-05-21 21:09:55 +02002000 (!s->maxconn || s->cur_sess < srv_dynamic_maxconn(s)) &&
2001 s->queue_mgt);
willy tarreau59a6cc22006-05-12 01:29:08 +02002002}
2003
2004
2005
willy tarreau18a957c2006-04-12 19:26:23 +02002006/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01002007/* more specific functions ***************************************/
2008/*********************************************************************/
2009
2010/* some prototypes */
2011static int maintain_proxies(void);
2012
willy tarreaub952e1d2005-12-18 01:31:20 +01002013/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
2015 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01002016static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01002017#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002018 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
2019#else
willy tarreaua1598082005-12-17 13:08:06 +01002020#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002021 return getsockname(fd, (struct sockaddr *)sa, salen);
2022#else
2023 return -1;
2024#endif
2025#endif
2026}
2027
2028/*
2029 * frees the context associated to a session. It must have been removed first.
2030 */
willy tarreaudfece232006-05-02 00:19:57 +02002031static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02002032 if (s->pend_pos)
2033 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002034 if (s->req)
2035 pool_free(buffer, s->req);
2036 if (s->rep)
2037 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01002038
2039 if (s->rsp_cap != NULL) {
2040 struct cap_hdr *h;
2041 for (h = s->proxy->rsp_cap; h; h = h->next) {
2042 if (s->rsp_cap[h->index] != NULL)
2043 pool_free_to(h->pool, s->rsp_cap[h->index]);
2044 }
2045 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
2046 }
2047 if (s->req_cap != NULL) {
2048 struct cap_hdr *h;
2049 for (h = s->proxy->req_cap; h; h = h->next) {
2050 if (s->req_cap[h->index] != NULL)
2051 pool_free_to(h->pool, s->req_cap[h->index]);
2052 }
2053 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
2054 }
2055
willy tarreaua1598082005-12-17 13:08:06 +01002056 if (s->logs.uri)
2057 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01002058 if (s->logs.cli_cookie)
2059 pool_free(capture, s->logs.cli_cookie);
2060 if (s->logs.srv_cookie)
2061 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01002062
willy tarreau5cbea6f2005-12-17 12:48:26 +01002063 pool_free(session, s);
2064}
2065
willy tarreau0f7af912005-12-17 12:21:26 +01002066
2067/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01002068 * This function recounts the number of usable active and backup servers for
2069 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002070 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01002071 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002072static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002073 struct server *srv;
2074
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002075 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002076 for (srv = px->srv; srv != NULL; srv = srv->next) {
2077 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002078 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002079 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002080 px->tot_wbck += srv->eweight + 1;
2081 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002082 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002083 px->tot_wact += srv->eweight + 1;
2084 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002085 }
2086 }
2087}
2088
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002089/* This function recomputes the server map for proxy px. It
2090 * relies on px->tot_wact and px->tot_wbck, so it must be
2091 * called after recount_servers(). It also expects px->srv_map
2092 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002093 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002094static void recalc_server_map(struct proxy *px) {
2095 int o, tot, flag;
2096 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002097
willy tarreau4c8c2b52006-03-24 19:36:41 +01002098 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002099 flag = SRV_RUNNING;
2100 tot = px->tot_wact;
2101 } else if (px->srv_bck) {
2102 flag = SRV_RUNNING | SRV_BACKUP;
2103 if (px->options & PR_O_USE_ALL_BK)
2104 tot = px->tot_wbck;
2105 else
2106 tot = 1; /* the first server is enough */
2107 } else {
2108 px->srv_map_sz = 0;
2109 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002110 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002111
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002112 /* this algorithm gives priority to the first server, which means that
2113 * it will respect the declaration order for equivalent weights, and
2114 * that whatever the weights, the first server called will always be
2115 * the first declard. This is an important asumption for the backup
2116 * case, where we want the first server only.
2117 */
2118 for (cur = px->srv; cur; cur = cur->next)
2119 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002120
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002121 for (o = 0; o < tot; o++) {
2122 int max = 0;
2123 best = NULL;
2124 for (cur = px->srv; cur; cur = cur->next) {
2125 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2126 int v;
2127
2128 /* If we are forced to return only one server, we don't want to
2129 * go further, because we would return the wrong one due to
2130 * divide overflow.
2131 */
2132 if (tot == 1) {
2133 best = cur;
2134 break;
2135 }
2136
2137 cur->wscore += cur->eweight + 1;
2138 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2139 if (best == NULL || v > max) {
2140 max = v;
2141 best = cur;
2142 }
2143 }
2144 }
2145 px->srv_map[o] = best;
2146 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002147 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002148 px->srv_map_sz = tot;
2149}
Willy TARREAU3481c462006-03-01 22:37:57 +01002150
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002151/*
willy tarreau898db9d2006-04-12 20:29:08 +02002152 * This function tries to find a running server with free connection slots for
2153 * the proxy <px> following the round-robin method.
2154 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2155 * to point to the next server. If no valid server is found, NULL is returned.
2156 */
2157static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2158 int newidx;
2159 struct server *srv;
2160
2161 if (px->srv_map_sz == 0)
2162 return NULL;
2163
2164 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2165 px->srv_rr_idx = 0;
2166 newidx = px->srv_rr_idx;
2167
2168 do {
2169 srv = px->srv_map[newidx++];
willy tarreauf76e6ca2006-05-21 21:09:55 +02002170 if (!srv->maxconn || srv->cur_sess < srv_dynamic_maxconn(srv)) {
willy tarreau898db9d2006-04-12 20:29:08 +02002171 px->srv_rr_idx = newidx;
2172 return srv;
2173 }
2174 if (newidx == px->srv_map_sz)
2175 newidx = 0;
2176 } while (newidx != px->srv_rr_idx);
2177
2178 return NULL;
2179}
2180
2181
2182/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002183 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002184 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002185 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2186 * to point to the next server. If no valid server is found, NULL is returned.
2187 */
2188static inline struct server *get_server_rr(struct proxy *px) {
2189 if (px->srv_map_sz == 0)
2190 return NULL;
2191
2192 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2193 px->srv_rr_idx = 0;
2194 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002195}
2196
willy tarreau62084d42006-03-24 18:57:41 +01002197
2198/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002199 * This function tries to find a running server for the proxy <px> following
2200 * the source hash method. Depending on the number of active/backup servers,
2201 * it will either look for active servers, or for backup servers.
2202 * If any server is found, it will be returned. If no valid server is found,
2203 * NULL is returned.
2204 */
2205static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002206 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002207
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002208 if (px->srv_map_sz == 0)
2209 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002210
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002211 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002212 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002213 while ((l + sizeof (int)) <= len) {
2214 h ^= ntohl(*(unsigned int *)(&addr[l]));
2215 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002216 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002217 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002218 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002219 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002220}
2221
2222
2223/*
willy tarreaudfece232006-05-02 00:19:57 +02002224 * This function marks the session as 'assigned' in direct or dispatch modes,
2225 * or tries to assign one in balance mode, according to the algorithm. It does
2226 * nothing if the session had already been assigned a server.
2227 *
2228 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002229 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2230 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2231 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002232 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2233 *
2234 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2235 * not need to be called anymore. This usually means that s->srv can be trusted
2236 * in balance and direct modes. This flag is not cleared, so it's to the caller
2237 * to clear it if required (eg: redispatch).
2238 *
willy tarreau0f7af912005-12-17 12:21:26 +01002239 */
willy tarreau0f7af912005-12-17 12:21:26 +01002240
willy tarreaudfece232006-05-02 00:19:57 +02002241int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002242#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002243 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002244#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002245
willy tarreaudfece232006-05-02 00:19:57 +02002246 if (s->pend_pos)
2247 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002248
willy tarreaudfece232006-05-02 00:19:57 +02002249 if (!(s->flags & SN_ASSIGNED)) {
2250 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2251 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2252 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002253
willy tarreaudfece232006-05-02 00:19:57 +02002254 if (s->proxy->options & PR_O_BALANCE_RR) {
2255 s->srv = get_server_rr_with_conns(s->proxy);
2256 if (!s->srv)
2257 return SRV_STATUS_FULL;
2258 }
2259 else if (s->proxy->options & PR_O_BALANCE_SH) {
2260 int len;
2261
2262 if (s->cli_addr.ss_family == AF_INET)
2263 len = 4;
2264 else if (s->cli_addr.ss_family == AF_INET6)
2265 len = 16;
2266 else /* unknown IP family */
2267 return SRV_STATUS_INTERNAL;
2268
2269 s->srv = get_server_sh(s->proxy,
2270 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2271 len);
2272 }
2273 else /* unknown balancing algorithm */
2274 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002275 }
willy tarreaudfece232006-05-02 00:19:57 +02002276 s->flags |= SN_ASSIGNED;
2277 }
2278 return SRV_STATUS_OK;
2279}
willy tarreau1a3442d2006-03-24 21:03:20 +01002280
willy tarreaudfece232006-05-02 00:19:57 +02002281/*
2282 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2283 * The address is taken from the currently assigned server, or from the
2284 * dispatch or transparent address.
2285 *
2286 * It may return :
2287 * SRV_STATUS_OK if everything is OK.
2288 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2289 *
2290 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2291 * not cleared, so it's to the caller to clear it if required.
2292 *
2293 */
2294int assign_server_address(struct session *s) {
2295#ifdef DEBUG_FULL
2296 fprintf(stderr,"assign_server_address : s=%p\n",s);
2297#endif
2298
2299 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2300 /* A server is necessarily known for this session */
2301 if (!(s->flags & SN_ASSIGNED))
2302 return SRV_STATUS_INTERNAL;
2303
2304 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002305
willy tarreaudfece232006-05-02 00:19:57 +02002306 /* if this server remaps proxied ports, we'll use
2307 * the port the client connected to with an offset. */
2308 if (s->srv->state & SRV_MAPPORTS) {
2309 struct sockaddr_in sockname;
2310 socklen_t namelen = sizeof(sockname);
2311
2312 if (!(s->proxy->options & PR_O_TRANSP) ||
2313 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2314 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2315 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002316 }
willy tarreau0f7af912005-12-17 12:21:26 +01002317 }
willy tarreaua1598082005-12-17 13:08:06 +01002318 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002319 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002320 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 }
2322 else if (s->proxy->options & PR_O_TRANSP) {
2323 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002324 socklen_t salen = sizeof(s->srv_addr);
2325
willy tarreau5cbea6f2005-12-17 12:48:26 +01002326 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2327 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002328 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002329 }
2330 }
willy tarreau0f7af912005-12-17 12:21:26 +01002331
willy tarreaudfece232006-05-02 00:19:57 +02002332 s->flags |= SN_ADDR_SET;
2333 return SRV_STATUS_OK;
2334}
willy tarreaua41a8b42005-12-17 14:02:24 +01002335
willy tarreaudfece232006-05-02 00:19:57 +02002336/* This function assigns a server to session <s> if required, and can add the
2337 * connection to either the assigned server's queue or to the proxy's queue.
2338 *
2339 * Returns :
2340 *
2341 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002342 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002343 * SRV_STATUS_QUEUED if the connection has been queued.
2344 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2345 * connection could not be queued.
2346 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2347 *
2348 */
2349int assign_server_and_queue(struct session *s) {
2350 struct pendconn *p;
2351 int err;
2352
2353 if (s->pend_pos)
2354 return SRV_STATUS_INTERNAL;
2355
2356 if (s->flags & SN_ASSIGNED) {
2357 /* a server does not need to be assigned, perhaps because we're in
2358 * direct mode, or in dispatch or transparent modes where the server
2359 * is not needed.
2360 */
2361 if (s->srv &&
willy tarreauf76e6ca2006-05-21 21:09:55 +02002362 s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) {
willy tarreaudfece232006-05-02 00:19:57 +02002363 p = pendconn_add(s);
2364 if (p)
2365 return SRV_STATUS_QUEUED;
2366 else
2367 return SRV_STATUS_FULL;
2368 }
2369 return SRV_STATUS_OK;
2370 }
2371
2372 /* a server needs to be assigned */
2373 err = assign_server(s);
2374 switch (err) {
2375 case SRV_STATUS_OK:
2376 /* in balance mode, we might have servers with connection limits */
willy tarreauf76e6ca2006-05-21 21:09:55 +02002377 if (s->srv &&
2378 s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) {
willy tarreaudfece232006-05-02 00:19:57 +02002379 p = pendconn_add(s);
2380 if (p)
2381 return SRV_STATUS_QUEUED;
2382 else
2383 return SRV_STATUS_FULL;
2384 }
2385 return SRV_STATUS_OK;
2386
2387 case SRV_STATUS_FULL:
2388 /* queue this session into the proxy's queue */
2389 p = pendconn_add(s);
2390 if (p)
2391 return SRV_STATUS_QUEUED;
2392 else
2393 return SRV_STATUS_FULL;
2394
2395 case SRV_STATUS_NOSRV:
2396 case SRV_STATUS_INTERNAL:
2397 return err;
2398 default:
2399 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002400 }
willy tarreaudfece232006-05-02 00:19:57 +02002401}
2402
2403
2404/*
2405 * This function initiates a connection to the server assigned to this session
2406 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2407 * It can return one of :
2408 * - SN_ERR_NONE if everything's OK
2409 * - SN_ERR_SRVTO if there are no more servers
2410 * - SN_ERR_SRVCL if the connection was refused by the server
2411 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2412 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2413 * - SN_ERR_INTERNAL for any other purely internal errors
2414 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2415 */
2416int connect_server(struct session *s) {
2417 int fd, err;
2418
2419 if (!(s->flags & SN_ADDR_SET)) {
2420 err = assign_server_address(s);
2421 if (err != SRV_STATUS_OK)
2422 return SN_ERR_INTERNAL;
2423 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002424
willy tarreau0f7af912005-12-17 12:21:26 +01002425 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002426 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002427
2428 if (errno == ENFILE)
2429 send_log(s->proxy, LOG_EMERG,
2430 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2431 s->proxy->id, maxfd);
2432 else if (errno == EMFILE)
2433 send_log(s->proxy, LOG_EMERG,
2434 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2435 s->proxy->id, maxfd);
2436 else if (errno == ENOBUFS || errno == ENOMEM)
2437 send_log(s->proxy, LOG_EMERG,
2438 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2439 s->proxy->id, maxfd);
2440 /* this is a resource error */
2441 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002442 }
2443
willy tarreau9fe663a2005-12-17 13:02:59 +01002444 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002445 /* do not log anything there, it's a normal condition when this option
2446 * is used to serialize connections to a server !
2447 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002448 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2449 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002450 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002451 }
2452
willy tarreau0f7af912005-12-17 12:21:26 +01002453 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2454 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002455 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002456 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002457 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002458 }
2459
willy tarreaub952e1d2005-12-18 01:31:20 +01002460 if (s->proxy->options & PR_O_TCP_SRV_KA)
2461 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2462
willy tarreau0174f312005-12-18 01:02:42 +01002463 /* allow specific binding :
2464 * - server-specific at first
2465 * - proxy-specific next
2466 */
2467 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2468 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2469 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2470 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2471 s->proxy->id, s->srv->id);
2472 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002473 send_log(s->proxy, LOG_EMERG,
2474 "Cannot bind to source address before connect() for server %s/%s.\n",
2475 s->proxy->id, s->srv->id);
2476 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002477 }
2478 }
2479 else if (s->proxy->options & PR_O_BIND_SRC) {
2480 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2481 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2482 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2483 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002484 send_log(s->proxy, LOG_EMERG,
2485 "Cannot bind to source address before connect() for server %s/%s.\n",
2486 s->proxy->id, s->srv->id);
2487 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002488 }
willy tarreaua1598082005-12-17 13:08:06 +01002489 }
2490
willy tarreaub1285d52005-12-18 01:20:14 +01002491 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2492 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2493
2494 if (errno == EAGAIN || errno == EADDRINUSE) {
2495 char *msg;
2496 if (errno == EAGAIN) /* no free ports left, try again later */
2497 msg = "no free ports";
2498 else
2499 msg = "local address already in use";
2500
2501 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002502 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002503 send_log(s->proxy, LOG_EMERG,
2504 "Connect() failed for server %s/%s: %s.\n",
2505 s->proxy->id, s->srv->id, msg);
2506 return SN_ERR_RESOURCE;
2507 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002508 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002509 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002510 return SN_ERR_SRVTO;
2511 } else {
2512 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002513 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002514 close(fd);
2515 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002516 }
2517 }
2518
willy tarreau5cbea6f2005-12-17 12:48:26 +01002519 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002520 fdtab[fd].read = &event_srv_read;
2521 fdtab[fd].write = &event_srv_write;
2522 fdtab[fd].state = FD_STCONN; /* connection in progress */
2523
2524 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002525#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2526 if (PrevReadEvent) {
2527 assert(!(FD_ISSET(fd, PrevReadEvent)));
2528 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2529 }
2530#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002531
2532 fd_insert(fd);
willy tarreaucb406512006-05-18 00:52:35 +02002533 if (s->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02002534 s->srv->cur_sess++;
willy tarreaucb406512006-05-18 00:52:35 +02002535 if (s->srv->cur_sess > s->srv->cur_sess_max)
2536 s->srv->cur_sess_max = s->srv->cur_sess;
2537 }
willy tarreau0f7af912005-12-17 12:21:26 +01002538
2539 if (s->proxy->contimeout)
2540 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2541 else
2542 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002543 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002544}
2545
2546/*
2547 * this function is called on a read event from a client socket.
2548 * It returns 0.
2549 */
2550int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 struct task *t = fdtab[fd].owner;
2552 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002553 struct buffer *b = s->req;
2554 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002555
willy tarreau12350152005-12-18 01:03:27 +01002556#ifdef DEBUG_FULL
2557 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2558#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002559
willy tarreau0f7af912005-12-17 12:21:26 +01002560 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002561#ifdef FILL_BUFFERS
2562 while (1)
2563#else
2564 do
2565#endif
2566 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002567 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2568 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002569 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002570 }
2571 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002572 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002573 }
2574 else {
2575 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002576 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2577 * since it means that the rewrite protection has been removed. This
2578 * implies that the if statement can be removed.
2579 */
2580 if (max > b->rlim - b->data)
2581 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002582 }
2583
2584 if (max == 0) { /* not anymore room to store data */
2585 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002586 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002587 }
2588
willy tarreau3242e862005-12-17 12:27:53 +01002589#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002590 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002591 int skerr;
2592 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002593
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2595 if (skerr)
2596 ret = -1;
2597 else
2598 ret = recv(fd, b->r, max, 0);
2599 }
willy tarreau3242e862005-12-17 12:27:53 +01002600#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002601 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002602#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603 if (ret > 0) {
2604 b->r += ret;
2605 b->l += ret;
2606 s->res_cr = RES_DATA;
2607
2608 if (b->r == b->data + BUFSIZE) {
2609 b->r = b->data; /* wrap around the buffer */
2610 }
willy tarreaua1598082005-12-17 13:08:06 +01002611
2612 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002613 /* we hope to read more data or to get a close on next round */
2614 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002615 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002616 else if (ret == 0) {
2617 s->res_cr = RES_NULL;
2618 break;
2619 }
2620 else if (errno == EAGAIN) {/* ignore EAGAIN */
2621 break;
2622 }
2623 else {
2624 s->res_cr = RES_ERROR;
2625 fdtab[fd].state = FD_STERROR;
2626 break;
2627 }
2628 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002629#ifndef FILL_BUFFERS
2630 while (0);
2631#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002632 }
2633 else {
2634 s->res_cr = RES_ERROR;
2635 fdtab[fd].state = FD_STERROR;
2636 }
2637
willy tarreau5cbea6f2005-12-17 12:48:26 +01002638 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002639 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2641 else
2642 tv_eternity(&s->crexpire);
2643
2644 task_wakeup(&rq, t);
2645 }
willy tarreau0f7af912005-12-17 12:21:26 +01002646
willy tarreau0f7af912005-12-17 12:21:26 +01002647 return 0;
2648}
2649
2650
2651/*
2652 * this function is called on a read event from a server socket.
2653 * It returns 0.
2654 */
2655int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 struct task *t = fdtab[fd].owner;
2657 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002658 struct buffer *b = s->rep;
2659 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002660
willy tarreau12350152005-12-18 01:03:27 +01002661#ifdef DEBUG_FULL
2662 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2663#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002664
willy tarreau0f7af912005-12-17 12:21:26 +01002665 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002666#ifdef FILL_BUFFERS
2667 while (1)
2668#else
2669 do
2670#endif
2671 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002672 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2673 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002674 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002675 }
2676 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002677 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002678 }
2679 else {
2680 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002681 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2682 * since it means that the rewrite protection has been removed. This
2683 * implies that the if statement can be removed.
2684 */
2685 if (max > b->rlim - b->data)
2686 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002687 }
2688
2689 if (max == 0) { /* not anymore room to store data */
2690 FD_CLR(fd, StaticReadEvent);
2691 break;
2692 }
2693
willy tarreau3242e862005-12-17 12:27:53 +01002694#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002695 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002696 int skerr;
2697 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002698
willy tarreau5cbea6f2005-12-17 12:48:26 +01002699 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2700 if (skerr)
2701 ret = -1;
2702 else
2703 ret = recv(fd, b->r, max, 0);
2704 }
willy tarreau3242e862005-12-17 12:27:53 +01002705#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002706 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002707#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002708 if (ret > 0) {
2709 b->r += ret;
2710 b->l += ret;
2711 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002712
willy tarreau5cbea6f2005-12-17 12:48:26 +01002713 if (b->r == b->data + BUFSIZE) {
2714 b->r = b->data; /* wrap around the buffer */
2715 }
willy tarreaua1598082005-12-17 13:08:06 +01002716
2717 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002718 /* we hope to read more data or to get a close on next round */
2719 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002720 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002721 else if (ret == 0) {
2722 s->res_sr = RES_NULL;
2723 break;
2724 }
2725 else if (errno == EAGAIN) {/* ignore EAGAIN */
2726 break;
2727 }
2728 else {
2729 s->res_sr = RES_ERROR;
2730 fdtab[fd].state = FD_STERROR;
2731 break;
2732 }
2733 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002734#ifndef FILL_BUFFERS
2735 while (0);
2736#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002737 }
2738 else {
2739 s->res_sr = RES_ERROR;
2740 fdtab[fd].state = FD_STERROR;
2741 }
2742
willy tarreau5cbea6f2005-12-17 12:48:26 +01002743 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002744 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002745 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2746 else
2747 tv_eternity(&s->srexpire);
2748
2749 task_wakeup(&rq, t);
2750 }
willy tarreau0f7af912005-12-17 12:21:26 +01002751
willy tarreau0f7af912005-12-17 12:21:26 +01002752 return 0;
2753}
2754
2755/*
2756 * this function is called on a write event from a client socket.
2757 * It returns 0.
2758 */
2759int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002760 struct task *t = fdtab[fd].owner;
2761 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002762 struct buffer *b = s->rep;
2763 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002764
willy tarreau12350152005-12-18 01:03:27 +01002765#ifdef DEBUG_FULL
2766 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2767#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002768
2769 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002770 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002771 // max = BUFSIZE; BUG !!!!
2772 max = 0;
2773 }
2774 else if (b->r > b->w) {
2775 max = b->r - b->w;
2776 }
2777 else
2778 max = b->data + BUFSIZE - b->w;
2779
willy tarreau0f7af912005-12-17 12:21:26 +01002780 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002781 if (max == 0) {
2782 s->res_cw = RES_NULL;
2783 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002784 tv_eternity(&s->cwexpire);
2785 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002786 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002787 }
2788
willy tarreau3242e862005-12-17 12:27:53 +01002789#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002790 {
2791 int skerr;
2792 socklen_t lskerr = sizeof(skerr);
2793
2794 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2795 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002796 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002797 else
willy tarreau3242e862005-12-17 12:27:53 +01002798 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002799 }
willy tarreau3242e862005-12-17 12:27:53 +01002800#else
willy tarreau0f7af912005-12-17 12:21:26 +01002801 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002803
2804 if (ret > 0) {
2805 b->l -= ret;
2806 b->w += ret;
2807
2808 s->res_cw = RES_DATA;
2809
2810 if (b->w == b->data + BUFSIZE) {
2811 b->w = b->data; /* wrap around the buffer */
2812 }
2813 }
2814 else if (ret == 0) {
2815 /* nothing written, just make as if we were never called */
2816// s->res_cw = RES_NULL;
2817 return 0;
2818 }
2819 else if (errno == EAGAIN) /* ignore EAGAIN */
2820 return 0;
2821 else {
2822 s->res_cw = RES_ERROR;
2823 fdtab[fd].state = FD_STERROR;
2824 }
2825 }
2826 else {
2827 s->res_cw = RES_ERROR;
2828 fdtab[fd].state = FD_STERROR;
2829 }
2830
willy tarreaub1ff9db2005-12-17 13:51:03 +01002831 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002832 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002833 /* FIXME: to prevent the client from expiring read timeouts during writes,
2834 * we refresh it. A solution would be to merge read+write timeouts into a
2835 * unique one, although that needs some study particularly on full-duplex
2836 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002837 s->crexpire = s->cwexpire;
2838 }
willy tarreau0f7af912005-12-17 12:21:26 +01002839 else
2840 tv_eternity(&s->cwexpire);
2841
willy tarreau5cbea6f2005-12-17 12:48:26 +01002842 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002843 return 0;
2844}
2845
2846
2847/*
2848 * this function is called on a write event from a server socket.
2849 * It returns 0.
2850 */
2851int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002852 struct task *t = fdtab[fd].owner;
2853 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002854 struct buffer *b = s->req;
2855 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002856
willy tarreau12350152005-12-18 01:03:27 +01002857#ifdef DEBUG_FULL
2858 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2859#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002860
2861 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002862 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002863 // max = BUFSIZE; BUG !!!!
2864 max = 0;
2865 }
2866 else if (b->r > b->w) {
2867 max = b->r - b->w;
2868 }
2869 else
2870 max = b->data + BUFSIZE - b->w;
2871
willy tarreau0f7af912005-12-17 12:21:26 +01002872 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002873 if (max == 0) {
2874 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002875 if (s->srv_state == SV_STCONN) {
2876 int skerr;
2877 socklen_t lskerr = sizeof(skerr);
2878 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2879 if (skerr) {
2880 s->res_sw = RES_ERROR;
2881 fdtab[fd].state = FD_STERROR;
2882 task_wakeup(&rq, t);
2883 tv_eternity(&s->swexpire);
2884 FD_CLR(fd, StaticWriteEvent);
2885 return 0;
2886 }
2887 }
2888
willy tarreau0f7af912005-12-17 12:21:26 +01002889 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002890 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002891 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002892 tv_eternity(&s->swexpire);
2893 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002894 return 0;
2895 }
2896
willy tarreau3242e862005-12-17 12:27:53 +01002897#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002898 {
2899 int skerr;
2900 socklen_t lskerr = sizeof(skerr);
2901 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2902 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002903 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002904 else
willy tarreau3242e862005-12-17 12:27:53 +01002905 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002906 }
willy tarreau3242e862005-12-17 12:27:53 +01002907#else
willy tarreau0f7af912005-12-17 12:21:26 +01002908 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002909#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002910 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002911 if (ret > 0) {
2912 b->l -= ret;
2913 b->w += ret;
2914
2915 s->res_sw = RES_DATA;
2916
2917 if (b->w == b->data + BUFSIZE) {
2918 b->w = b->data; /* wrap around the buffer */
2919 }
2920 }
2921 else if (ret == 0) {
2922 /* nothing written, just make as if we were never called */
2923 // s->res_sw = RES_NULL;
2924 return 0;
2925 }
2926 else if (errno == EAGAIN) /* ignore EAGAIN */
2927 return 0;
2928 else {
2929 s->res_sw = RES_ERROR;
2930 fdtab[fd].state = FD_STERROR;
2931 }
2932 }
2933 else {
2934 s->res_sw = RES_ERROR;
2935 fdtab[fd].state = FD_STERROR;
2936 }
2937
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002938 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2939 * otherwise it could loop indefinitely !
2940 */
2941 if (s->srv_state != SV_STCONN) {
2942 if (s->proxy->srvtimeout) {
2943 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002944 /* FIXME: to prevent the server from expiring read timeouts during writes,
2945 * we refresh it. A solution would be to merge read+write+connect timeouts
2946 * into a unique one since we don't mind expiring on read or write, and none
2947 * of them is enabled while waiting for connect(), although that needs some
2948 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002949 s->srexpire = s->swexpire;
2950 }
2951 else
2952 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002953 }
willy tarreau0f7af912005-12-17 12:21:26 +01002954
willy tarreau5cbea6f2005-12-17 12:48:26 +01002955 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002956 return 0;
2957}
2958
2959
willy tarreaue0331262006-05-15 03:02:46 +02002960/* returns 1 if the buffer is empty, 0 otherwise */
2961static inline int buffer_isempty(struct buffer *buf) {
2962 return buf->l == 0;
2963}
2964
2965
2966/* returns 1 if the buffer is full, 0 otherwise */
2967static inline int buffer_isfull(struct buffer *buf) {
2968 return buf->l == BUFSIZE;
2969}
2970
2971
2972/* flushes any content from buffer <buf> */
2973void buffer_flush(struct buffer *buf) {
2974 buf->r = buf->h = buf->lr = buf->w = buf->data;
2975 buf->l = 0;
2976}
2977
2978
2979/* returns the maximum number of bytes writable at once in this buffer */
2980int buffer_max(struct buffer *buf) {
willy tarreaucb406512006-05-18 00:52:35 +02002981 if (buf->l == BUFSIZE)
2982 return 0;
2983 else if (buf->r >= buf->w)
willy tarreaue0331262006-05-15 03:02:46 +02002984 return buf->data + BUFSIZE - buf->r;
2985 else
2986 return buf->w - buf->r;
2987}
2988
2989
willy tarreau0f7af912005-12-17 12:21:26 +01002990/*
willy tarreaue0331262006-05-15 03:02:46 +02002991 * Tries to realign the given buffer, and returns how many bytes can be written
2992 * there at once without overwriting anything.
2993 */
2994int buffer_realign(struct buffer *buf) {
2995 if (buf->l == 0) {
2996 /* let's realign the buffer to optimize I/O */
willy tarreaucb406512006-05-18 00:52:35 +02002997 buf->r = buf->w = buf->h = buf->lr = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02002998 }
2999 return buffer_max(buf);
3000}
3001
3002
3003/* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of
3004 * success, or the number of bytes available otherwise.
willy tarreau1f431b52006-05-21 14:46:15 +02003005 * FIXME-20060521: handle unaligned data.
willy tarreaue0331262006-05-15 03:02:46 +02003006 */
3007int buffer_write(struct buffer *buf, const char *msg, int len) {
3008 int max;
3009
willy tarreaucb406512006-05-18 00:52:35 +02003010 max = buffer_realign(buf);
willy tarreaue0331262006-05-15 03:02:46 +02003011
3012 if (len > max)
3013 return max;
3014
3015 memcpy(buf->r, msg, len);
3016 buf->l += len;
3017 buf->r += len;
3018 if (buf->r == buf->data + BUFSIZE)
willy tarreaucb406512006-05-18 00:52:35 +02003019 buf->r = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02003020 return 0;
3021}
3022
3023
3024/*
willy tarreaue39cd132005-12-17 13:00:18 +01003025 * returns a message to the client ; the connection is shut down for read,
3026 * and the request is cleared so that no server connection can be initiated.
3027 * The client must be in a valid state for this (HEADER, DATA ...).
3028 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01003029 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003030 */
3031void client_retnclose(struct session *s, int len, const char *msg) {
3032 FD_CLR(s->cli_fd, StaticReadEvent);
3033 FD_SET(s->cli_fd, StaticWriteEvent);
3034 tv_eternity(&s->crexpire);
willy tarreauccf454a2006-06-13 19:28:58 +02003035 if (s->proxy->clitimeout)
3036 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3037 else
3038 tv_eternity(&s->cwexpire);
willy tarreaue39cd132005-12-17 13:00:18 +01003039 shutdown(s->cli_fd, SHUT_RD);
3040 s->cli_state = CL_STSHUTR;
willy tarreaue0331262006-05-15 03:02:46 +02003041 buffer_flush(s->rep);
3042 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003043 s->req->l = 0;
3044}
3045
3046
3047/*
3048 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01003049 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003050 */
3051void client_return(struct session *s, int len, const char *msg) {
willy tarreaue0331262006-05-15 03:02:46 +02003052 buffer_flush(s->rep);
3053 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003054 s->req->l = 0;
3055}
3056
willy tarreaue0331262006-05-15 03:02:46 +02003057/*
3058 * Produces data for the session <s> depending on its source. Expects to be
3059 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3060 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3061 * session, which it uses to keep on being called when there is free space in
3062 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3063 * if it changes the session state from CL_STSHUTR, otherwise 0.
3064 */
3065int produce_content(struct session *s) {
3066 struct buffer *rep = s->rep;
3067 struct proxy *px;
3068 struct server *sv;
willy tarreaucb406512006-05-18 00:52:35 +02003069 int msglen;
willy tarreaue0331262006-05-15 03:02:46 +02003070
3071 if (s->data_source == DATA_SRC_NONE) {
3072 s->flags &= ~SN_SELF_GEN;
3073 return 1;
3074 }
3075 else if (s->data_source == DATA_SRC_STATS) {
willy tarreau1f431b52006-05-21 14:46:15 +02003076 msglen = 0;
3077
3078 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
3079 unsigned int up;
3080
willy tarreaue0331262006-05-15 03:02:46 +02003081 s->flags |= SN_SELF_GEN; // more data will follow
willy tarreau1f431b52006-05-21 14:46:15 +02003082
3083 /* send the start of the HTTP response */
3084 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003085 "HTTP/1.0 200 OK\r\n"
3086 "Cache-Control: no-cache\r\n"
3087 "Connection: close\r\n"
3088 "\r\n\r\n");
3089
3090 s->logs.status = 200;
3091 client_retnclose(s, msglen, trash); // send the start of the response.
willy tarreau1f431b52006-05-21 14:46:15 +02003092 msglen = 0;
3093
willy tarreaue0331262006-05-15 03:02:46 +02003094 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3095 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3096 if (!(s->flags & SN_FINST_MASK))
3097 s->flags |= SN_FINST_R;
3098
3099 /* WARNING! This must fit in the first buffer !!! */
willy tarreau1f431b52006-05-21 14:46:15 +02003100 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003101 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3102 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3103 "<style type=\"text/css\"><!--\n"
3104 "body {"
3105 " font-family: helvetica, arial;"
3106 " font-size: 12px;"
3107 " font-weight: normal;"
3108 " color: black;"
3109 " background: white;"
3110 "}\n"
3111 "td {"
3112 " font-size: 12px;"
willy tarreaucb406512006-05-18 00:52:35 +02003113 " align: center;"
willy tarreaue0331262006-05-15 03:02:46 +02003114 "}\n"
3115 "h1 {"
3116 " font-size: xx-large;"
3117 " margin-bottom: 0.5em;"
3118 "}\n"
3119 "h2 {"
3120 " font-family: helvetica, arial;"
3121 " font-size: x-large;"
3122 " font-weight: bold;"
3123 " font-style: italic;"
3124 " color: #6020a0;"
3125 " margin-top: 0em;"
3126 " margin-bottom: 0em;"
3127 "}\n"
3128 "h3 {"
3129 " font-family: helvetica, arial;"
3130 " font-size: 16px;"
3131 " font-weight: bold;"
3132 " color: #b00040;"
3133 " background: #e8e8d0;"
3134 " margin-top: 0em;"
3135 " margin-bottom: 0em;"
3136 "}\n"
3137 "li {"
3138 " margin-top: 0.25em;"
3139 " margin-right: 2em;"
3140 "}\n"
3141 ".hr {"
3142 " margin-top: 0.25em;"
3143 " border-color: black;"
3144 " border-bottom-style: solid;"
willy tarreaucb406512006-05-18 00:52:35 +02003145 "}\n"
3146 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
3147 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3148 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3149 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3150 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
willy tarreaue0331262006-05-15 03:02:46 +02003151 "-->"
3152 "</style></head>");
3153
willy tarreaucb406512006-05-18 00:52:35 +02003154 if (buffer_write(rep, trash, msglen) != 0)
3155 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003156 msglen = 0;
willy tarreaue0331262006-05-15 03:02:46 +02003157
3158 up = (now.tv_sec - start_date.tv_sec);
3159
3160 /* WARNING! this has to fit the first packet too */
willy tarreau1f431b52006-05-21 14:46:15 +02003161 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003162 "<body><h1>" PRODUCT_NAME "</h1>\n"
3163 "<h2>Statistics Report for pid %d</h2>\n"
3164 "<hr width=\"100%%\" class=\"hr\">\n"
willy tarreau338be832006-05-21 08:58:06 +02003165 "<h3>&gt; General process information</h3>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003166 "<table border=0><tr><td align=\"left\">\n"
willy tarreaue0331262006-05-15 03:02:46 +02003167 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3168 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
willy tarreau338be832006-05-21 08:58:06 +02003169 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003170 "<b>maxsock = </b> %d<br>\n"
3171 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003172 "</td><td width=\"10%%\">\n"
3173 "</td><td align=\"right\">\n"
3174 "<table class=\"lgd\">"
3175 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
3176 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
3177 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
3178 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
3179 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
3180 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
3181 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
3182 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
3183 "</table>\n"
3184 "</tr></table>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003185 "",
3186 pid, pid, global.nbproc,
3187 up / 86400, (up % 86400) / 3600,
3188 (up % 3600) / 60, (up % 60),
willy tarreau338be832006-05-21 08:58:06 +02003189 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3190 global.rlimit_memmax ? " MB" : "",
willy tarreaue0331262006-05-15 03:02:46 +02003191 global.rlimit_nofile,
3192 global.maxsock,
3193 global.maxconn,
3194 actconn
3195 );
willy tarreaucb406512006-05-18 00:52:35 +02003196
3197 if (buffer_write(rep, trash, msglen) != 0)
3198 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003199 msglen = 0;
3200
3201 s->data_state = DATA_ST_DATA;
3202 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
3203
willy tarreaue0331262006-05-15 03:02:46 +02003204 px = s->data_ctx.stats.px = proxy;
willy tarreau1f431b52006-05-21 14:46:15 +02003205 s->data_ctx.stats.px_st = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02003206 }
3207
3208 while (s->data_ctx.stats.px) {
willy tarreaucb406512006-05-18 00:52:35 +02003209 int dispatch_sess, dispatch_cum;
willy tarreau1f431b52006-05-21 14:46:15 +02003210 int failed_checks, down_trans;
willy tarreaue3b30652006-05-21 16:23:22 +02003211 int failed_secu, failed_conns, failed_resp;
willy tarreaucb406512006-05-18 00:52:35 +02003212
willy tarreau1f431b52006-05-21 14:46:15 +02003213 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
3214 /* we are on a new proxy */
willy tarreaue0331262006-05-15 03:02:46 +02003215 px = s->data_ctx.stats.px;
willy tarreau1f431b52006-05-21 14:46:15 +02003216
3217 /* skip the disabled proxies */
3218 if (px->state == PR_STSTOPPED)
3219 goto next_proxy;
3220
3221 if (s->proxy->uri_auth && s->proxy->uri_auth->scope) {
3222 /* we have a limited scope, we have to check the proxy name */
3223 struct stat_scope *scope;
3224 int len;
3225
3226 len = strlen(px->id);
3227 scope = s->proxy->uri_auth->scope;
3228
3229 while (scope) {
3230 /* match exact proxy name */
3231 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3232 break;
3233
3234 /* match '.' which means 'self' proxy */
3235 if (!strcmp(scope->px_id, ".") && px == s->proxy)
3236 break;
3237 scope = scope->next;
3238 }
3239
3240 /* proxy name not found */
3241 if (scope == NULL)
3242 goto next_proxy;
3243 }
3244
3245 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue0331262006-05-15 03:02:46 +02003246 "<h3>&gt; Proxy instance %s : "
3247 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
3248 "",
3249 px->id,
3250 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
3251
3252 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaue3b30652006-05-21 16:23:22 +02003253 "<table cols=\"16\" class=\"tbl\">\n"
willy tarreaucb406512006-05-18 00:52:35 +02003254 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3255 "<th colspan=5>Server</th>"
3256 "<th colspan=2>Queue</th>"
3257 "<th colspan=4>Sessions</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003258 "<th colspan=5>Errors</th></tr>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003259 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3260 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
3261 "<th>Curr.</th><th>Max.</th>"
3262 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
willy tarreaue3b30652006-05-21 16:23:22 +02003263 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
willy tarreaue0331262006-05-15 03:02:46 +02003264
3265 if (buffer_write(rep, trash, msglen) != 0)
3266 return 0;
willy tarreau1f431b52006-05-21 14:46:15 +02003267 msglen = 0;
3268
willy tarreaue0331262006-05-15 03:02:46 +02003269 s->data_ctx.stats.sv = px->srv;
willy tarreau1f431b52006-05-21 14:46:15 +02003270 s->data_ctx.stats.px_st = DATA_ST_DATA;
willy tarreaue0331262006-05-15 03:02:46 +02003271 }
3272
willy tarreaucb406512006-05-18 00:52:35 +02003273 px = s->data_ctx.stats.px;
3274
willy tarreau1f431b52006-05-21 14:46:15 +02003275 /* stats.sv has been initialized above */
willy tarreaue0331262006-05-15 03:02:46 +02003276 while (s->data_ctx.stats.sv != NULL) {
willy tarreaucb406512006-05-18 00:52:35 +02003277 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
3278 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
3279 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3280 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
3281
willy tarreaue0331262006-05-15 03:02:46 +02003282 sv = s->data_ctx.stats.sv;
willy tarreaucb406512006-05-18 00:52:35 +02003283
willy tarreaucb406512006-05-18 00:52:35 +02003284 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3285 if (!(sv->state & SRV_CHECKED))
3286 sv_state = 4;
3287 else if (sv->state & SRV_RUNNING)
3288 if (sv->health == sv->rise + sv->fall - 1)
3289 sv_state = 3; /* UP */
3290 else
3291 sv_state = 2; /* going down */
3292 else
3293 if (sv->health)
3294 sv_state = 1; /* going up */
3295 else
3296 sv_state = 0; /* DOWN */
3297
3298 /* name, weight */
willy tarreau1f431b52006-05-21 14:46:15 +02003299 msglen += snprintf(trash, sizeof(trash),
willy tarreaucb406512006-05-18 00:52:35 +02003300 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
3301 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
3302 sv->id, sv->uweight+1);
3303 /* status */
3304 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
3305 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3306 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3307
3308 /* act, bck */
3309 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3310 "</td><td>%s</td><td>%s</td>",
willy tarreaue0331262006-05-15 03:02:46 +02003311 (sv->state & SRV_BACKUP) ? "-" : "Y",
3312 (sv->state & SRV_BACKUP) ? "Y" : "-");
willy tarreaucb406512006-05-18 00:52:35 +02003313
3314 /* queue : current, max */
3315 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3316 "<td align=right>%d</td><td align=right>%d</td>",
3317 sv->nbpend, sv->nbpend_max);
3318
3319 /* sessions : current, max, limit, cumul */
3320 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3321 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
3322 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
3323
willy tarreaue3b30652006-05-21 16:23:22 +02003324 /* errors : connect, response, security */
3325 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3326 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3327 sv->failed_conns, sv->failed_resp, sv->failed_secu);
3328
3329 /* check failures : unique, fatal */
willy tarreau338be832006-05-21 08:58:06 +02003330 if (sv->state & SRV_CHECKED)
3331 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3332 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3333 sv->failed_checks, sv->down_trans);
3334 else
3335 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3336 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003337
willy tarreau1f431b52006-05-21 14:46:15 +02003338 if (buffer_write(rep, trash, msglen) != 0)
3339 return 0;
3340 msglen = 0;
3341
3342 s->data_ctx.stats.sv = sv->next;
3343 } /* while sv */
3344
3345 /* now we are past the last server, we'll dump information about the dispatcher */
3346
3347 /* We have to count down from the proxy to the servers to tell how
3348 * many sessions are on the dispatcher, and how many checks have
3349 * failed. We cannot count this during the servers dump because it
3350 * might be interrupted multiple times.
3351 */
3352 dispatch_sess = px->nbconn;
willy tarreaue3b30652006-05-21 16:23:22 +02003353 dispatch_cum = px->cum_conn;
3354 failed_secu = px->failed_secu;
3355 failed_conns = px->failed_conns;
3356 failed_resp = px->failed_resp;
willy tarreau1f431b52006-05-21 14:46:15 +02003357 failed_checks = down_trans = 0;
3358
3359 sv = px->srv;
3360 while (sv) {
3361 dispatch_sess -= sv->cur_sess;
3362 dispatch_cum -= sv->cum_sess;
willy tarreaue3b30652006-05-21 16:23:22 +02003363 failed_conns -= sv->failed_conns;
3364 failed_resp -= sv->failed_resp;
3365 failed_secu -= sv->failed_secu;
3366 if (sv->state & SRV_CHECKED) {
3367 failed_checks += sv->failed_checks;
3368 down_trans += sv->down_trans;
3369 }
willy tarreaue0331262006-05-15 03:02:46 +02003370 sv = sv->next;
willy tarreau1f431b52006-05-21 14:46:15 +02003371 }
willy tarreaucb406512006-05-18 00:52:35 +02003372
willy tarreau1f431b52006-05-21 14:46:15 +02003373 /* name, weight, status, act, bck */
3374 msglen += snprintf(trash + msglen, sizeof(trash),
3375 "<tr align=center bgcolor=\"#e8e8d0\">"
3376 "<td>Dispatcher</td><td>-</td>"
3377 "<td>%s</td><td>-</td><td>-</td>",
3378 px->state == PR_STRUN ? "UP" : "DOWN");
willy tarreaucb406512006-05-18 00:52:35 +02003379
willy tarreau1f431b52006-05-21 14:46:15 +02003380 /* queue : current, max */
3381 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3382 "<td align=right>%d</td><td align=right>%d</td>",
3383 px->nbpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003384
willy tarreau1f431b52006-05-21 14:46:15 +02003385 /* sessions : current, max, limit, cumul. */
3386 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3387 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
3388 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
willy tarreaucb406512006-05-18 00:52:35 +02003389
willy tarreaue3b30652006-05-21 16:23:22 +02003390 /* errors : connect, response, security */
3391 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3392 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3393 failed_conns, failed_resp, failed_secu);
3394
3395 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003396 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3397 "<td align=right>-</td><td align=right>-</td></tr>\n");
willy tarreaucb406512006-05-18 00:52:35 +02003398
willy tarreaucb406512006-05-18 00:52:35 +02003399
willy tarreau1f431b52006-05-21 14:46:15 +02003400 /* now the summary for the whole proxy */
3401 /* name, weight, status, act, bck */
3402 msglen += snprintf(trash + msglen, sizeof(trash),
3403 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3404 "<td><b>Total</b></td><td>-</td>"
3405 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3406 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3407 px->srv_act, px->srv_bck);
willy tarreaucb406512006-05-18 00:52:35 +02003408
willy tarreau1f431b52006-05-21 14:46:15 +02003409 /* queue : current, max */
3410 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3411 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3412 px->totpend, px->nbpend_max);
willy tarreaucb406512006-05-18 00:52:35 +02003413
willy tarreau1f431b52006-05-21 14:46:15 +02003414 /* sessions : current, max, limit, cumul */
3415 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3416 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3417 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
willy tarreaucb406512006-05-18 00:52:35 +02003418
willy tarreaue3b30652006-05-21 16:23:22 +02003419 /* errors : connect, response, security */
3420 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3421 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3422 px->failed_conns, px->failed_resp, px->failed_secu);
3423
3424 /* check failures : unique, fatal */
willy tarreau1f431b52006-05-21 14:46:15 +02003425 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3426 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3427 failed_checks, down_trans);
willy tarreaucb406512006-05-18 00:52:35 +02003428
willy tarreau1f431b52006-05-21 14:46:15 +02003429 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
3430
3431 if (buffer_write(rep, trash, msglen) != 0)
3432 return 0;
3433 msglen = 0;
3434
3435 s->data_ctx.stats.px_st = DATA_ST_INIT;
3436 next_proxy:
3437 s->data_ctx.stats.px = px->next;
willy tarreaucb406512006-05-18 00:52:35 +02003438 } /* proxy loop */
willy tarreaue0331262006-05-15 03:02:46 +02003439 /* here, we just have reached the sv == NULL and px == NULL */
3440 s->flags &= ~SN_SELF_GEN;
3441 return 1;
3442 }
3443 else {
3444 /* unknown data source */
3445 s->logs.status = 500;
3446 client_retnclose(s, s->proxy->errmsg.len500, s->proxy->errmsg.msg500);
3447 if (!(s->flags & SN_ERR_MASK))
3448 s->flags |= SN_ERR_PRXCOND;
3449 if (!(s->flags & SN_FINST_MASK))
3450 s->flags |= SN_FINST_R;
3451 s->flags &= SN_SELF_GEN;
3452 return 1;
3453 }
3454}
3455
3456
willy tarreau9fe663a2005-12-17 13:02:59 +01003457/*
3458 * send a log for the session when we have enough info about it
3459 */
3460void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003461 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01003462 struct proxy *p = s->proxy;
3463 int log;
3464 char *uri;
3465 char *pxid;
3466 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01003467 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01003468
3469 /* This is a first attempt at a better logging system.
3470 * For now, we rely on send_log() to provide the date, although it obviously
3471 * is the date of the log and not of the request, and most fields are not
3472 * computed.
3473 */
3474
willy tarreaua1598082005-12-17 13:08:06 +01003475 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01003476
willy tarreau8a86dbf2005-12-18 00:45:59 +01003477 if (s->cli_addr.ss_family == AF_INET)
3478 inet_ntop(AF_INET,
3479 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3480 pn, sizeof(pn));
3481 else
3482 inet_ntop(AF_INET6,
3483 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3484 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01003485
willy tarreauc1cae632005-12-17 14:12:23 +01003486 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01003487 pxid = p->id;
willy tarreau8cd31142006-05-21 22:08:00 +02003488 srv = (p->to_log & LW_SVID) ?
3489 (s->data_source != DATA_SRC_STATS) ?
3490 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01003491
willy tarreauc1cae632005-12-17 14:12:23 +01003492 tm = localtime(&s->logs.tv_accept.tv_sec);
3493 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01003494 char tmpline[MAX_SYSLOG_LEN], *h;
3495 int hdr;
3496
3497 h = tmpline;
3498 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
3499 *(h++) = ' ';
3500 *(h++) = '{';
3501 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
3502 if (hdr)
3503 *(h++) = '|';
3504 if (s->req_cap[hdr] != NULL)
3505 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
3506 }
3507 *(h++) = '}';
3508 }
3509
3510 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
3511 *(h++) = ' ';
3512 *(h++) = '{';
3513 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
3514 if (hdr)
3515 *(h++) = '|';
3516 if (s->rsp_cap[hdr] != NULL)
3517 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
3518 }
3519 *(h++) = '}';
3520 }
3521
3522 if (h < tmpline + sizeof(tmpline) - 4) {
3523 *(h++) = ' ';
3524 *(h++) = '"';
3525 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
3526 *(h++) = '"';
3527 }
3528 *h = '\0';
3529
willy tarreau5e69b162006-05-12 19:49:37 +02003530 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d/%d %d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01003531 pn,
3532 (s->cli_addr.ss_family == AF_INET) ?
3533 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3534 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01003535 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3536 tm->tm_hour, tm->tm_min, tm->tm_sec,
3537 pxid, srv,
3538 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02003539 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
3540 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01003541 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003542 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3543 s->logs.status,
3544 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01003545 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
3546 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01003547 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
3548 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
3549 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
3550 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02003551 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3552 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003553 }
3554 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003555 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%s%d %s%lld %c%c %d/%d/%d %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01003556 pn,
3557 (s->cli_addr.ss_family == AF_INET) ?
3558 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3559 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003560 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3561 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003562 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003563 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3564 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003565 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3566 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003567 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003568 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003569 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3570 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003571 }
3572
3573 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003574}
3575
willy tarreaue39cd132005-12-17 13:00:18 +01003576
3577/*
willy tarreau0f7af912005-12-17 12:21:26 +01003578 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003579 * to an accept. It tries to accept as many connections as possible.
3580 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003581 */
3582int event_accept(int fd) {
3583 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003584 struct session *s;
3585 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003586 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003587 int max_accept;
3588
3589 if (global.nbproc > 1)
3590 max_accept = 8; /* let other processes catch some connections too */
3591 else
3592 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003593
willy tarreauc2becdc2006-03-19 19:36:48 +01003594 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003595 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003596 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003597
willy tarreaub1285d52005-12-18 01:20:14 +01003598 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3599 switch (errno) {
3600 case EAGAIN:
3601 case EINTR:
3602 case ECONNABORTED:
3603 return 0; /* nothing more to accept */
3604 case ENFILE:
3605 send_log(p, LOG_EMERG,
3606 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3607 p->id, maxfd);
3608 return 0;
3609 case EMFILE:
3610 send_log(p, LOG_EMERG,
3611 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3612 p->id, maxfd);
3613 return 0;
3614 case ENOBUFS:
3615 case ENOMEM:
3616 send_log(p, LOG_EMERG,
3617 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3618 p->id, maxfd);
3619 return 0;
3620 default:
3621 return 0;
3622 }
3623 }
willy tarreau0f7af912005-12-17 12:21:26 +01003624
willy tarreau5cbea6f2005-12-17 12:48:26 +01003625 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3626 Alert("out of memory in event_accept().\n");
3627 FD_CLR(fd, StaticReadEvent);
3628 p->state = PR_STIDLE;
3629 close(cfd);
3630 return 0;
3631 }
willy tarreau0f7af912005-12-17 12:21:26 +01003632
willy tarreaub1285d52005-12-18 01:20:14 +01003633 /* if this session comes from a known monitoring system, we want to ignore
3634 * it as soon as possible, which means closing it immediately for TCP.
3635 */
3636 s->flags = 0;
3637 if (addr.ss_family == AF_INET &&
3638 p->mon_mask.s_addr &&
3639 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3640 if (p->mode == PR_MODE_TCP) {
3641 close(cfd);
3642 pool_free(session, s);
3643 continue;
3644 }
3645 s->flags |= SN_MONITOR;
3646 }
3647
willy tarreau5cbea6f2005-12-17 12:48:26 +01003648 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3649 Alert("out of memory in event_accept().\n");
3650 FD_CLR(fd, StaticReadEvent);
3651 p->state = PR_STIDLE;
3652 close(cfd);
3653 pool_free(session, s);
3654 return 0;
3655 }
willy tarreau0f7af912005-12-17 12:21:26 +01003656
willy tarreau5cbea6f2005-12-17 12:48:26 +01003657 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003658 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003659 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3660 close(cfd);
3661 pool_free(task, t);
3662 pool_free(session, s);
3663 return 0;
3664 }
willy tarreau0f7af912005-12-17 12:21:26 +01003665
willy tarreau5cbea6f2005-12-17 12:48:26 +01003666 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3667 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3668 (char *) &one, sizeof(one)) == -1)) {
3669 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3670 close(cfd);
3671 pool_free(task, t);
3672 pool_free(session, s);
3673 return 0;
3674 }
willy tarreau0f7af912005-12-17 12:21:26 +01003675
willy tarreaub952e1d2005-12-18 01:31:20 +01003676 if (p->options & PR_O_TCP_CLI_KA)
3677 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3678
willy tarreau9fe663a2005-12-17 13:02:59 +01003679 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003680 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003681 t->state = TASK_IDLE;
3682 t->process = process_session;
3683 t->context = s;
3684
3685 s->task = t;
3686 s->proxy = p;
3687 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3688 s->srv_state = SV_STIDLE;
3689 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003690
willy tarreau9fe663a2005-12-17 13:02:59 +01003691 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3692 s->cli_fd = cfd;
3693 s->srv_fd = -1;
willy tarreau9e138862006-05-14 23:06:28 +02003694 s->req_line.len = -1;
3695 s->auth_hdr.len = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003696 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003697 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003698 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003699
willy tarreaub1285d52005-12-18 01:20:14 +01003700 if (s->flags & SN_MONITOR)
3701 s->logs.logwait = 0;
3702 else
3703 s->logs.logwait = p->to_log;
3704
willy tarreaua1598082005-12-17 13:08:06 +01003705 s->logs.tv_accept = now;
3706 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003707 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003708 s->logs.t_connect = -1;
3709 s->logs.t_data = -1;
3710 s->logs.t_close = 0;
3711 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003712 s->logs.cli_cookie = NULL;
3713 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003714 s->logs.status = -1;
3715 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003716 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3717 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003718
willy tarreaue0331262006-05-15 03:02:46 +02003719 s->data_source = DATA_SRC_NONE;
willy tarreaue0331262006-05-15 03:02:46 +02003720
willy tarreau2f6ba652005-12-17 13:57:42 +01003721 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003722 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003723
willy tarreau4302f492005-12-18 01:00:37 +01003724 if (p->nb_req_cap > 0) {
3725 if ((s->req_cap =
3726 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3727 == NULL) { /* no memory */
3728 close(cfd); /* nothing can be done for this fd without memory */
3729 pool_free(task, t);
3730 pool_free(session, s);
3731 return 0;
3732 }
3733 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3734 }
3735 else
3736 s->req_cap = NULL;
3737
3738 if (p->nb_rsp_cap > 0) {
3739 if ((s->rsp_cap =
3740 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3741 == NULL) { /* no memory */
3742 if (s->req_cap != NULL)
3743 pool_free_to(p->req_cap_pool, s->req_cap);
3744 close(cfd); /* nothing can be done for this fd without memory */
3745 pool_free(task, t);
3746 pool_free(session, s);
3747 return 0;
3748 }
3749 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3750 }
3751 else
3752 s->rsp_cap = NULL;
3753
willy tarreau5cbea6f2005-12-17 12:48:26 +01003754 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3755 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003756 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003757 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003758
willy tarreau8a86dbf2005-12-18 00:45:59 +01003759 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003760 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003761 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003762 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003763
willy tarreau9fe663a2005-12-17 13:02:59 +01003764 if (p->to_log) {
3765 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003766 if (s->logs.logwait & LW_CLIP)
3767 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003768 sess_log(s);
3769 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003770 else if (s->cli_addr.ss_family == AF_INET) {
3771 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3772 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3773 sn, sizeof(sn)) &&
3774 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3775 pn, sizeof(pn))) {
3776 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3777 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3778 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3779 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3780 }
3781 }
3782 else {
3783 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3784 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3785 sn, sizeof(sn)) &&
3786 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3787 pn, sizeof(pn))) {
3788 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3789 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3790 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3791 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3792 }
3793 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003794 }
willy tarreau0f7af912005-12-17 12:21:26 +01003795
willy tarreau982249e2005-12-18 00:57:06 +01003796 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003797 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003798 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003799 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003800 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003801 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003802 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003803 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003804
willy tarreau8a86dbf2005-12-18 00:45:59 +01003805 if (s->cli_addr.ss_family == AF_INET) {
3806 char pn[INET_ADDRSTRLEN];
3807 inet_ntop(AF_INET,
3808 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3809 pn, sizeof(pn));
3810
3811 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3812 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3813 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3814 }
3815 else {
3816 char pn[INET6_ADDRSTRLEN];
3817 inet_ntop(AF_INET6,
3818 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3819 pn, sizeof(pn));
3820
3821 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3822 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3823 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3824 }
3825
willy tarreauef900ab2005-12-17 12:52:52 +01003826 write(1, trash, len);
3827 }
willy tarreau0f7af912005-12-17 12:21:26 +01003828
willy tarreau5cbea6f2005-12-17 12:48:26 +01003829 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003830 if (s->rsp_cap != NULL)
3831 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3832 if (s->req_cap != NULL)
3833 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003834 close(cfd); /* nothing can be done for this fd without memory */
3835 pool_free(task, t);
3836 pool_free(session, s);
3837 return 0;
3838 }
willy tarreau4302f492005-12-18 01:00:37 +01003839
willy tarreau5cbea6f2005-12-17 12:48:26 +01003840 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003841 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003842 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3843 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003844 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003845 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003846
willy tarreau5cbea6f2005-12-17 12:48:26 +01003847 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3848 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003849 if (s->rsp_cap != NULL)
3850 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3851 if (s->req_cap != NULL)
3852 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003853 close(cfd); /* nothing can be done for this fd without memory */
3854 pool_free(task, t);
3855 pool_free(session, s);
3856 return 0;
3857 }
3858 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003859 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003860 s->rep->h = s->rep->r = s->rep->lr = s->rep->w = s->rep->rlim = s->rep->data;
willy tarreau0f7af912005-12-17 12:21:26 +01003861
willy tarreau5cbea6f2005-12-17 12:48:26 +01003862 fdtab[cfd].read = &event_cli_read;
3863 fdtab[cfd].write = &event_cli_write;
3864 fdtab[cfd].owner = t;
3865 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003866
willy tarreaub1285d52005-12-18 01:20:14 +01003867 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3868 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3869 /* Either we got a request from a monitoring system on an HTTP instance,
3870 * or we're in health check mode with the 'httpchk' option enabled. In
3871 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3872 */
3873 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3874 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3875 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003876 }
3877 else {
3878 FD_SET(cfd, StaticReadEvent);
3879 }
3880
willy tarreaub952e1d2005-12-18 01:31:20 +01003881#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3882 if (PrevReadEvent) {
3883 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3884 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3885 }
3886#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003887 fd_insert(cfd);
3888
3889 tv_eternity(&s->cnexpire);
3890 tv_eternity(&s->srexpire);
3891 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003892 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003893 tv_eternity(&s->cwexpire);
3894
willy tarreaub1285d52005-12-18 01:20:14 +01003895 if (s->proxy->clitimeout) {
3896 if (FD_ISSET(cfd, StaticReadEvent))
3897 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3898 if (FD_ISSET(cfd, StaticWriteEvent))
3899 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3900 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003901
willy tarreaub1285d52005-12-18 01:20:14 +01003902 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003903
3904 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003905
3906 if (p->mode != PR_MODE_HEALTH)
3907 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003908
3909 p->nbconn++;
willy tarreaucb406512006-05-18 00:52:35 +02003910 if (p->nbconn > p->nbconn_max)
3911 p->nbconn_max = p->nbconn;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003912 actconn++;
3913 totalconn++;
3914
willy tarreaub952e1d2005-12-18 01:31:20 +01003915 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003916 } /* end of while (p->nbconn < p->maxconn) */
3917 return 0;
3918}
willy tarreau0f7af912005-12-17 12:21:26 +01003919
willy tarreau0f7af912005-12-17 12:21:26 +01003920
willy tarreau5cbea6f2005-12-17 12:48:26 +01003921/*
3922 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003923 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3924 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003925 * or -1 if an error occured.
3926 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003927int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003928 struct task *t = fdtab[fd].owner;
3929 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003930 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003931 socklen_t lskerr = sizeof(skerr);
3932
willy tarreau05be12b2006-03-19 19:35:00 +01003933 skerr = 1;
3934 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3935 || (skerr != 0)) {
3936 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003937 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003938 fdtab[fd].state = FD_STERROR;
3939 FD_CLR(fd, StaticWriteEvent);
3940 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003941 else if (s->result != -1) {
3942 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003943 if (s->proxy->options & PR_O_HTTP_CHK) {
3944 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003945 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003946 * so we'll send the request, and won't wake the checker up now.
3947 */
3948#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003949 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003950#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003951 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003952#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003953 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003954 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3955 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3956 return 0;
3957 }
willy tarreau05be12b2006-03-19 19:35:00 +01003958 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003959 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003960 FD_CLR(fd, StaticWriteEvent);
3961 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003962 }
3963 else {
3964 /* good TCP connection is enough */
3965 s->result = 1;
3966 }
3967 }
3968
3969 task_wakeup(&rq, t);
3970 return 0;
3971}
3972
willy tarreau0f7af912005-12-17 12:21:26 +01003973
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003974/*
3975 * This function is used only for server health-checks. It handles
3976 * the server's reply to an HTTP request. It returns 1 if the server replies
3977 * 2xx or 3xx (valid responses), or -1 in other cases.
3978 */
3979int event_srv_chk_r(int fd) {
3980 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003981 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003982 struct task *t = fdtab[fd].owner;
3983 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003984 int skerr;
3985 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003986
willy tarreaua4a583a2005-12-18 01:39:19 +01003987 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003988
willy tarreau05be12b2006-03-19 19:35:00 +01003989 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3990 if (!skerr) {
3991#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003992 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003993#else
willy tarreau05be12b2006-03-19 19:35:00 +01003994 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3995 * but the connection was closed on the remote end. Fortunately, recv still
3996 * works correctly and we don't need to do the getsockopt() on linux.
3997 */
3998 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003999#endif
willy tarreau05be12b2006-03-19 19:35:00 +01004000
4001 if ((len >= sizeof("HTTP/1.0 000")) &&
4002 !memcmp(reply, "HTTP/1.", 7) &&
4003 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
4004 result = 1;
4005 }
4006
4007 if (result == -1)
4008 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01004009
4010 if (s->result != -1)
4011 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004012
4013 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004014 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01004015 return 0;
4016}
4017
4018
4019/*
4020 * this function writes the string <str> at position <pos> which must be in buffer <b>,
4021 * and moves <end> just after the end of <str>.
4022 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
4023 * the shift value (positive or negative) is returned.
4024 * If there's no space left, the move is not done.
4025 *
4026 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004027int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01004028 int delta;
4029 int len;
4030
4031 len = strlen(str);
4032 delta = len - (end - pos);
4033
4034 if (delta + b->r >= b->data + BUFSIZE)
4035 return 0; /* no space left */
4036
4037 /* first, protect the end of the buffer */
4038 memmove(end + delta, end, b->data + b->l - end);
4039
4040 /* now, copy str over pos */
4041 memcpy(pos, str,len);
4042
willy tarreau5cbea6f2005-12-17 12:48:26 +01004043 /* we only move data after the displaced zone */
4044 if (b->r > pos) b->r += delta;
4045 if (b->w > pos) b->w += delta;
4046 if (b->h > pos) b->h += delta;
4047 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004048 b->l += delta;
4049
4050 return delta;
4051}
4052
willy tarreau8337c6b2005-12-17 13:41:01 +01004053/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01004054 * len is 0.
4055 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004056int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01004057 int delta;
4058
4059 delta = len - (end - pos);
4060
4061 if (delta + b->r >= b->data + BUFSIZE)
4062 return 0; /* no space left */
4063
Willy TARREAUe78ae262006-01-08 01:24:12 +01004064 if (b->data + b->l < end)
4065 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
4066 return 0;
4067
willy tarreau0f7af912005-12-17 12:21:26 +01004068 /* first, protect the end of the buffer */
4069 memmove(end + delta, end, b->data + b->l - end);
4070
4071 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01004072 if (len)
4073 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01004074
willy tarreau5cbea6f2005-12-17 12:48:26 +01004075 /* we only move data after the displaced zone */
4076 if (b->r > pos) b->r += delta;
4077 if (b->w > pos) b->w += delta;
4078 if (b->h > pos) b->h += delta;
4079 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01004080 b->l += delta;
4081
4082 return delta;
4083}
4084
4085
4086int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
4087 char *old_dst = dst;
4088
4089 while (*str) {
4090 if (*str == '\\') {
4091 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01004092 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004093 int len, num;
4094
4095 num = *str - '0';
4096 str++;
4097
willy tarreau8a86dbf2005-12-18 00:45:59 +01004098 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01004099 len = matches[num].rm_eo - matches[num].rm_so;
4100 memcpy(dst, src + matches[num].rm_so, len);
4101 dst += len;
4102 }
4103
4104 }
4105 else if (*str == 'x') {
4106 unsigned char hex1, hex2;
4107 str++;
4108
willy tarreauc1f47532005-12-18 01:08:26 +01004109 hex1 = toupper(*str++) - '0';
4110 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01004111
4112 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4113 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4114 *dst++ = (hex1<<4) + hex2;
4115 }
4116 else
4117 *dst++ = *str++;
4118 }
4119 else
4120 *dst++ = *str++;
4121 }
4122 *dst = 0;
4123 return dst - old_dst;
4124}
4125
willy tarreauc1f47532005-12-18 01:08:26 +01004126static int ishex(char s)
4127{
4128 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
4129}
4130
4131/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
4132char *check_replace_string(char *str)
4133{
4134 char *err = NULL;
4135 while (*str) {
4136 if (*str == '\\') {
4137 err = str; /* in case of a backslash, we return the pointer to it */
4138 str++;
4139 if (!*str)
4140 return err;
4141 else if (isdigit((int)*str))
4142 err = NULL;
4143 else if (*str == 'x') {
4144 str++;
4145 if (!ishex(*str))
4146 return err;
4147 str++;
4148 if (!ishex(*str))
4149 return err;
4150 err = NULL;
4151 }
4152 else {
4153 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
4154 err = NULL;
4155 }
4156 }
4157 str++;
4158 }
4159 return err;
4160}
4161
willy tarreau0f7af912005-12-17 12:21:26 +01004162/*
4163 * manages the client FSM and its socket. BTW, it also tries to handle the
4164 * cookie. It returns 1 if a state has changed (and a resync may be needed),
4165 * 0 else.
4166 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004167int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004168 int s = t->srv_state;
4169 int c = t->cli_state;
4170 struct buffer *req = t->req;
4171 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004172 int method_checked = 0;
4173 appsess *asession_temp = NULL;
4174 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01004175
willy tarreau750a4722005-12-17 13:21:24 +01004176#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01004177 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
4178 cli_stnames[c], srv_stnames[s],
4179 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4180 t->crexpire.tv_sec, t->crexpire.tv_usec,
4181 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01004182#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004183 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4184 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4185 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4186 //);
4187 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004188 /* now parse the partial (or complete) headers */
4189 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
4190 char *ptr;
4191 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01004192 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01004193
willy tarreau5cbea6f2005-12-17 12:48:26 +01004194 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01004195
willy tarreau0f7af912005-12-17 12:21:26 +01004196 /* look for the end of the current header */
4197 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
4198 ptr++;
4199
willy tarreau5cbea6f2005-12-17 12:48:26 +01004200 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004201 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02004202
4203 /*
4204 * first, let's check that it's not a leading empty line, in
4205 * which case we'll ignore and remove it (according to RFC2616).
4206 */
4207 if (req->h == req->data) {
4208 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4209 if (ptr > req->r - 2) {
4210 /* this is a partial header, let's wait for more to come */
4211 req->lr = ptr;
4212 break;
4213 }
4214
4215 /* now we know that *ptr is either \r or \n,
4216 * and that there are at least 1 char after it.
4217 */
4218 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4219 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4220 else
4221 req->lr = ptr + 2; /* \r\n or \n\r */
4222 /* ignore empty leading lines */
4223 buffer_replace2(req, req->h, req->lr, NULL, 0);
4224 req->h = req->lr;
4225 continue;
4226 }
4227
willy tarreau5cbea6f2005-12-17 12:48:26 +01004228 /* we can only get here after an end of headers */
4229 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004230
willy tarreaue39cd132005-12-17 13:00:18 +01004231 if (t->flags & SN_CLDENY) {
4232 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01004233 t->logs.status = 403;
willy tarreau47ee7ad2006-05-18 01:25:36 +02004234 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now); /* let's log the request time */
willy tarreau8337c6b2005-12-17 13:41:01 +01004235 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01004236 if (!(t->flags & SN_ERR_MASK))
4237 t->flags |= SN_ERR_PRXCOND;
4238 if (!(t->flags & SN_FINST_MASK))
4239 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004240 return 1;
4241 }
4242
willy tarreau9e138862006-05-14 23:06:28 +02004243 /* Right now, we know that we have processed the entire headers
4244 * and that unwanted requests have been filtered out. We can do
4245 * whatever we want.
4246 */
4247
willy tarreau9e138862006-05-14 23:06:28 +02004248 if (t->proxy->uri_auth != NULL
4249 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
4250 if (!memcmp(t->req_line.str + 4,
4251 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
4252 && !memcmp(t->req_line.str, "GET ", 4)) {
4253 struct user_auth *user;
4254 int authenticated;
4255
4256 /* we are in front of a interceptable URI. Let's check
4257 * if there's an authentication and if it's valid.
4258 */
4259 user = t->proxy->uri_auth->users;
4260 if (!user) {
4261 /* no user auth required, it's OK */
4262 authenticated = 1;
4263 } else {
4264 authenticated = 0;
4265
4266 /* a user list is defined, we have to check.
4267 * skip 21 chars for "Authorization: Basic ".
4268 */
4269 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
4270 user = NULL;
4271
4272 while (user) {
4273 if ((t->auth_hdr.len == user->user_len + 21)
4274 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
4275 authenticated = 1;
4276 break;
4277 }
4278 user = user->next;
willy tarreau9e138862006-05-14 23:06:28 +02004279 }
4280 }
4281
4282 if (!authenticated) {
4283 int msglen;
4284
4285 /* no need to go further */
4286
4287 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
4288 t->logs.status = 401;
4289 client_retnclose(t, msglen, trash);
4290 if (!(t->flags & SN_ERR_MASK))
4291 t->flags |= SN_ERR_PRXCOND;
4292 if (!(t->flags & SN_FINST_MASK))
4293 t->flags |= SN_FINST_R;
4294 return 1;
4295 }
4296
willy tarreaue0331262006-05-15 03:02:46 +02004297 t->cli_state = CL_STSHUTR;
willy tarreau950609c2006-05-18 01:23:51 +02004298 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
4299 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreaue0331262006-05-15 03:02:46 +02004300 t->data_source = DATA_SRC_STATS;
willy tarreau1f431b52006-05-21 14:46:15 +02004301 t->data_state = DATA_ST_INIT;
willy tarreaue0331262006-05-15 03:02:46 +02004302 produce_content(t);
4303 return 1;
willy tarreau9e138862006-05-14 23:06:28 +02004304 }
4305 }
4306
4307
willy tarreau5cbea6f2005-12-17 12:48:26 +01004308 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004309 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
4310 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004311 }
willy tarreau0f7af912005-12-17 12:21:26 +01004312
willy tarreau9fe663a2005-12-17 13:02:59 +01004313 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01004314 if (t->cli_addr.ss_family == AF_INET) {
4315 unsigned char *pn;
4316 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
4317 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
4318 pn[0], pn[1], pn[2], pn[3]);
4319 buffer_replace2(req, req->h, req->h, trash, len);
4320 }
4321 else if (t->cli_addr.ss_family == AF_INET6) {
4322 char pn[INET6_ADDRSTRLEN];
4323 inet_ntop(AF_INET6,
4324 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
4325 pn, sizeof(pn));
4326 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
4327 buffer_replace2(req, req->h, req->h, trash, len);
4328 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004329 }
4330
willy tarreau25c4ea52005-12-18 00:49:49 +01004331 /* add a "connection: close" line if needed */
4332 if (t->proxy->options & PR_O_HTTP_CLOSE)
4333 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
4334
willy tarreau982249e2005-12-18 00:57:06 +01004335 if (!memcmp(req->data, "POST ", 5)) {
4336 /* this is a POST request, which is not cacheable by default */
4337 t->flags |= SN_POST;
4338 }
willy tarreaucd878942005-12-17 13:27:43 +01004339
willy tarreau5cbea6f2005-12-17 12:48:26 +01004340 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004341 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01004342
willy tarreau750a4722005-12-17 13:21:24 +01004343 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004344 /* FIXME: we'll set the client in a wait state while we try to
4345 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02004346 * better to release the maximum of system buffers instead ?
4347 * The solution is to enable the FD but set its time-out to
4348 * eternity as long as the server-side does not enable data xfer.
4349 * CL_STDATA also has to take care of this, which is done below.
4350 */
willy tarreauef900ab2005-12-17 12:52:52 +01004351 //FD_CLR(t->cli_fd, StaticReadEvent);
4352 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01004353
4354 /* FIXME: if we break here (as up to 1.1.23), having the client
4355 * shutdown its connection can lead to an abort further.
4356 * it's better to either return 1 or even jump directly to the
4357 * data state which will save one schedule.
4358 */
4359 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01004360
4361 if (!t->proxy->clitimeout ||
4362 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4363 /* If the client has no timeout, or if the server is not ready yet,
4364 * and we know for sure that it can expire, then it's cleaner to
4365 * disable the timeout on the client side so that too low values
4366 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01004367 *
4368 * FIXME-20050705: the server needs a way to re-enable this time-out
4369 * when it switches its state, otherwise a client can stay connected
4370 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01004371 */
4372 tv_eternity(&t->crexpire);
4373
willy tarreau197e8ec2005-12-17 14:10:59 +01004374 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004375 }
willy tarreau0f7af912005-12-17 12:21:26 +01004376
Willy TARREAU13032e72006-03-12 17:31:45 +01004377 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4378 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004379 /* this is a partial header, let's wait for more to come */
4380 req->lr = ptr;
4381 break;
4382 }
willy tarreau0f7af912005-12-17 12:21:26 +01004383
willy tarreau5cbea6f2005-12-17 12:48:26 +01004384 /* now we know that *ptr is either \r or \n,
4385 * and that there are at least 1 char after it.
4386 */
4387 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4388 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4389 else
4390 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01004391
willy tarreau5cbea6f2005-12-17 12:48:26 +01004392 /*
4393 * now we know that we have a full header ; we can do whatever
4394 * we want with these pointers :
4395 * req->h = beginning of header
4396 * ptr = end of header (first \r or \n)
4397 * req->lr = beginning of next line (next rep->h)
4398 * req->r = end of data (not used at this stage)
4399 */
willy tarreau0f7af912005-12-17 12:21:26 +01004400
willy tarreau12350152005-12-18 01:03:27 +01004401 if (!method_checked && (t->proxy->appsession_name != NULL) &&
4402 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
4403 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
4404
4405 /* skip ; */
4406 request_line++;
4407
4408 /* look if we have a jsessionid */
4409
4410 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
4411
4412 /* skip jsessionid= */
4413 request_line += t->proxy->appsession_name_len + 1;
4414
4415 /* First try if we allready have an appsession */
4416 asession_temp = &local_asession;
4417
4418 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4419 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4420 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4421 return 0;
4422 }
4423
4424 /* Copy the sessionid */
4425 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
4426 asession_temp->sessid[t->proxy->appsession_len] = 0;
4427 asession_temp->serverid = NULL;
4428
4429 /* only do insert, if lookup fails */
4430 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
4431 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4432 Alert("Not enough memory process_cli():asession:calloc().\n");
4433 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4434 return 0;
4435 }
4436 asession_temp->sessid = local_asession.sessid;
4437 asession_temp->serverid = local_asession.serverid;
4438 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004439 } /* end if (chtbl_lookup()) */
4440 else {
willy tarreau12350152005-12-18 01:03:27 +01004441 /*free wasted memory;*/
4442 pool_free_to(apools.sessid, local_asession.sessid);
4443 }
4444
4445 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4446 asession_temp->request_count++;
4447
4448#if defined(DEBUG_HASH)
4449 print_table(&(t->proxy->htbl_proxy));
4450#endif
4451
4452 if (asession_temp->serverid == NULL) {
4453 Alert("Found Application Session without matching server.\n");
4454 } else {
4455 struct server *srv = t->proxy->srv;
4456 while (srv) {
4457 if (strcmp(srv->id, asession_temp->serverid) == 0) {
4458 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4459 /* we found the server and it's usable */
4460 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004461 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004462 t->srv = srv;
4463 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01004464 } else {
willy tarreau12350152005-12-18 01:03:27 +01004465 t->flags &= ~SN_CK_MASK;
4466 t->flags |= SN_CK_DOWN;
4467 }
willy tarreaub952e1d2005-12-18 01:31:20 +01004468 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01004469 srv = srv->next;
4470 }/* end while(srv) */
4471 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01004472 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01004473 else {
4474 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
4475 }
willy tarreau598da412005-12-18 01:07:29 +01004476 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01004477 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01004478 else{
4479 //printf("No Methode-Header with Session-String\n");
4480 }
4481
willy tarreau8337c6b2005-12-17 13:41:01 +01004482 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004483 /* we have a complete HTTP request that we must log */
4484 int urilen;
4485
willy tarreaua1598082005-12-17 13:08:06 +01004486 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004487 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01004488 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01004489 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01004490 if (!(t->flags & SN_ERR_MASK))
4491 t->flags |= SN_ERR_PRXCOND;
4492 if (!(t->flags & SN_FINST_MASK))
4493 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01004494 return 1;
4495 }
4496
4497 urilen = ptr - req->h;
4498 if (urilen >= REQURI_LEN)
4499 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01004500 memcpy(t->logs.uri, req->h, urilen);
4501 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004502
willy tarreaua1598082005-12-17 13:08:06 +01004503 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01004504 sess_log(t);
4505 }
willy tarreau4302f492005-12-18 01:00:37 +01004506 else if (t->logs.logwait & LW_REQHDR) {
4507 struct cap_hdr *h;
4508 int len;
4509 for (h = t->proxy->req_cap; h; h = h->next) {
4510 if ((h->namelen + 2 <= ptr - req->h) &&
4511 (req->h[h->namelen] == ':') &&
4512 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
4513
4514 if (t->req_cap[h->index] == NULL)
4515 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4516
4517 len = ptr - (req->h + h->namelen + 2);
4518 if (len > h->len)
4519 len = h->len;
4520
4521 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
4522 t->req_cap[h->index][len]=0;
4523 }
4524 }
4525
4526 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004527
willy tarreau5cbea6f2005-12-17 12:48:26 +01004528 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004529
willy tarreau982249e2005-12-18 00:57:06 +01004530 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004531 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004532 len = sprintf(trash, "%08x:%s.clihdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004533 max = ptr - req->h;
4534 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004535 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004536 trash[len++] = '\n';
4537 write(1, trash, len);
4538 }
willy tarreau0f7af912005-12-17 12:21:26 +01004539
willy tarreau25c4ea52005-12-18 00:49:49 +01004540
4541 /* remove "connection: " if needed */
4542 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4543 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
4544 delete_header = 1;
4545 }
4546
willy tarreau5cbea6f2005-12-17 12:48:26 +01004547 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004548 if (!delete_header && t->proxy->req_exp != NULL
4549 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004550 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004551 char term;
4552
4553 term = *ptr;
4554 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004555 exp = t->proxy->req_exp;
4556 do {
4557 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
4558 switch (exp->action) {
4559 case ACT_ALLOW:
4560 if (!(t->flags & SN_CLDENY))
4561 t->flags |= SN_CLALLOW;
4562 break;
4563 case ACT_REPLACE:
4564 if (!(t->flags & SN_CLDENY)) {
4565 int len = exp_replace(trash, req->h, exp->replace, pmatch);
4566 ptr += buffer_replace2(req, req->h, ptr, trash, len);
4567 }
4568 break;
4569 case ACT_REMOVE:
4570 if (!(t->flags & SN_CLDENY))
4571 delete_header = 1;
4572 break;
4573 case ACT_DENY:
4574 if (!(t->flags & SN_CLALLOW))
4575 t->flags |= SN_CLDENY;
4576 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004577 case ACT_PASS: /* we simply don't deny this one */
4578 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004579 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004580 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004581 }
willy tarreaue39cd132005-12-17 13:00:18 +01004582 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004583 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01004584 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004585
willy tarreau240afa62005-12-17 13:14:35 +01004586 /* Now look for cookies. Conforming to RFC2109, we have to support
4587 * attributes whose name begin with a '$', and associate them with
4588 * the right cookie, if we want to delete this cookie.
4589 * So there are 3 cases for each cookie read :
4590 * 1) it's a special attribute, beginning with a '$' : ignore it.
4591 * 2) it's a server id cookie that we *MAY* want to delete : save
4592 * some pointers on it (last semi-colon, beginning of cookie...)
4593 * 3) it's an application cookie : we *MAY* have to delete a previous
4594 * "special" cookie.
4595 * At the end of loop, if a "special" cookie remains, we may have to
4596 * remove it. If no application cookie persists in the header, we
4597 * *MUST* delete it
4598 */
willy tarreau12350152005-12-18 01:03:27 +01004599 if (!delete_header &&
4600 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01004601 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01004602 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004603 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01004604 char *del_colon, *del_cookie, *colon;
4605 int app_cookies;
4606
willy tarreau5cbea6f2005-12-17 12:48:26 +01004607 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01004608 colon = p1;
4609 /* del_cookie == NULL => nothing to be deleted */
4610 del_colon = del_cookie = NULL;
4611 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004612
4613 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01004614 /* skip spaces and colons, but keep an eye on these ones */
4615 while (p1 < ptr) {
4616 if (*p1 == ';' || *p1 == ',')
4617 colon = p1;
4618 else if (!isspace((int)*p1))
4619 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004620 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01004621 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004622
4623 if (p1 == ptr)
4624 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004625
4626 /* p1 is at the beginning of the cookie name */
4627 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004628 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004629 p2++;
4630
4631 if (p2 == ptr)
4632 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004633
4634 p3 = p2 + 1; /* skips the '=' sign */
4635 if (p3 == ptr)
4636 break;
4637
willy tarreau240afa62005-12-17 13:14:35 +01004638 p4 = p3;
4639 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004640 p4++;
4641
4642 /* here, we have the cookie name between p1 and p2,
4643 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004644 * we can process it :
4645 *
4646 * Cookie: NAME=VALUE;
4647 * | || || |
4648 * | || || +--> p4
4649 * | || |+-------> p3
4650 * | || +--------> p2
4651 * | |+------------> p1
4652 * | +-------------> colon
4653 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004654 */
4655
willy tarreau240afa62005-12-17 13:14:35 +01004656 if (*p1 == '$') {
4657 /* skip this one */
4658 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004659 else {
4660 /* first, let's see if we want to capture it */
4661 if (t->proxy->capture_name != NULL &&
4662 t->logs.cli_cookie == NULL &&
4663 (p4 - p1 >= t->proxy->capture_namelen) &&
4664 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4665 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004666
willy tarreau8337c6b2005-12-17 13:41:01 +01004667 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4668 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004669 } else {
4670 if (log_len > t->proxy->capture_len)
4671 log_len = t->proxy->capture_len;
4672 memcpy(t->logs.cli_cookie, p1, log_len);
4673 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004674 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004675 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004676
4677 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4678 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4679 /* Cool... it's the right one */
4680 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004681 char *delim;
4682
4683 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4684 * have the server ID betweek p3 and delim, and the original cookie between
4685 * delim+1 and p4. Otherwise, delim==p4 :
4686 *
4687 * Cookie: NAME=SRV~VALUE;
4688 * | || || | |
4689 * | || || | +--> p4
4690 * | || || +--------> delim
4691 * | || |+-----------> p3
4692 * | || +------------> p2
4693 * | |+----------------> p1
4694 * | +-----------------> colon
4695 * +------------------------> req->h
4696 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004697
willy tarreau0174f312005-12-18 01:02:42 +01004698 if (t->proxy->options & PR_O_COOK_PFX) {
4699 for (delim = p3; delim < p4; delim++)
4700 if (*delim == COOKIE_DELIM)
4701 break;
4702 }
4703 else
4704 delim = p4;
4705
4706
4707 /* Here, we'll look for the first running server which supports the cookie.
4708 * This allows to share a same cookie between several servers, for example
4709 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004710 * However, to prevent clients from sticking to cookie-less backup server
4711 * when they have incidentely learned an empty cookie, we simply ignore
4712 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004713 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004714 if (delim == p3)
4715 srv = NULL;
4716
willy tarreau0174f312005-12-18 01:02:42 +01004717 while (srv) {
4718 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4719 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4720 /* we found the server and it's usable */
4721 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004722 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004723 t->srv = srv;
4724 break;
willy tarreau12350152005-12-18 01:03:27 +01004725 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004726 /* we found a server, but it's down */
4727 t->flags &= ~SN_CK_MASK;
4728 t->flags |= SN_CK_DOWN;
4729 }
4730 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004731 srv = srv->next;
4732 }
4733
willy tarreau0174f312005-12-18 01:02:42 +01004734 if (!srv && !(t->flags & SN_CK_DOWN)) {
4735 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004736 t->flags &= ~SN_CK_MASK;
4737 t->flags |= SN_CK_INVALID;
4738 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004739
willy tarreau0174f312005-12-18 01:02:42 +01004740 /* depending on the cookie mode, we may have to either :
4741 * - delete the complete cookie if we're in insert+indirect mode, so that
4742 * the server never sees it ;
4743 * - remove the server id from the cookie value, and tag the cookie as an
4744 * application cookie so that it does not get accidentely removed later,
4745 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004746 */
willy tarreau0174f312005-12-18 01:02:42 +01004747 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4748 buffer_replace2(req, p3, delim + 1, NULL, 0);
4749 p4 -= (delim + 1 - p3);
4750 ptr -= (delim + 1 - p3);
4751 del_cookie = del_colon = NULL;
4752 app_cookies++; /* protect the header from deletion */
4753 }
4754 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004755 (t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
willy tarreau240afa62005-12-17 13:14:35 +01004756 del_cookie = p1;
4757 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004758 }
willy tarreau12350152005-12-18 01:03:27 +01004759 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004760 /* now we know that we must keep this cookie since it's
4761 * not ours. But if we wanted to delete our cookie
4762 * earlier, we cannot remove the complete header, but we
4763 * can remove the previous block itself.
4764 */
4765 app_cookies++;
4766
4767 if (del_cookie != NULL) {
4768 buffer_replace2(req, del_cookie, p1, NULL, 0);
4769 p4 -= (p1 - del_cookie);
4770 ptr -= (p1 - del_cookie);
4771 del_cookie = del_colon = NULL;
4772 }
willy tarreau240afa62005-12-17 13:14:35 +01004773 }
willy tarreau12350152005-12-18 01:03:27 +01004774
4775 if ((t->proxy->appsession_name != NULL) &&
4776 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4777 /* first, let's see if the cookie is our appcookie*/
4778
4779 /* Cool... it's the right one */
4780
4781 asession_temp = &local_asession;
4782
4783 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4784 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4785 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4786 return 0;
4787 }
4788
4789 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4790 asession_temp->sessid[t->proxy->appsession_len] = 0;
4791 asession_temp->serverid = NULL;
4792
4793 /* only do insert, if lookup fails */
4794 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4795 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4796 Alert("Not enough memory process_cli():asession:calloc().\n");
4797 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4798 return 0;
4799 }
4800
4801 asession_temp->sessid = local_asession.sessid;
4802 asession_temp->serverid = local_asession.serverid;
4803 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4804 }
4805 else{
4806 /* free wasted memory */
4807 pool_free_to(apools.sessid, local_asession.sessid);
4808 }
4809
4810 if (asession_temp->serverid == NULL) {
4811 Alert("Found Application Session without matching server.\n");
4812 } else {
4813 struct server *srv = t->proxy->srv;
4814 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004815 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004816 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4817 /* we found the server and it's usable */
4818 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004819 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004820 t->srv = srv;
4821 break;
4822 } else {
4823 t->flags &= ~SN_CK_MASK;
4824 t->flags |= SN_CK_DOWN;
4825 }
4826 }
4827 srv = srv->next;
4828 }/* end while(srv) */
4829 }/* end else if server == NULL */
4830
4831 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004832 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004833 }
willy tarreau240afa62005-12-17 13:14:35 +01004834
willy tarreau5cbea6f2005-12-17 12:48:26 +01004835 /* we'll have to look for another cookie ... */
4836 p1 = p4;
4837 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004838
4839 /* There's no more cookie on this line.
4840 * We may have marked the last one(s) for deletion.
4841 * We must do this now in two ways :
4842 * - if there is no app cookie, we simply delete the header ;
4843 * - if there are app cookies, we must delete the end of the
4844 * string properly, including the colon/semi-colon before
4845 * the cookie name.
4846 */
4847 if (del_cookie != NULL) {
4848 if (app_cookies) {
4849 buffer_replace2(req, del_colon, ptr, NULL, 0);
4850 /* WARNING! <ptr> becomes invalid for now. If some code
4851 * below needs to rely on it before the end of the global
4852 * header loop, we need to correct it with this code :
willy tarreau240afa62005-12-17 13:14:35 +01004853 */
willy tarreau9e138862006-05-14 23:06:28 +02004854 ptr = del_colon;
willy tarreau240afa62005-12-17 13:14:35 +01004855 }
4856 else
4857 delete_header = 1;
4858 }
4859 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004860
4861 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004862 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004863 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau9e138862006-05-14 23:06:28 +02004864 /* WARNING: ptr is not valid anymore, since the header may have
4865 * been deleted or truncated ! */
4866 } else {
4867 /* try to catch the first line as the request */
4868 if (t->req_line.len < 0) {
4869 t->req_line.str = req->h;
4870 t->req_line.len = ptr - req->h;
4871 }
4872
4873 /* We might also need the 'Authorization: ' header */
4874 if (t->auth_hdr.len < 0 &&
4875 t->proxy->uri_auth != NULL &&
4876 ptr > req->h + 15 &&
4877 !strncasecmp("Authorization: ", req->h, 15)) {
4878 t->auth_hdr.str = req->h;
4879 t->auth_hdr.len = ptr - req->h;
4880 }
willy tarreau0f7af912005-12-17 12:21:26 +01004881 }
willy tarreau240afa62005-12-17 13:14:35 +01004882
willy tarreau5cbea6f2005-12-17 12:48:26 +01004883 req->h = req->lr;
4884 } /* while (req->lr < req->r) */
4885
4886 /* end of header processing (even if incomplete) */
4887
willy tarreauef900ab2005-12-17 12:52:52 +01004888 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4889 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4890 * full. We cannot loop here since event_cli_read will disable it only if
4891 * req->l == rlim-data
4892 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004893 FD_SET(t->cli_fd, StaticReadEvent);
4894 if (t->proxy->clitimeout)
4895 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4896 else
4897 tv_eternity(&t->crexpire);
4898 }
4899
willy tarreaue39cd132005-12-17 13:00:18 +01004900 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004901 * won't be able to free more later, so the session will never terminate.
4902 */
willy tarreaue39cd132005-12-17 13:00:18 +01004903 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004904 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004905 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004906 if (!(t->flags & SN_ERR_MASK))
4907 t->flags |= SN_ERR_PRXCOND;
4908 if (!(t->flags & SN_FINST_MASK))
4909 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004910 return 1;
4911 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004912 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004913 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004914 tv_eternity(&t->crexpire);
4915 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004916 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004917 if (!(t->flags & SN_ERR_MASK))
4918 t->flags |= SN_ERR_CLICL;
4919 if (!(t->flags & SN_FINST_MASK))
4920 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004921 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004922 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004923 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4924
4925 /* read timeout : give up with an error message.
4926 */
4927 t->logs.status = 408;
4928 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004929 if (!(t->flags & SN_ERR_MASK))
4930 t->flags |= SN_ERR_CLITO;
4931 if (!(t->flags & SN_FINST_MASK))
4932 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004933 return 1;
4934 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004935
4936 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004937 }
4938 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004939 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004940 /* FIXME: this error handling is partly buggy because we always report
4941 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4942 * or HEADER phase. BTW, it's not logical to expire the client while
4943 * we're waiting for the server to connect.
4944 */
willy tarreau0f7af912005-12-17 12:21:26 +01004945 /* read or write error */
4946 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004947 tv_eternity(&t->crexpire);
4948 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004949 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004950 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004951 if (!(t->flags & SN_ERR_MASK))
4952 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004953 if (!(t->flags & SN_FINST_MASK)) {
4954 if (t->pend_pos)
4955 t->flags |= SN_FINST_Q;
4956 else if (s == SV_STCONN)
4957 t->flags |= SN_FINST_C;
4958 else
4959 t->flags |= SN_FINST_D;
4960 }
willy tarreau0f7af912005-12-17 12:21:26 +01004961 return 1;
4962 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004963 /* last read, or end of server write */
4964 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004965 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004966 tv_eternity(&t->crexpire);
4967 shutdown(t->cli_fd, SHUT_RD);
4968 t->cli_state = CL_STSHUTR;
4969 return 1;
4970 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004971 /* last server read and buffer empty */
4972 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004973 FD_CLR(t->cli_fd, StaticWriteEvent);
4974 tv_eternity(&t->cwexpire);
4975 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004976 /* We must ensure that the read part is still alive when switching
4977 * to shutw */
4978 FD_SET(t->cli_fd, StaticReadEvent);
4979 if (t->proxy->clitimeout)
4980 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004981 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004982 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01004983 return 1;
4984 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004985 /* read timeout */
4986 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4987 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004988 tv_eternity(&t->crexpire);
4989 shutdown(t->cli_fd, SHUT_RD);
4990 t->cli_state = CL_STSHUTR;
4991 if (!(t->flags & SN_ERR_MASK))
4992 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004993 if (!(t->flags & SN_FINST_MASK)) {
4994 if (t->pend_pos)
4995 t->flags |= SN_FINST_Q;
4996 else if (s == SV_STCONN)
4997 t->flags |= SN_FINST_C;
4998 else
4999 t->flags |= SN_FINST_D;
5000 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005001 return 1;
5002 }
5003 /* write timeout */
5004 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5005 FD_CLR(t->cli_fd, StaticWriteEvent);
5006 tv_eternity(&t->cwexpire);
5007 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005008 /* We must ensure that the read part is still alive when switching
5009 * to shutw */
5010 FD_SET(t->cli_fd, StaticReadEvent);
5011 if (t->proxy->clitimeout)
5012 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5013
willy tarreau036e1ce2005-12-17 13:46:33 +01005014 t->cli_state = CL_STSHUTW;
5015 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01005016 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005017 if (!(t->flags & SN_FINST_MASK)) {
5018 if (t->pend_pos)
5019 t->flags |= SN_FINST_Q;
5020 else if (s == SV_STCONN)
5021 t->flags |= SN_FINST_C;
5022 else
5023 t->flags |= SN_FINST_D;
5024 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005025 return 1;
5026 }
willy tarreau0f7af912005-12-17 12:21:26 +01005027
willy tarreauc58fc692005-12-17 14:13:08 +01005028 if (req->l >= req->rlim - req->data) {
5029 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01005030 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005031 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005032 FD_CLR(t->cli_fd, StaticReadEvent);
5033 tv_eternity(&t->crexpire);
5034 }
5035 }
5036 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005037 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005038 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5039 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01005040 if (!t->proxy->clitimeout ||
5041 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
5042 /* If the client has no timeout, or if the server not ready yet, and we
5043 * know for sure that it can expire, then it's cleaner to disable the
5044 * timeout on the client side so that too low values cannot make the
5045 * sessions abort too early.
5046 */
willy tarreau0f7af912005-12-17 12:21:26 +01005047 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01005048 else
5049 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005050 }
5051 }
5052
5053 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01005054 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005055 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5056 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5057 tv_eternity(&t->cwexpire);
5058 }
5059 }
5060 else { /* buffer not empty */
5061 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5062 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005063 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005064 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005065 /* FIXME: to prevent the client from expiring read timeouts during writes,
5066 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005067 t->crexpire = t->cwexpire;
5068 }
willy tarreau0f7af912005-12-17 12:21:26 +01005069 else
5070 tv_eternity(&t->cwexpire);
5071 }
5072 }
5073 return 0; /* other cases change nothing */
5074 }
5075 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005076 if (t->res_cw == RES_ERROR) {
5077 tv_eternity(&t->cwexpire);
5078 fd_delete(t->cli_fd);
5079 t->cli_state = CL_STCLOSE;
5080 if (!(t->flags & SN_ERR_MASK))
5081 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005082 if (!(t->flags & SN_FINST_MASK)) {
5083 if (t->pend_pos)
5084 t->flags |= SN_FINST_Q;
5085 else if (s == SV_STCONN)
5086 t->flags |= SN_FINST_C;
5087 else
5088 t->flags |= SN_FINST_D;
5089 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005090 return 1;
5091 }
willy tarreaue0331262006-05-15 03:02:46 +02005092 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
5093 && !(t->flags & SN_SELF_GEN)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005094 tv_eternity(&t->cwexpire);
5095 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005096 t->cli_state = CL_STCLOSE;
5097 return 1;
5098 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005099 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
5100 tv_eternity(&t->cwexpire);
5101 fd_delete(t->cli_fd);
5102 t->cli_state = CL_STCLOSE;
5103 if (!(t->flags & SN_ERR_MASK))
5104 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005105 if (!(t->flags & SN_FINST_MASK)) {
5106 if (t->pend_pos)
5107 t->flags |= SN_FINST_Q;
5108 else if (s == SV_STCONN)
5109 t->flags |= SN_FINST_C;
5110 else
5111 t->flags |= SN_FINST_D;
5112 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005113 return 1;
5114 }
willy tarreaue0331262006-05-15 03:02:46 +02005115
5116 if (t->flags & SN_SELF_GEN) {
5117 produce_content(t);
5118 if (rep->l == 0) {
5119 tv_eternity(&t->cwexpire);
5120 fd_delete(t->cli_fd);
5121 t->cli_state = CL_STCLOSE;
5122 return 1;
5123 }
5124 }
5125
5126 if ((rep->l == 0)
5127 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005128 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5129 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5130 tv_eternity(&t->cwexpire);
5131 }
5132 }
5133 else { /* buffer not empty */
5134 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5135 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005136 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005137 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005138 /* FIXME: to prevent the client from expiring read timeouts during writes,
5139 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005140 t->crexpire = t->cwexpire;
5141 }
willy tarreau0f7af912005-12-17 12:21:26 +01005142 else
5143 tv_eternity(&t->cwexpire);
5144 }
5145 }
5146 return 0;
5147 }
5148 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005149 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005150 tv_eternity(&t->crexpire);
5151 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005152 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005153 if (!(t->flags & SN_ERR_MASK))
5154 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005155 if (!(t->flags & SN_FINST_MASK)) {
5156 if (t->pend_pos)
5157 t->flags |= SN_FINST_Q;
5158 else if (s == SV_STCONN)
5159 t->flags |= SN_FINST_C;
5160 else
5161 t->flags |= SN_FINST_D;
5162 }
willy tarreau0f7af912005-12-17 12:21:26 +01005163 return 1;
5164 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005165 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
5166 tv_eternity(&t->crexpire);
5167 fd_delete(t->cli_fd);
5168 t->cli_state = CL_STCLOSE;
5169 return 1;
5170 }
5171 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
5172 tv_eternity(&t->crexpire);
5173 fd_delete(t->cli_fd);
5174 t->cli_state = CL_STCLOSE;
5175 if (!(t->flags & SN_ERR_MASK))
5176 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005177 if (!(t->flags & SN_FINST_MASK)) {
5178 if (t->pend_pos)
5179 t->flags |= SN_FINST_Q;
5180 else if (s == SV_STCONN)
5181 t->flags |= SN_FINST_C;
5182 else
5183 t->flags |= SN_FINST_D;
5184 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005185 return 1;
5186 }
willy tarreauef900ab2005-12-17 12:52:52 +01005187 else if (req->l >= req->rlim - req->data) {
5188 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01005189
5190 /* FIXME-20050705: is it possible for a client to maintain a session
5191 * after the timeout by sending more data after it receives a close ?
5192 */
5193
willy tarreau0f7af912005-12-17 12:21:26 +01005194 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005195 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005196 FD_CLR(t->cli_fd, StaticReadEvent);
5197 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005198 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005199 }
5200 }
5201 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005202 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005203 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5204 FD_SET(t->cli_fd, StaticReadEvent);
5205 if (t->proxy->clitimeout)
5206 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5207 else
5208 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005209 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005210 }
5211 }
5212 return 0;
5213 }
5214 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005215 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005216 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005217 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005218 write(1, trash, len);
5219 }
5220 return 0;
5221 }
5222 return 0;
5223}
5224
willy tarreaudfece232006-05-02 00:19:57 +02005225/* This function turns the server state into the SV_STCLOSE, and sets
5226 * indicators accordingly. Note that if <status> is 0, no message is
5227 * returned.
5228 */
5229void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
5230 t->srv_state = SV_STCLOSE;
5231 if (status > 0) {
5232 t->logs.status = status;
5233 if (t->proxy->mode == PR_MODE_HTTP)
5234 client_return(t, msglen, msg);
5235 }
5236 if (!(t->flags & SN_ERR_MASK))
5237 t->flags |= err;
5238 if (!(t->flags & SN_FINST_MASK))
5239 t->flags |= finst;
5240}
5241
5242/*
5243 * This function checks the retry count during the connect() job.
5244 * It updates the session's srv_state and retries, so that the caller knows
5245 * what it has to do. It uses the last connection error to set the log when
5246 * it expires. It returns 1 when it has expired, and 0 otherwise.
5247 */
5248int srv_count_retry_down(struct session *t, int conn_err) {
5249 /* we are in front of a retryable error */
5250 t->conn_retries--;
5251 if (t->conn_retries < 0) {
5252 /* if not retryable anymore, let's abort */
5253 tv_eternity(&t->cnexpire);
5254 srv_close_with_err(t, conn_err, SN_FINST_C,
5255 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005256 if (t->srv)
5257 t->srv->failed_conns++;
5258 t->proxy->failed_conns++;
5259
willy tarreaudfece232006-05-02 00:19:57 +02005260 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005261 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005262 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005263 if (may_dequeue_tasks(t->srv, t->proxy))
5264 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005265 return 1;
5266 }
5267 return 0;
5268}
willy tarreau0f7af912005-12-17 12:21:26 +01005269
5270/*
willy tarreaudfece232006-05-02 00:19:57 +02005271 * This function performs the retryable part of the connect() job.
5272 * It updates the session's srv_state and retries, so that the caller knows
5273 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
5274 * it needs to redispatch.
5275 */
5276int srv_retryable_connect(struct session *t) {
5277 int conn_err;
5278
5279 /* This loop ensures that we stop before the last retry in case of a
5280 * redispatchable server.
5281 */
5282 do {
5283 /* initiate a connection to the server */
5284 conn_err = connect_server(t);
5285 switch (conn_err) {
5286
5287 case SN_ERR_NONE:
5288 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
5289 t->srv_state = SV_STCONN;
5290 return 1;
5291
5292 case SN_ERR_INTERNAL:
5293 tv_eternity(&t->cnexpire);
5294 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5295 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005296 if (t->srv)
5297 t->srv->failed_conns++;
5298 t->proxy->failed_conns++;
willy tarreaudfece232006-05-02 00:19:57 +02005299 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005300 if (may_dequeue_tasks(t->srv, t->proxy))
5301 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005302 return 1;
5303 }
5304 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02005305 if (srv_count_retry_down(t, conn_err)) {
5306 /* let's try to offer this slot to anybody */
5307 if (may_dequeue_tasks(t->srv, t->proxy))
5308 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005309 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02005310 }
willy tarreaudfece232006-05-02 00:19:57 +02005311 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
5312
5313 /* We're on our last chance, and the REDISP option was specified.
5314 * We will ignore cookie and force to balance or use the dispatcher.
5315 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005316 /* let's try to offer this slot to anybody */
5317 if (may_dequeue_tasks(t->srv, t->proxy))
5318 task_wakeup(&rq, t->srv->queue_mgt);
5319
willy tarreaue3b30652006-05-21 16:23:22 +02005320 if (t->srv)
5321 t->srv->failed_conns++;
5322 t->proxy->failed_conns++;
5323
willy tarreaudfece232006-05-02 00:19:57 +02005324 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5325 t->srv = NULL; /* it's left to the dispatcher to choose a server */
5326 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
5327 t->flags &= ~SN_CK_MASK;
5328 t->flags |= SN_CK_DOWN;
5329 }
5330 return 0;
5331}
5332
5333/* This function performs the "redispatch" part of a connection attempt. It
5334 * will assign a server if required, queue the connection if required, and
5335 * handle errors that might arise at this level. It can change the server
5336 * state. It will return 1 if it encounters an error, switches the server
5337 * state, or has to queue a connection. Otherwise, it will return 0 indicating
5338 * that the connection is ready to use.
5339 */
5340
5341int srv_redispatch_connect(struct session *t) {
5342 int conn_err;
5343
5344 /* We know that we don't have any connection pending, so we will
5345 * try to get a new one, and wait in this state if it's queued
5346 */
5347 conn_err = assign_server_and_queue(t);
5348 switch (conn_err) {
5349 case SRV_STATUS_OK:
5350 break;
5351
5352 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02005353 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02005354 tv_eternity(&t->cnexpire);
5355 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
5356 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005357 if (t->srv)
5358 t->srv->failed_conns++;
5359 t->proxy->failed_conns++;
5360
willy tarreaudfece232006-05-02 00:19:57 +02005361 return 1;
5362
5363 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02005364 /* FIXME-20060503 : we should use the queue timeout instead */
5365 if (t->proxy->contimeout)
5366 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
5367 else
5368 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02005369 t->srv_state = SV_STIDLE;
5370 /* do nothing else and do not wake any other session up */
5371 return 1;
5372
5373 case SRV_STATUS_FULL:
5374 case SRV_STATUS_INTERNAL:
5375 default:
5376 tv_eternity(&t->cnexpire);
5377 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5378 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreaue3b30652006-05-21 16:23:22 +02005379 if (t->srv)
5380 t->srv->failed_conns++;
5381 t->proxy->failed_conns++;
5382
willy tarreaudfece232006-05-02 00:19:57 +02005383 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005384 if (may_dequeue_tasks(t->srv, t->proxy))
5385 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005386 return 1;
5387 }
5388 /* if we get here, it's because we got SRV_STATUS_OK, which also
5389 * means that the connection has not been queued.
5390 */
5391 return 0;
5392}
5393
5394
5395/*
willy tarreau0f7af912005-12-17 12:21:26 +01005396 * manages the server FSM and its socket. It returns 1 if a state has changed
5397 * (and a resync may be needed), 0 else.
5398 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005399int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01005400 int s = t->srv_state;
5401 int c = t->cli_state;
5402 struct buffer *req = t->req;
5403 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01005404 appsess *asession_temp = NULL;
5405 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01005406 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01005407
willy tarreau750a4722005-12-17 13:21:24 +01005408#ifdef DEBUG_FULL
5409 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
5410#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01005411 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
5412 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
5413 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
5414 //);
willy tarreau0f7af912005-12-17 12:21:26 +01005415 if (s == SV_STIDLE) {
5416 if (c == CL_STHEADERS)
5417 return 0; /* stay in idle, waiting for data to reach the client side */
willy tarreau03a92de2006-05-21 18:26:53 +02005418 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
5419 (c == CL_STSHUTR &&
5420 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
willy tarreau0f7af912005-12-17 12:21:26 +01005421 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02005422 if (t->pend_pos)
5423 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau51e91292006-05-14 23:29:47 +02005424 /* note that this must not return any error because it would be able to
5425 * overwrite the client_retnclose() output.
5426 */
willy tarreau078c79a2006-05-13 12:23:58 +02005427 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, 0, NULL);
willy tarreaudfece232006-05-02 00:19:57 +02005428
willy tarreau0f7af912005-12-17 12:21:26 +01005429 return 1;
5430 }
willy tarreaudfece232006-05-02 00:19:57 +02005431 else {
5432 /* Right now, we will need to create a connection to the server.
5433 * We might already have tried, and got a connection pending, in
5434 * which case we will not do anything till it's pending. It's up
5435 * to any other session to release it and wake us up again.
5436 */
willy tarreau45526ed2006-05-03 20:11:50 +02005437 if (t->pend_pos) {
5438 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
5439 return 0;
5440 else {
5441 /* we've been waiting too long here */
5442 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02005443 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
5444 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02005445 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaue3b30652006-05-21 16:23:22 +02005446 if (t->srv)
5447 t->srv->failed_conns++;
5448 t->proxy->failed_conns++;
willy tarreau45526ed2006-05-03 20:11:50 +02005449 return 1;
5450 }
5451 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005452
willy tarreaudfece232006-05-02 00:19:57 +02005453 do {
5454 /* first, get a connection */
5455 if (srv_redispatch_connect(t))
5456 return t->srv_state != SV_STIDLE;
5457
5458 /* try to (re-)connect to the server, and fail if we expire the
5459 * number of retries.
5460 */
willy tarreauf32f5242006-05-02 22:54:52 +02005461 if (srv_retryable_connect(t)) {
5462 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005463 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02005464 }
willy tarreaudfece232006-05-02 00:19:57 +02005465
5466 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005467 }
5468 }
5469 else if (s == SV_STCONN) { /* connection in progress */
willy tarreau03a92de2006-05-21 18:26:53 +02005470 if (c == CL_STCLOSE || c == CL_STSHUTW ||
5471 (c == CL_STSHUTR &&
5472 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
5473 tv_eternity(&t->cnexpire);
5474 fd_delete(t->srv_fd);
5475 if (t->srv)
5476 t->srv->cur_sess--;
5477
5478 /* note that this must not return any error because it would be able to
5479 * overwrite the client_retnclose() output.
5480 */
5481 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
5482 return 1;
5483 }
willy tarreau0f7af912005-12-17 12:21:26 +01005484 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01005485 //fprintf(stderr,"1: c=%d, s=%d, now=%d.%06d, exp=%d.%06d\n", c, s, now.tv_sec, now.tv_usec, t->cnexpire.tv_sec, t->cnexpire.tv_usec);
willy tarreau0f7af912005-12-17 12:21:26 +01005486 return 0; /* nothing changed */
5487 }
5488 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02005489 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005490 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02005491
willy tarreau0f7af912005-12-17 12:21:26 +01005492 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005493 if (t->srv)
5494 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02005495
5496 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01005497 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
5498 else
willy tarreaudfece232006-05-02 00:19:57 +02005499 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01005500
willy tarreaudfece232006-05-02 00:19:57 +02005501 /* ensure that we have enough retries left */
5502 if (srv_count_retry_down(t, conn_err))
5503 return 1;
5504
5505 do {
5506 /* Now we will try to either reconnect to the same server or
5507 * connect to another server. If the connection gets queued
5508 * because all servers are saturated, then we will go back to
5509 * the SV_STIDLE state.
5510 */
willy tarreauf32f5242006-05-02 22:54:52 +02005511 if (srv_retryable_connect(t)) {
5512 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005513 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02005514 }
willy tarreaudfece232006-05-02 00:19:57 +02005515
5516 /* we need to redispatch the connection to another server */
5517 if (srv_redispatch_connect(t))
5518 return t->srv_state != SV_STCONN;
5519 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005520 }
5521 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01005522 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005523
willy tarreau0f7af912005-12-17 12:21:26 +01005524 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005525 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005526 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005527 tv_eternity(&t->swexpire);
5528 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005529 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005530 if (t->proxy->srvtimeout) {
5531 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005532 /* FIXME: to prevent the server from expiring read timeouts during writes,
5533 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005534 t->srexpire = t->swexpire;
5535 }
5536 else
5537 tv_eternity(&t->swexpire);
5538 }
willy tarreau0f7af912005-12-17 12:21:26 +01005539
5540 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
5541 FD_SET(t->srv_fd, StaticReadEvent);
5542 if (t->proxy->srvtimeout)
5543 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5544 else
5545 tv_eternity(&t->srexpire);
5546
5547 t->srv_state = SV_STDATA;
willy tarreau2d505e52006-05-21 08:32:50 +02005548 if (t->srv)
5549 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005550 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01005551
5552 /* if the user wants to log as soon as possible, without counting
5553 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005554 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005555 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
5556 sess_log(t);
5557 }
willy tarreau0f7af912005-12-17 12:21:26 +01005558 }
willy tarreauef900ab2005-12-17 12:52:52 +01005559 else {
willy tarreau0f7af912005-12-17 12:21:26 +01005560 t->srv_state = SV_STHEADERS;
willy tarreau2d505e52006-05-21 08:32:50 +02005561 if (t->srv)
5562 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005563 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
5564 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005565 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005566 return 1;
5567 }
5568 }
5569 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005570 /* now parse the partial (or complete) headers */
5571 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
5572 char *ptr;
5573 int delete_header;
5574
5575 ptr = rep->lr;
5576
5577 /* look for the end of the current header */
5578 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
5579 ptr++;
5580
5581 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005582 int line, len;
5583
5584 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01005585
5586 /* first, we'll block if security checks have caught nasty things */
5587 if (t->flags & SN_CACHEABLE) {
5588 if ((t->flags & SN_CACHE_COOK) &&
5589 (t->flags & SN_SCK_ANY) &&
5590 (t->proxy->options & PR_O_CHK_CACHE)) {
5591
5592 /* we're in presence of a cacheable response containing
5593 * a set-cookie header. We'll block it as requested by
5594 * the 'checkcache' option, and send an alert.
5595 */
5596 tv_eternity(&t->srexpire);
5597 tv_eternity(&t->swexpire);
5598 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005599 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005600 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005601 t->srv->failed_secu++;
5602 }
5603 t->proxy->failed_secu++;
willy tarreau97f58572005-12-18 00:53:44 +01005604 t->srv_state = SV_STCLOSE;
5605 t->logs.status = 502;
5606 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5607 if (!(t->flags & SN_ERR_MASK))
5608 t->flags |= SN_ERR_PRXCOND;
5609 if (!(t->flags & SN_FINST_MASK))
5610 t->flags |= SN_FINST_H;
5611
5612 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5613 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5614
willy tarreaudfece232006-05-02 00:19:57 +02005615 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005616 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005617 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005618 if (may_dequeue_tasks(t->srv, t->proxy))
5619 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005620
willy tarreau97f58572005-12-18 00:53:44 +01005621 return 1;
5622 }
5623 }
5624
willy tarreau982249e2005-12-18 00:57:06 +01005625 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
5626 if (t->flags & SN_SVDENY) {
5627 tv_eternity(&t->srexpire);
5628 tv_eternity(&t->swexpire);
5629 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02005630 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02005631 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02005632 t->srv->failed_secu++;
5633 }
5634 t->proxy->failed_secu++;
willy tarreau982249e2005-12-18 00:57:06 +01005635 t->srv_state = SV_STCLOSE;
5636 t->logs.status = 502;
5637 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5638 if (!(t->flags & SN_ERR_MASK))
5639 t->flags |= SN_ERR_PRXCOND;
5640 if (!(t->flags & SN_FINST_MASK))
5641 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005642 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005643 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005644 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005645 if (may_dequeue_tasks(t->srv, t->proxy))
5646 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005647
willy tarreau982249e2005-12-18 00:57:06 +01005648 return 1;
5649 }
5650
willy tarreau5cbea6f2005-12-17 12:48:26 +01005651 /* we'll have something else to do here : add new headers ... */
5652
willy tarreaucd878942005-12-17 13:27:43 +01005653 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
5654 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005655 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01005656 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02005657 * requests and this one isn't. Note that servers which don't have cookies
5658 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005659 */
willy tarreau750a4722005-12-17 13:21:24 +01005660 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01005661 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02005662 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01005663
willy tarreau036e1ce2005-12-17 13:46:33 +01005664 t->flags |= SN_SCK_INSERTED;
5665
willy tarreau750a4722005-12-17 13:21:24 +01005666 /* Here, we will tell an eventual cache on the client side that we don't
5667 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
5668 * Some caches understand the correct form: 'no-cache="set-cookie"', but
5669 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
5670 */
willy tarreau240afa62005-12-17 13:14:35 +01005671 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01005672 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
5673 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01005674
5675 if (rep->data + rep->l < rep->h)
5676 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
5677 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01005678 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005679 }
5680
5681 /* headers to be added */
5682 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01005683 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
5684 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005685 }
5686
willy tarreau25c4ea52005-12-18 00:49:49 +01005687 /* add a "connection: close" line if needed */
5688 if (t->proxy->options & PR_O_HTTP_CLOSE)
5689 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
5690
willy tarreau5cbea6f2005-12-17 12:48:26 +01005691 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01005692 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01005693 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01005694
Willy TARREAU767ba712006-03-01 22:40:50 +01005695 /* client connection already closed or option 'httpclose' required :
5696 * we close the server's outgoing connection right now.
5697 */
5698 if ((req->l == 0) &&
5699 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5700 FD_CLR(t->srv_fd, StaticWriteEvent);
5701 tv_eternity(&t->swexpire);
5702
5703 /* We must ensure that the read part is still alive when switching
5704 * to shutw */
5705 FD_SET(t->srv_fd, StaticReadEvent);
5706 if (t->proxy->srvtimeout)
5707 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5708
5709 shutdown(t->srv_fd, SHUT_WR);
5710 t->srv_state = SV_STSHUTW;
5711 }
5712
willy tarreau25c4ea52005-12-18 00:49:49 +01005713 /* if the user wants to log as soon as possible, without counting
5714 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005715 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005716 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5717 t->logs.bytes = rep->h - rep->data;
5718 sess_log(t);
5719 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005720 break;
5721 }
5722
5723 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5724 if (ptr > rep->r - 2) {
5725 /* this is a partial header, let's wait for more to come */
5726 rep->lr = ptr;
5727 break;
5728 }
5729
5730 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5731 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5732
5733 /* now we know that *ptr is either \r or \n,
5734 * and that there are at least 1 char after it.
5735 */
5736 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5737 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5738 else
5739 rep->lr = ptr + 2; /* \r\n or \n\r */
5740
5741 /*
5742 * now we know that we have a full header ; we can do whatever
5743 * we want with these pointers :
5744 * rep->h = beginning of header
5745 * ptr = end of header (first \r or \n)
5746 * rep->lr = beginning of next line (next rep->h)
5747 * rep->r = end of data (not used at this stage)
5748 */
5749
willy tarreaua1598082005-12-17 13:08:06 +01005750
willy tarreau982249e2005-12-18 00:57:06 +01005751 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005752 t->logs.logwait &= ~LW_RESP;
5753 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005754 switch (t->logs.status) {
5755 case 200:
5756 case 203:
5757 case 206:
5758 case 300:
5759 case 301:
5760 case 410:
5761 /* RFC2616 @13.4:
5762 * "A response received with a status code of
5763 * 200, 203, 206, 300, 301 or 410 MAY be stored
5764 * by a cache (...) unless a cache-control
5765 * directive prohibits caching."
5766 *
5767 * RFC2616 @9.5: POST method :
5768 * "Responses to this method are not cacheable,
5769 * unless the response includes appropriate
5770 * Cache-Control or Expires header fields."
5771 */
willy tarreau7476ec92006-05-21 16:24:15 +02005772 if (!(t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
willy tarreau982249e2005-12-18 00:57:06 +01005773 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5774 break;
5775 default:
5776 break;
5777 }
willy tarreau4302f492005-12-18 01:00:37 +01005778 }
5779 else if (t->logs.logwait & LW_RSPHDR) {
5780 struct cap_hdr *h;
5781 int len;
5782 for (h = t->proxy->rsp_cap; h; h = h->next) {
5783 if ((h->namelen + 2 <= ptr - rep->h) &&
5784 (rep->h[h->namelen] == ':') &&
5785 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5786
5787 if (t->rsp_cap[h->index] == NULL)
5788 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5789
5790 len = ptr - (rep->h + h->namelen + 2);
5791 if (len > h->len)
5792 len = h->len;
5793
5794 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5795 t->rsp_cap[h->index][len]=0;
5796 }
5797 }
5798
willy tarreaua1598082005-12-17 13:08:06 +01005799 }
5800
willy tarreau5cbea6f2005-12-17 12:48:26 +01005801 delete_header = 0;
5802
willy tarreau982249e2005-12-18 00:57:06 +01005803 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005804 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005805 len = sprintf(trash, "%08x:%s.srvhdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005806 max = ptr - rep->h;
5807 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005808 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005809 trash[len++] = '\n';
5810 write(1, trash, len);
5811 }
5812
willy tarreau25c4ea52005-12-18 00:49:49 +01005813 /* remove "connection: " if needed */
5814 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5815 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5816 delete_header = 1;
5817 }
5818
willy tarreau5cbea6f2005-12-17 12:48:26 +01005819 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005820 if (!delete_header && t->proxy->rsp_exp != NULL
5821 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005822 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005823 char term;
5824
5825 term = *ptr;
5826 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005827 exp = t->proxy->rsp_exp;
5828 do {
5829 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5830 switch (exp->action) {
5831 case ACT_ALLOW:
5832 if (!(t->flags & SN_SVDENY))
5833 t->flags |= SN_SVALLOW;
5834 break;
5835 case ACT_REPLACE:
5836 if (!(t->flags & SN_SVDENY)) {
5837 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5838 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5839 }
5840 break;
5841 case ACT_REMOVE:
5842 if (!(t->flags & SN_SVDENY))
5843 delete_header = 1;
5844 break;
5845 case ACT_DENY:
5846 if (!(t->flags & SN_SVALLOW))
5847 t->flags |= SN_SVDENY;
5848 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005849 case ACT_PASS: /* we simply don't deny this one */
5850 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005851 }
5852 break;
5853 }
willy tarreaue39cd132005-12-17 13:00:18 +01005854 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005855 *ptr = term; /* restore the string terminator */
5856 }
5857
willy tarreau97f58572005-12-18 00:53:44 +01005858 /* check for cache-control: or pragma: headers */
5859 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5860 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5861 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5862 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5863 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005864 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005865 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5866 else {
5867 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005868 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005869 t->flags &= ~SN_CACHE_COOK;
5870 }
5871 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005872 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005873 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005874 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005875 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5876 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005877 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005878 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005879 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5880 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5881 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5882 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5883 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5884 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005885 }
5886 }
5887 }
5888
willy tarreau5cbea6f2005-12-17 12:48:26 +01005889 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005890 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005891 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005892 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005893 char *p1, *p2, *p3, *p4;
5894
willy tarreau97f58572005-12-18 00:53:44 +01005895 t->flags |= SN_SCK_ANY;
5896
willy tarreau5cbea6f2005-12-17 12:48:26 +01005897 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5898
5899 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005900 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005901 p1++;
5902
5903 if (p1 == ptr || *p1 == ';') /* end of cookie */
5904 break;
5905
5906 /* p1 is at the beginning of the cookie name */
5907 p2 = p1;
5908
5909 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5910 p2++;
5911
5912 if (p2 == ptr || *p2 == ';') /* next cookie */
5913 break;
5914
5915 p3 = p2 + 1; /* skips the '=' sign */
5916 if (p3 == ptr)
5917 break;
5918
5919 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005920 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005921 p4++;
5922
5923 /* here, we have the cookie name between p1 and p2,
5924 * and its value between p3 and p4.
5925 * we can process it.
5926 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005927
5928 /* first, let's see if we want to capture it */
5929 if (t->proxy->capture_name != NULL &&
5930 t->logs.srv_cookie == NULL &&
5931 (p4 - p1 >= t->proxy->capture_namelen) &&
5932 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5933 int log_len = p4 - p1;
5934
5935 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5936 Alert("HTTP logging : out of memory.\n");
5937 }
5938
5939 if (log_len > t->proxy->capture_len)
5940 log_len = t->proxy->capture_len;
5941 memcpy(t->logs.srv_cookie, p1, log_len);
5942 t->logs.srv_cookie[log_len] = 0;
5943 }
5944
5945 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5946 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005947 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005948 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005949
5950 /* If the cookie is in insert mode on a known server, we'll delete
5951 * this occurrence because we'll insert another one later.
5952 * We'll delete it too if the "indirect" option is set and we're in
5953 * a direct access. */
5954 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005955 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005956 /* this header must be deleted */
5957 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005958 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005959 }
5960 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5961 /* replace bytes p3->p4 with the cookie name associated
5962 * with this server since we know it.
5963 */
5964 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005965 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005966 }
willy tarreau0174f312005-12-18 01:02:42 +01005967 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5968 /* insert the cookie name associated with this server
5969 * before existing cookie, and insert a delimitor between them..
5970 */
5971 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5972 p3[t->srv->cklen] = COOKIE_DELIM;
5973 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5974 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005975 break;
5976 }
willy tarreau12350152005-12-18 01:03:27 +01005977
5978 /* first, let's see if the cookie is our appcookie*/
5979 if ((t->proxy->appsession_name != NULL) &&
5980 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5981
5982 /* Cool... it's the right one */
5983
willy tarreaub952e1d2005-12-18 01:31:20 +01005984 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005985 asession_temp = &local_asession;
5986
willy tarreaub952e1d2005-12-18 01:31:20 +01005987 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005988 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5989 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5990 }
5991 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5992 asession_temp->sessid[t->proxy->appsession_len] = 0;
5993 asession_temp->serverid = NULL;
5994
5995 /* only do insert, if lookup fails */
5996 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5997 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5998 Alert("Not enought Memory process_srv():asession:calloc().\n");
5999 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
6000 return 0;
6001 }
6002 asession_temp->sessid = local_asession.sessid;
6003 asession_temp->serverid = local_asession.serverid;
6004 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01006005 }/* end if (chtbl_lookup()) */
6006 else {
willy tarreau12350152005-12-18 01:03:27 +01006007 /* free wasted memory */
6008 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01006009 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01006010
willy tarreaub952e1d2005-12-18 01:31:20 +01006011 if (asession_temp->serverid == NULL) {
6012 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01006013 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
6014 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
6015 }
6016 asession_temp->serverid[0] = '\0';
6017 }
6018
willy tarreaub952e1d2005-12-18 01:31:20 +01006019 if (asession_temp->serverid[0] == '\0')
6020 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01006021
6022 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
6023
6024#if defined(DEBUG_HASH)
6025 print_table(&(t->proxy->htbl_proxy));
6026#endif
6027 break;
6028 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006029 else {
6030 // fprintf(stderr,"Ignoring unknown cookie : ");
6031 // write(2, p1, p2-p1);
6032 // fprintf(stderr," = ");
6033 // write(2, p3, p4-p3);
6034 // fprintf(stderr,"\n");
6035 }
6036 break; /* we don't want to loop again since there cannot be another cookie on the same line */
6037 } /* we're now at the end of the cookie value */
6038 } /* end of cookie processing */
6039
willy tarreau97f58572005-12-18 00:53:44 +01006040 /* check for any set-cookie in case we check for cacheability */
6041 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
6042 (t->proxy->options & PR_O_CHK_CACHE) &&
6043 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
6044 t->flags |= SN_SCK_ANY;
6045 }
6046
willy tarreau5cbea6f2005-12-17 12:48:26 +01006047 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01006048 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006049 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01006050
willy tarreau5cbea6f2005-12-17 12:48:26 +01006051 rep->h = rep->lr;
6052 } /* while (rep->lr < rep->r) */
6053
6054 /* end of header processing (even if incomplete) */
6055
willy tarreauef900ab2005-12-17 12:52:52 +01006056 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6057 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
6058 * full. We cannot loop here since event_srv_read will disable it only if
6059 * rep->l == rlim-data
6060 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006061 FD_SET(t->srv_fd, StaticReadEvent);
6062 if (t->proxy->srvtimeout)
6063 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6064 else
6065 tv_eternity(&t->srexpire);
6066 }
willy tarreau0f7af912005-12-17 12:21:26 +01006067
willy tarreau8337c6b2005-12-17 13:41:01 +01006068 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01006069 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006070 tv_eternity(&t->srexpire);
6071 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006072 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006073 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006074 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006075 t->srv->failed_resp++;
6076 }
6077 t->proxy->failed_resp++;
6078
willy tarreau0f7af912005-12-17 12:21:26 +01006079 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01006080 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01006081 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01006082 if (!(t->flags & SN_ERR_MASK))
6083 t->flags |= SN_ERR_SRVCL;
6084 if (!(t->flags & SN_FINST_MASK))
6085 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006086 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006087 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006088 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006089 if (may_dequeue_tasks(t->srv, t->proxy))
6090 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006091
willy tarreau0f7af912005-12-17 12:21:26 +01006092 return 1;
6093 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006094 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01006095 * since we are in header mode, if there's no space left for headers, we
6096 * won't be able to free more later, so the session will never terminate.
6097 */
willy tarreau8337c6b2005-12-17 13:41:01 +01006098 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE || rep->l >= rep->rlim - rep->data) {
willy tarreau0f7af912005-12-17 12:21:26 +01006099 FD_CLR(t->srv_fd, StaticReadEvent);
6100 tv_eternity(&t->srexpire);
6101 shutdown(t->srv_fd, SHUT_RD);
6102 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006103 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01006104 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006105 }
6106 /* read timeout : return a 504 to the client.
6107 */
6108 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6109 tv_eternity(&t->srexpire);
6110 tv_eternity(&t->swexpire);
6111 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006112 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006113 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006114 t->srv->failed_resp++;
6115 }
6116 t->proxy->failed_resp++;
willy tarreau8337c6b2005-12-17 13:41:01 +01006117 t->srv_state = SV_STCLOSE;
6118 t->logs.status = 504;
6119 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01006120 if (!(t->flags & SN_ERR_MASK))
6121 t->flags |= SN_ERR_SRVTO;
6122 if (!(t->flags & SN_FINST_MASK))
6123 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02006124 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006125 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006126 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006127 if (may_dequeue_tasks(t->srv, t->proxy))
6128 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006129
willy tarreau8337c6b2005-12-17 13:41:01 +01006130 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006131 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006132 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01006133 /* FIXME!!! here, we don't want to switch to SHUTW if the
6134 * client shuts read too early, because we may still have
6135 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01006136 * The side-effect is that if the client completely closes its
6137 * connection during SV_STHEADER, the connection to the server
6138 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01006139 */
willy tarreau036e1ce2005-12-17 13:46:33 +01006140 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01006141 FD_CLR(t->srv_fd, StaticWriteEvent);
6142 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01006143
6144 /* We must ensure that the read part is still alive when switching
6145 * to shutw */
6146 FD_SET(t->srv_fd, StaticReadEvent);
6147 if (t->proxy->srvtimeout)
6148 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6149
willy tarreau0f7af912005-12-17 12:21:26 +01006150 shutdown(t->srv_fd, SHUT_WR);
6151 t->srv_state = SV_STSHUTW;
6152 return 1;
6153 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006154 /* write timeout */
6155 /* FIXME!!! here, we don't want to switch to SHUTW if the
6156 * client shuts read too early, because we may still have
6157 * some work to do on the headers.
6158 */
6159 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6160 FD_CLR(t->srv_fd, StaticWriteEvent);
6161 tv_eternity(&t->swexpire);
6162 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006163 /* We must ensure that the read part is still alive when switching
6164 * to shutw */
6165 FD_SET(t->srv_fd, StaticReadEvent);
6166 if (t->proxy->srvtimeout)
6167 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6168
6169 /* We must ensure that the read part is still alive when switching
6170 * to shutw */
6171 FD_SET(t->srv_fd, StaticReadEvent);
6172 if (t->proxy->srvtimeout)
6173 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6174
willy tarreau036e1ce2005-12-17 13:46:33 +01006175 t->srv_state = SV_STSHUTW;
6176 if (!(t->flags & SN_ERR_MASK))
6177 t->flags |= SN_ERR_SRVTO;
6178 if (!(t->flags & SN_FINST_MASK))
6179 t->flags |= SN_FINST_H;
6180 return 1;
6181 }
willy tarreau0f7af912005-12-17 12:21:26 +01006182
6183 if (req->l == 0) {
6184 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6185 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6186 tv_eternity(&t->swexpire);
6187 }
6188 }
6189 else { /* client buffer not empty */
6190 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6191 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006192 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006193 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006194 /* FIXME: to prevent the server from expiring read timeouts during writes,
6195 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006196 t->srexpire = t->swexpire;
6197 }
willy tarreau0f7af912005-12-17 12:21:26 +01006198 else
6199 tv_eternity(&t->swexpire);
6200 }
6201 }
6202
willy tarreau5cbea6f2005-12-17 12:48:26 +01006203 /* be nice with the client side which would like to send a complete header
6204 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
6205 * would read all remaining data at once ! The client should not write past rep->lr
6206 * when the server is in header state.
6207 */
6208 //return header_processed;
6209 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01006210 }
6211 else if (s == SV_STDATA) {
6212 /* read or write error */
6213 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006214 tv_eternity(&t->srexpire);
6215 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006216 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006217 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006218 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006219 t->srv->failed_resp++;
6220 }
6221 t->proxy->failed_resp++;
willy tarreau0f7af912005-12-17 12:21:26 +01006222 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006223 if (!(t->flags & SN_ERR_MASK))
6224 t->flags |= SN_ERR_SRVCL;
6225 if (!(t->flags & SN_FINST_MASK))
6226 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006227 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006228 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006229 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006230 if (may_dequeue_tasks(t->srv, t->proxy))
6231 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006232
willy tarreau0f7af912005-12-17 12:21:26 +01006233 return 1;
6234 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006235 /* last read, or end of client write */
6236 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006237 FD_CLR(t->srv_fd, StaticReadEvent);
6238 tv_eternity(&t->srexpire);
6239 shutdown(t->srv_fd, SHUT_RD);
6240 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006241 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01006242 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006243 }
6244 /* end of client read and no more data to send */
6245 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
6246 FD_CLR(t->srv_fd, StaticWriteEvent);
6247 tv_eternity(&t->swexpire);
6248 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006249 /* We must ensure that the read part is still alive when switching
6250 * to shutw */
6251 FD_SET(t->srv_fd, StaticReadEvent);
6252 if (t->proxy->srvtimeout)
6253 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6254
willy tarreaua41a8b42005-12-17 14:02:24 +01006255 t->srv_state = SV_STSHUTW;
6256 return 1;
6257 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006258 /* read timeout */
6259 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6260 FD_CLR(t->srv_fd, StaticReadEvent);
6261 tv_eternity(&t->srexpire);
6262 shutdown(t->srv_fd, SHUT_RD);
6263 t->srv_state = SV_STSHUTR;
6264 if (!(t->flags & SN_ERR_MASK))
6265 t->flags |= SN_ERR_SRVTO;
6266 if (!(t->flags & SN_FINST_MASK))
6267 t->flags |= SN_FINST_D;
6268 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006269 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006270 /* write timeout */
6271 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006272 FD_CLR(t->srv_fd, StaticWriteEvent);
6273 tv_eternity(&t->swexpire);
6274 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006275 /* We must ensure that the read part is still alive when switching
6276 * to shutw */
6277 FD_SET(t->srv_fd, StaticReadEvent);
6278 if (t->proxy->srvtimeout)
6279 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01006280 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01006281 if (!(t->flags & SN_ERR_MASK))
6282 t->flags |= SN_ERR_SRVTO;
6283 if (!(t->flags & SN_FINST_MASK))
6284 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01006285 return 1;
6286 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006287
6288 /* recompute request time-outs */
6289 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006290 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6291 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6292 tv_eternity(&t->swexpire);
6293 }
6294 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006295 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01006296 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6297 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006298 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006299 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006300 /* FIXME: to prevent the server from expiring read timeouts during writes,
6301 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006302 t->srexpire = t->swexpire;
6303 }
willy tarreau0f7af912005-12-17 12:21:26 +01006304 else
6305 tv_eternity(&t->swexpire);
6306 }
6307 }
6308
willy tarreaub1ff9db2005-12-17 13:51:03 +01006309 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01006310 if (rep->l == BUFSIZE) { /* no room to read more data */
6311 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6312 FD_CLR(t->srv_fd, StaticReadEvent);
6313 tv_eternity(&t->srexpire);
6314 }
6315 }
6316 else {
6317 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6318 FD_SET(t->srv_fd, StaticReadEvent);
6319 if (t->proxy->srvtimeout)
6320 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6321 else
6322 tv_eternity(&t->srexpire);
6323 }
6324 }
6325
6326 return 0; /* other cases change nothing */
6327 }
6328 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006329 if (t->res_sw == RES_ERROR) {
6330 //FD_CLR(t->srv_fd, StaticWriteEvent);
6331 tv_eternity(&t->swexpire);
6332 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006333 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006334 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006335 t->srv->failed_resp++;
6336 }
6337 t->proxy->failed_resp++;
willy tarreau036e1ce2005-12-17 13:46:33 +01006338 //close(t->srv_fd);
6339 t->srv_state = SV_STCLOSE;
6340 if (!(t->flags & SN_ERR_MASK))
6341 t->flags |= SN_ERR_SRVCL;
6342 if (!(t->flags & SN_FINST_MASK))
6343 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006344 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006345 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006346 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006347 if (may_dequeue_tasks(t->srv, t->proxy))
6348 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006349
willy tarreau036e1ce2005-12-17 13:46:33 +01006350 return 1;
6351 }
6352 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006353 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006354 tv_eternity(&t->swexpire);
6355 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006356 if (t->srv)
6357 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006358 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006359 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006360 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006361 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006362 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006363 if (may_dequeue_tasks(t->srv, t->proxy))
6364 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006365
willy tarreau0f7af912005-12-17 12:21:26 +01006366 return 1;
6367 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006368 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6369 //FD_CLR(t->srv_fd, StaticWriteEvent);
6370 tv_eternity(&t->swexpire);
6371 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006372 if (t->srv)
6373 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006374 //close(t->srv_fd);
6375 t->srv_state = SV_STCLOSE;
6376 if (!(t->flags & SN_ERR_MASK))
6377 t->flags |= SN_ERR_SRVTO;
6378 if (!(t->flags & SN_FINST_MASK))
6379 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006380 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006381 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006382 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006383 if (may_dequeue_tasks(t->srv, t->proxy))
6384 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006385
willy tarreau036e1ce2005-12-17 13:46:33 +01006386 return 1;
6387 }
willy tarreau0f7af912005-12-17 12:21:26 +01006388 else if (req->l == 0) {
6389 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6390 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6391 tv_eternity(&t->swexpire);
6392 }
6393 }
6394 else { /* buffer not empty */
6395 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6396 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006397 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006398 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006399 /* FIXME: to prevent the server from expiring read timeouts during writes,
6400 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006401 t->srexpire = t->swexpire;
6402 }
willy tarreau0f7af912005-12-17 12:21:26 +01006403 else
6404 tv_eternity(&t->swexpire);
6405 }
6406 }
6407 return 0;
6408 }
6409 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006410 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006411 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006412 tv_eternity(&t->srexpire);
6413 fd_delete(t->srv_fd);
willy tarreaue3b30652006-05-21 16:23:22 +02006414 if (t->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02006415 t->srv->cur_sess--;
willy tarreaue3b30652006-05-21 16:23:22 +02006416 t->srv->failed_resp++;
6417 }
6418 t->proxy->failed_resp++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006419 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006420 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006421 if (!(t->flags & SN_ERR_MASK))
6422 t->flags |= SN_ERR_SRVCL;
6423 if (!(t->flags & SN_FINST_MASK))
6424 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006425 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006426 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006427 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006428 if (may_dequeue_tasks(t->srv, t->proxy))
6429 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006430
willy tarreau0f7af912005-12-17 12:21:26 +01006431 return 1;
6432 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006433 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
6434 //FD_CLR(t->srv_fd, StaticReadEvent);
6435 tv_eternity(&t->srexpire);
6436 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006437 if (t->srv)
6438 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006439 //close(t->srv_fd);
6440 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006441 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006442 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006443 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006444 if (may_dequeue_tasks(t->srv, t->proxy))
6445 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006446
willy tarreau036e1ce2005-12-17 13:46:33 +01006447 return 1;
6448 }
6449 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6450 //FD_CLR(t->srv_fd, StaticReadEvent);
6451 tv_eternity(&t->srexpire);
6452 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006453 if (t->srv)
6454 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006455 //close(t->srv_fd);
6456 t->srv_state = SV_STCLOSE;
6457 if (!(t->flags & SN_ERR_MASK))
6458 t->flags |= SN_ERR_SRVTO;
6459 if (!(t->flags & SN_FINST_MASK))
6460 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006461 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006462 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006463 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006464 if (may_dequeue_tasks(t->srv, t->proxy))
6465 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006466
willy tarreau036e1ce2005-12-17 13:46:33 +01006467 return 1;
6468 }
willy tarreau0f7af912005-12-17 12:21:26 +01006469 else if (rep->l == BUFSIZE) { /* no room to read more data */
6470 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6471 FD_CLR(t->srv_fd, StaticReadEvent);
6472 tv_eternity(&t->srexpire);
6473 }
6474 }
6475 else {
6476 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6477 FD_SET(t->srv_fd, StaticReadEvent);
6478 if (t->proxy->srvtimeout)
6479 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6480 else
6481 tv_eternity(&t->srexpire);
6482 }
6483 }
6484 return 0;
6485 }
6486 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01006487 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006488 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006489 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006490 write(1, trash, len);
6491 }
6492 return 0;
6493 }
6494 return 0;
6495}
6496
6497
willy tarreau5cbea6f2005-12-17 12:48:26 +01006498/* Processes the client and server jobs of a session task, then
6499 * puts it back to the wait queue in a clean state, or
6500 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006501 * the time the task accepts to wait, or TIME_ETERNITY for
6502 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01006503 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006504int process_session(struct task *t) {
6505 struct session *s = t->context;
6506 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006507
willy tarreau5cbea6f2005-12-17 12:48:26 +01006508 do {
6509 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01006510 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006511 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006512 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006513 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006514 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006515 } while (fsm_resync);
6516
6517 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006518 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006519 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01006520
willy tarreau5cbea6f2005-12-17 12:48:26 +01006521 tv_min(&min1, &s->crexpire, &s->cwexpire);
6522 tv_min(&min2, &s->srexpire, &s->swexpire);
6523 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01006524 tv_min(&t->expire, &min1, &min2);
6525
6526 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006527 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01006528
Willy TARREAU1cec83c2006-03-01 22:33:49 +01006529#ifdef DEBUG_FULL
6530 /* DEBUG code : this should never ever happen, otherwise it indicates
6531 * that a task still has something to do and will provoke a quick loop.
6532 */
6533 if (tv_remain2(&now, &t->expire) <= 0)
6534 exit(100);
6535#endif
6536
willy tarreaub952e1d2005-12-18 01:31:20 +01006537 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01006538 }
6539
willy tarreau5cbea6f2005-12-17 12:48:26 +01006540 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01006541 actconn--;
6542
willy tarreau982249e2005-12-18 00:57:06 +01006543 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006544 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006545 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n", s->uniq_id, s->proxy->id, (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006546 write(1, trash, len);
6547 }
6548
willy tarreau750a4722005-12-17 13:21:24 +01006549 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01006550 if (s->rep != NULL)
6551 s->logs.bytes = s->rep->total;
6552
willy tarreau9fe663a2005-12-17 13:02:59 +01006553 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01006554 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01006555 sess_log(s);
6556
willy tarreau0f7af912005-12-17 12:21:26 +01006557 /* the task MUST not be in the run queue anymore */
6558 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006559 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01006560 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01006561 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006562}
6563
6564
willy tarreau2812edc2006-05-04 12:09:37 +02006565/* Sets server <s> down, notifies by all available means, recounts the
6566 * remaining servers on the proxy and transfers queued sessions whenever
6567 * possible to other servers.
6568 */
6569void set_server_down(struct server *s) {
6570 struct pendconn *pc, *pc_bck, *pc_end;
6571 struct session *sess;
6572 int xferred;
6573
6574 s->state &= ~SRV_RUNNING;
6575
6576 if (s->health == s->rise) {
6577 recount_servers(s->proxy);
6578 recalc_server_map(s->proxy);
6579
6580 /* we might have sessions queued on this server and waiting for
6581 * a connection. Those which are redispatchable will be queued
6582 * to another server or to the proxy itself.
6583 */
6584 xferred = 0;
6585 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
6586 sess = pc->sess;
6587 if ((sess->proxy->options & PR_O_REDISP)) {
6588 /* The REDISP option was specified. We will ignore
6589 * cookie and force to balance or use the dispatcher.
6590 */
6591 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
6592 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
6593 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
6594 sess->flags &= ~SN_CK_MASK;
6595 sess->flags |= SN_CK_DOWN;
6596 }
6597 pendconn_free(pc);
6598 task_wakeup(&rq, sess->task);
6599 xferred++;
6600 }
6601 }
6602
6603 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
6604 " %d sessions active, %d requeued, %d remaining in queue.\n",
6605 s->state & SRV_BACKUP ? "Backup " : "",
6606 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6607 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6608 s->cur_sess, xferred, s->nbpend);
6609
willy tarreaubc2eda62006-05-04 15:16:23 +02006610 Warning("%s", trash);
6611 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02006612
6613 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
6614 Alert("Proxy %s has no server available !\n", s->proxy->id);
6615 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
6616 }
willy tarreaucb406512006-05-18 00:52:35 +02006617 s->down_trans++;
willy tarreau2812edc2006-05-04 12:09:37 +02006618 }
6619 s->health = 0; /* failure */
6620}
6621
6622
willy tarreau5cbea6f2005-12-17 12:48:26 +01006623
6624/*
6625 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006626 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01006627 */
6628int process_chk(struct task *t) {
6629 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01006630 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01006631 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006632
willy tarreauef900ab2005-12-17 12:52:52 +01006633 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006634
willy tarreau25424f82006-03-19 19:37:48 +01006635 new_chk:
6636 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006637 if (fd < 0) { /* no check currently running */
6638 //fprintf(stderr, "process_chk: 2\n");
6639 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
6640 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006641 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006642 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006643
6644 /* we don't send any health-checks when the proxy is stopped or when
6645 * the server should not be checked.
6646 */
6647 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01006648 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6649 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01006650 task_queue(t); /* restore t to its place in the task list */
6651 return tv_remain2(&now, &t->expire);
6652 }
6653
willy tarreau5cbea6f2005-12-17 12:48:26 +01006654 /* we'll initiate a new check */
6655 s->result = 0; /* no result yet */
6656 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006657 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01006658 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
6659 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
6660 //fprintf(stderr, "process_chk: 3\n");
6661
willy tarreaua41a8b42005-12-17 14:02:24 +01006662 /* we'll connect to the check port on the server */
6663 sa = s->addr;
6664 sa.sin_port = htons(s->check_port);
6665
willy tarreau0174f312005-12-18 01:02:42 +01006666 /* allow specific binding :
6667 * - server-specific at first
6668 * - proxy-specific next
6669 */
6670 if (s->state & SRV_BIND_SRC) {
6671 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6672 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
6673 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
6674 s->proxy->id, s->id);
6675 s->result = -1;
6676 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006677 }
willy tarreau0174f312005-12-18 01:02:42 +01006678 else if (s->proxy->options & PR_O_BIND_SRC) {
6679 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6680 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
6681 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
6682 s->proxy->id);
6683 s->result = -1;
6684 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006685 }
willy tarreau0174f312005-12-18 01:02:42 +01006686
6687 if (!s->result) {
6688 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
6689 /* OK, connection in progress or established */
6690
6691 //fprintf(stderr, "process_chk: 4\n");
6692
6693 s->curfd = fd; /* that's how we know a test is in progress ;-) */
6694 fdtab[fd].owner = t;
6695 fdtab[fd].read = &event_srv_chk_r;
6696 fdtab[fd].write = &event_srv_chk_w;
6697 fdtab[fd].state = FD_STCONN; /* connection in progress */
6698 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01006699#ifdef DEBUG_FULL
6700 assert (!FD_ISSET(fd, StaticReadEvent));
6701#endif
willy tarreau0174f312005-12-18 01:02:42 +01006702 fd_insert(fd);
6703 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
6704 tv_delayfrom(&t->expire, &now, s->inter);
6705 task_queue(t); /* restore t to its place in the task list */
6706 return tv_remain(&now, &t->expire);
6707 }
6708 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
6709 s->result = -1; /* a real error */
6710 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006711 }
6712 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006713 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006714 }
6715
6716 if (!s->result) { /* nothing done */
6717 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006718 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6719 tv_delayfrom(&t->expire, &t->expire, s->inter);
6720 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006721 }
6722
6723 /* here, we have seen a failure */
willy tarreaucb406512006-05-18 00:52:35 +02006724 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006725 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006726 s->failed_checks++;
6727 }
willy tarreau2812edc2006-05-04 12:09:37 +02006728 else
6729 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006730
6731 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006732 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006733 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6734 tv_delayfrom(&t->expire, &t->expire, s->inter);
6735 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006736 }
6737 else {
6738 //fprintf(stderr, "process_chk: 8\n");
6739 /* there was a test running */
6740 if (s->result > 0) { /* good server detected */
6741 //fprintf(stderr, "process_chk: 9\n");
6742 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006743 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006744 s->state |= SRV_RUNNING;
6745
willy tarreau535ae7a2005-12-17 12:58:00 +01006746 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006747 int xferred;
6748
willy tarreau62084d42006-03-24 18:57:41 +01006749 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006750 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006751
6752 /* check if we can handle some connections queued at the proxy. We
6753 * will take as many as we can handle.
6754 */
willy tarreauf76e6ca2006-05-21 21:09:55 +02006755 for (xferred = 0; !s->maxconn || xferred < srv_dynamic_maxconn(s); xferred++) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006756 struct session *sess;
6757 struct pendconn *p;
6758
6759 p = pendconn_from_px(s->proxy);
6760 if (!p)
6761 break;
6762 p->sess->srv = s;
6763 sess = p->sess;
6764 pendconn_free(p);
6765 task_wakeup(&rq, sess->task);
6766 }
6767
6768 sprintf(trash,
6769 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6770 " %d sessions requeued, %d total in queue.\n",
6771 s->state & SRV_BACKUP ? "Backup " : "",
6772 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6773 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6774 xferred, s->nbpend);
6775
6776 Warning("%s", trash);
6777 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006778 }
willy tarreauef900ab2005-12-17 12:52:52 +01006779
willy tarreaue47c8d72005-12-17 12:55:52 +01006780 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006781 }
willy tarreauef900ab2005-12-17 12:52:52 +01006782 s->curfd = -1; /* no check running anymore */
6783 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006784 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006785 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6786 tv_delayfrom(&t->expire, &t->expire, s->inter);
6787 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006788 }
6789 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6790 //fprintf(stderr, "process_chk: 10\n");
6791 /* failure or timeout detected */
willy tarreaucb406512006-05-18 00:52:35 +02006792 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006793 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006794 s->failed_checks++;
6795 }
willy tarreau2812edc2006-05-04 12:09:37 +02006796 else
6797 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006798 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006799 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006800 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006801 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6802 tv_delayfrom(&t->expire, &t->expire, s->inter);
6803 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006804 }
6805 /* if result is 0 and there's no timeout, we have to wait again */
6806 }
6807 //fprintf(stderr, "process_chk: 11\n");
6808 s->result = 0;
6809 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006810 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006811}
6812
6813
willy tarreau5cbea6f2005-12-17 12:48:26 +01006814
willy tarreau59a6cc22006-05-12 01:29:08 +02006815/*
6816 * Manages a server's connection queue. If woken up, will try to dequeue as
6817 * many pending sessions as possible, and wake them up. The task has nothing
6818 * else to do, so it always returns TIME_ETERNITY.
6819 */
6820int process_srv_queue(struct task *t) {
6821 struct server *s = (struct server*)t->context;
6822 struct proxy *p = s->proxy;
6823 int xferred;
6824
6825 /* First, check if we can handle some connections queued at the proxy. We
6826 * will take as many as we can handle.
6827 */
willy tarreauf76e6ca2006-05-21 21:09:55 +02006828 for (xferred = 0; s->cur_sess + xferred < srv_dynamic_maxconn(s); xferred++) {
willy tarreau59a6cc22006-05-12 01:29:08 +02006829 struct session *sess;
6830
6831 sess = pendconn_get_next_sess(s, p);
6832 if (sess == NULL)
6833 break;
6834 task_wakeup(&rq, sess->task);
6835 }
6836
6837 return TIME_ETERNITY;
6838}
6839
willy tarreau0f7af912005-12-17 12:21:26 +01006840#if STATTIME > 0
6841int stats(void);
6842#endif
6843
6844/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006845 * This does 4 things :
6846 * - wake up all expired tasks
6847 * - call all runnable tasks
6848 * - call maintain_proxies() to enable/disable the listeners
6849 * - return the delay till next event in ms, -1 = wait indefinitely
6850 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6851 *
willy tarreau0f7af912005-12-17 12:21:26 +01006852 */
6853
willy tarreau1c2ad212005-12-18 01:11:29 +01006854int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006855 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006856 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006857 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006858
willy tarreaub952e1d2005-12-18 01:31:20 +01006859 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006860
willy tarreau1c2ad212005-12-18 01:11:29 +01006861 /* look for expired tasks and add them to the run queue.
6862 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006863 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6864 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006865 tnext = t->next;
6866 if (t->state & TASK_RUNNING)
6867 continue;
6868
willy tarreaub952e1d2005-12-18 01:31:20 +01006869 if (tv_iseternity(&t->expire))
6870 continue;
6871
willy tarreau1c2ad212005-12-18 01:11:29 +01006872 /* wakeup expired entries. It doesn't matter if they are
6873 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006874 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006875 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006876 task_wakeup(&rq, t);
6877 }
6878 else {
6879 /* first non-runnable task. Use its expiration date as an upper bound */
6880 int temp_time = tv_remain(&now, &t->expire);
6881 if (temp_time)
6882 next_time = temp_time;
6883 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006884 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006885 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006886
willy tarreau1c2ad212005-12-18 01:11:29 +01006887 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006888 * since we only use the run queue's head. Note that any task can be
6889 * woken up by any other task and it will be processed immediately
6890 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006891 */
willy tarreau7feab592006-04-22 15:13:16 +02006892 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006893 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006894
willy tarreau1c2ad212005-12-18 01:11:29 +01006895 task_sleep(&rq, t);
6896 temp_time = t->process(t);
6897 next_time = MINTIME(temp_time, next_time);
6898 }
6899
6900 /* maintain all proxies in a consistent state. This should quickly become a task */
6901 time2 = maintain_proxies();
6902 return MINTIME(time2, next_time);
6903}
6904
6905
6906#if defined(ENABLE_EPOLL)
6907
6908/*
6909 * Main epoll() loop.
6910 */
6911
6912/* does 3 actions :
6913 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6914 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6915 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6916 *
6917 * returns 0 if initialization failed, !0 otherwise.
6918 */
6919
6920int epoll_loop(int action) {
6921 int next_time;
6922 int status;
6923 int fd;
6924
6925 int fds, count;
6926 int pr, pw, sr, sw;
6927 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6928 struct epoll_event ev;
6929
6930 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006931 static struct epoll_event *epoll_events = NULL;
6932 static int epoll_fd;
6933
6934 if (action == POLL_LOOP_ACTION_INIT) {
6935 epoll_fd = epoll_create(global.maxsock + 1);
6936 if (epoll_fd < 0)
6937 return 0;
6938 else {
6939 epoll_events = (struct epoll_event*)
6940 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6941 PrevReadEvent = (fd_set *)
6942 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6943 PrevWriteEvent = (fd_set *)
6944 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006945 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006946 return 1;
6947 }
6948 else if (action == POLL_LOOP_ACTION_CLEAN) {
6949 if (PrevWriteEvent) free(PrevWriteEvent);
6950 if (PrevReadEvent) free(PrevReadEvent);
6951 if (epoll_events) free(epoll_events);
6952 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006953 epoll_fd = 0;
6954 return 1;
6955 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006956
willy tarreau1c2ad212005-12-18 01:11:29 +01006957 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006958
willy tarreau1c2ad212005-12-18 01:11:29 +01006959 tv_now(&now);
6960
6961 while (1) {
6962 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006963
6964 /* stop when there's no connection left and we don't allow them anymore */
6965 if (!actconn && listeners == 0)
6966 break;
6967
willy tarreau0f7af912005-12-17 12:21:26 +01006968#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006969 {
6970 int time2;
6971 time2 = stats();
6972 next_time = MINTIME(time2, next_time);
6973 }
willy tarreau0f7af912005-12-17 12:21:26 +01006974#endif
6975
willy tarreau1c2ad212005-12-18 01:11:29 +01006976 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6977
6978 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6979 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6980
6981 if ((ro^rn) | (wo^wn)) {
6982 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6983#define FDSETS_ARE_INT_ALIGNED
6984#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006985
willy tarreauad90a0c2005-12-18 01:09:15 +01006986#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6987#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006988 pr = (ro >> count) & 1;
6989 pw = (wo >> count) & 1;
6990 sr = (rn >> count) & 1;
6991 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006992#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006993 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6994 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6995 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6996 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006997#endif
6998#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006999 pr = FD_ISSET(fd, PrevReadEvent);
7000 pw = FD_ISSET(fd, PrevWriteEvent);
7001 sr = FD_ISSET(fd, StaticReadEvent);
7002 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01007003#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01007004 if (!((sr^pr) | (sw^pw)))
7005 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01007006
willy tarreau1c2ad212005-12-18 01:11:29 +01007007 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
7008 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01007009
willy tarreaub952e1d2005-12-18 01:31:20 +01007010#ifdef EPOLL_CTL_MOD_WORKAROUND
7011 /* I encountered a rarely reproducible problem with
7012 * EPOLL_CTL_MOD where a modified FD (systematically
7013 * the one in epoll_events[0], fd#7) would sometimes
7014 * be set EPOLL_OUT while asked for a read ! This is
7015 * with the 2.4 epoll patch. The workaround is to
7016 * delete then recreate in case of modification.
7017 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
7018 * nor RHEL kernels.
7019 */
7020
7021 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
7022 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
7023
7024 if ((sr | sw))
7025 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
7026#else
willy tarreau1c2ad212005-12-18 01:11:29 +01007027 if ((pr | pw)) {
7028 /* the file-descriptor already exists... */
7029 if ((sr | sw)) {
7030 /* ...and it will still exist */
7031 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
7032 // perror("epoll_ctl(MOD)");
7033 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007034 }
7035 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01007036 /* ...and it will be removed */
7037 if (fdtab[fd].state != FD_STCLOSE &&
7038 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
7039 // perror("epoll_ctl(DEL)");
7040 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01007041 }
7042 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007043 } else {
7044 /* the file-descriptor did not exist, let's add it */
7045 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
7046 // perror("epoll_ctl(ADD)");
7047 // exit(1);
7048 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007049 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007050#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01007051 }
7052 ((int*)PrevReadEvent)[fds] = rn;
7053 ((int*)PrevWriteEvent)[fds] = wn;
7054 }
7055 }
7056
7057 /* now let's wait for events */
7058 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
7059 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007060
willy tarreau1c2ad212005-12-18 01:11:29 +01007061 for (count = 0; count < status; count++) {
7062 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01007063
7064 if (FD_ISSET(fd, StaticReadEvent)) {
7065 if (fdtab[fd].state == FD_STCLOSE)
7066 continue;
7067 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
7068 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007069 }
willy tarreau05be12b2006-03-19 19:35:00 +01007070
7071 if (FD_ISSET(fd, StaticWriteEvent)) {
7072 if (fdtab[fd].state == FD_STCLOSE)
7073 continue;
7074 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
7075 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007076 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007077 }
7078 }
7079 return 1;
7080}
7081#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007082
willy tarreauad90a0c2005-12-18 01:09:15 +01007083
willy tarreau5cbea6f2005-12-17 12:48:26 +01007084
willy tarreau1c2ad212005-12-18 01:11:29 +01007085#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01007086
willy tarreau1c2ad212005-12-18 01:11:29 +01007087/*
7088 * Main poll() loop.
7089 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007090
willy tarreau1c2ad212005-12-18 01:11:29 +01007091/* does 3 actions :
7092 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7093 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7094 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7095 *
7096 * returns 0 if initialization failed, !0 otherwise.
7097 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007098
willy tarreau1c2ad212005-12-18 01:11:29 +01007099int poll_loop(int action) {
7100 int next_time;
7101 int status;
7102 int fd, nbfd;
7103
7104 int fds, count;
7105 int sr, sw;
7106 unsigned rn, wn; /* read new, write new */
7107
7108 /* private data */
7109 static struct pollfd *poll_events = NULL;
7110
7111 if (action == POLL_LOOP_ACTION_INIT) {
7112 poll_events = (struct pollfd*)
7113 calloc(1, sizeof(struct pollfd) * global.maxsock);
7114 return 1;
7115 }
7116 else if (action == POLL_LOOP_ACTION_CLEAN) {
7117 if (poll_events)
7118 free(poll_events);
7119 return 1;
7120 }
7121
7122 /* OK, it's POLL_LOOP_ACTION_RUN */
7123
7124 tv_now(&now);
7125
7126 while (1) {
7127 next_time = process_runnable_tasks();
7128
7129 /* stop when there's no connection left and we don't allow them anymore */
7130 if (!actconn && listeners == 0)
7131 break;
7132
7133#if STATTIME > 0
7134 {
7135 int time2;
7136 time2 = stats();
7137 next_time = MINTIME(time2, next_time);
7138 }
7139#endif
7140
7141
7142 nbfd = 0;
7143 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
7144
7145 rn = ((int*)StaticReadEvent)[fds];
7146 wn = ((int*)StaticWriteEvent)[fds];
7147
7148 if ((rn|wn)) {
7149 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
7150#define FDSETS_ARE_INT_ALIGNED
7151#ifdef FDSETS_ARE_INT_ALIGNED
7152
7153#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7154#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
7155 sr = (rn >> count) & 1;
7156 sw = (wn >> count) & 1;
7157#else
7158 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
7159 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
7160#endif
7161#else
7162 sr = FD_ISSET(fd, StaticReadEvent);
7163 sw = FD_ISSET(fd, StaticWriteEvent);
7164#endif
7165 if ((sr|sw)) {
7166 poll_events[nbfd].fd = fd;
7167 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
7168 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01007169 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007170 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007171 }
7172 }
7173
7174 /* now let's wait for events */
7175 status = poll(poll_events, nbfd, next_time);
7176 tv_now(&now);
7177
7178 for (count = 0; status > 0 && count < nbfd; count++) {
7179 fd = poll_events[count].fd;
7180
willy tarreau606788e2006-05-21 16:26:20 +02007181 if (!(poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP )))
willy tarreau1c2ad212005-12-18 01:11:29 +01007182 continue;
7183
7184 /* ok, we found one active fd */
7185 status--;
7186
willy tarreau05be12b2006-03-19 19:35:00 +01007187 if (FD_ISSET(fd, StaticReadEvent)) {
7188 if (fdtab[fd].state == FD_STCLOSE)
7189 continue;
7190 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
7191 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007192 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007193
willy tarreau05be12b2006-03-19 19:35:00 +01007194 if (FD_ISSET(fd, StaticWriteEvent)) {
7195 if (fdtab[fd].state == FD_STCLOSE)
7196 continue;
7197 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
7198 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007199 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007200 }
7201 }
7202 return 1;
7203}
willy tarreauad90a0c2005-12-18 01:09:15 +01007204#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007205
willy tarreauad90a0c2005-12-18 01:09:15 +01007206
willy tarreauad90a0c2005-12-18 01:09:15 +01007207
willy tarreau1c2ad212005-12-18 01:11:29 +01007208/*
7209 * Main select() loop.
7210 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007211
willy tarreau1c2ad212005-12-18 01:11:29 +01007212/* does 3 actions :
7213 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7214 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7215 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7216 *
7217 * returns 0 if initialization failed, !0 otherwise.
7218 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007219
willy tarreauad90a0c2005-12-18 01:09:15 +01007220
willy tarreau1c2ad212005-12-18 01:11:29 +01007221int select_loop(int action) {
7222 int next_time;
7223 int status;
7224 int fd,i;
7225 struct timeval delta;
7226 int readnotnull, writenotnull;
7227 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01007228
willy tarreau1c2ad212005-12-18 01:11:29 +01007229 if (action == POLL_LOOP_ACTION_INIT) {
7230 ReadEvent = (fd_set *)
7231 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7232 WriteEvent = (fd_set *)
7233 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7234 return 1;
7235 }
7236 else if (action == POLL_LOOP_ACTION_CLEAN) {
7237 if (WriteEvent) free(WriteEvent);
7238 if (ReadEvent) free(ReadEvent);
7239 return 1;
7240 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007241
willy tarreau1c2ad212005-12-18 01:11:29 +01007242 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01007243
willy tarreau1c2ad212005-12-18 01:11:29 +01007244 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007245
willy tarreau1c2ad212005-12-18 01:11:29 +01007246 while (1) {
7247 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01007248
willy tarreau1c2ad212005-12-18 01:11:29 +01007249 /* stop when there's no connection left and we don't allow them anymore */
7250 if (!actconn && listeners == 0)
7251 break;
7252
7253#if STATTIME > 0
7254 {
7255 int time2;
7256 time2 = stats();
7257 next_time = MINTIME(time2, next_time);
7258 }
7259#endif
7260
willy tarreau1c2ad212005-12-18 01:11:29 +01007261 if (next_time > 0) { /* FIXME */
7262 /* Convert to timeval */
7263 /* to avoid eventual select loops due to timer precision */
7264 next_time += SCHEDULER_RESOLUTION;
7265 delta.tv_sec = next_time / 1000;
7266 delta.tv_usec = (next_time % 1000) * 1000;
7267 }
7268 else if (next_time == 0) { /* allow select to return immediately when needed */
7269 delta.tv_sec = delta.tv_usec = 0;
7270 }
7271
7272
7273 /* let's restore fdset state */
7274
7275 readnotnull = 0; writenotnull = 0;
7276 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
7277 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
7278 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
7279 }
7280
7281 // /* just a verification code, needs to be removed for performance */
7282 // for (i=0; i<maxfd; i++) {
7283 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
7284 // abort();
7285 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
7286 // abort();
7287 //
7288 // }
7289
7290 status = select(maxfd,
7291 readnotnull ? ReadEvent : NULL,
7292 writenotnull ? WriteEvent : NULL,
7293 NULL,
7294 (next_time >= 0) ? &delta : NULL);
7295
7296 /* this is an experiment on the separation of the select work */
7297 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7298 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7299
7300 tv_now(&now);
7301
7302 if (status > 0) { /* must proceed with events */
7303
7304 int fds;
7305 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01007306
willy tarreau1c2ad212005-12-18 01:11:29 +01007307 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
7308 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
7309 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
7310
7311 /* if we specify read first, the accepts and zero reads will be
7312 * seen first. Moreover, system buffers will be flushed faster.
7313 */
willy tarreau05be12b2006-03-19 19:35:00 +01007314 if (FD_ISSET(fd, ReadEvent)) {
7315 if (fdtab[fd].state == FD_STCLOSE)
7316 continue;
7317 fdtab[fd].read(fd);
7318 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007319
willy tarreau05be12b2006-03-19 19:35:00 +01007320 if (FD_ISSET(fd, WriteEvent)) {
7321 if (fdtab[fd].state == FD_STCLOSE)
7322 continue;
7323 fdtab[fd].write(fd);
7324 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007325 }
7326 }
7327 else {
7328 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01007329 }
willy tarreau0f7af912005-12-17 12:21:26 +01007330 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007331 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01007332}
7333
7334
7335#if STATTIME > 0
7336/*
7337 * Display proxy statistics regularly. It is designed to be called from the
7338 * select_loop().
7339 */
7340int stats(void) {
7341 static int lines;
7342 static struct timeval nextevt;
7343 static struct timeval lastevt;
7344 static struct timeval starttime = {0,0};
7345 unsigned long totaltime, deltatime;
7346 int ret;
7347
willy tarreau750a4722005-12-17 13:21:24 +01007348 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01007349 deltatime = (tv_diff(&lastevt, &now)?:1);
7350 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01007351
willy tarreau9fe663a2005-12-17 13:02:59 +01007352 if (global.mode & MODE_STATS) {
7353 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007354 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007355 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
7356 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007357 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01007358 actconn, totalconn,
7359 stats_tsk_new, stats_tsk_good,
7360 stats_tsk_left, stats_tsk_right,
7361 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
7362 }
7363 }
7364
7365 tv_delayfrom(&nextevt, &now, STATTIME);
7366
7367 lastevt=now;
7368 }
7369 ret = tv_remain(&now, &nextevt);
7370 return ret;
7371}
7372#endif
7373
7374
7375/*
7376 * this function enables proxies when there are enough free sessions,
7377 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01007378 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01007379 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01007380 */
7381static int maintain_proxies(void) {
7382 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01007383 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007384 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01007385
7386 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01007387 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01007388
7389 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01007390 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01007391 while (p) {
7392 if (p->nbconn < p->maxconn) {
7393 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007394 for (l = p->listen; l != NULL; l = l->next) {
7395 FD_SET(l->fd, StaticReadEvent);
7396 }
willy tarreau0f7af912005-12-17 12:21:26 +01007397 p->state = PR_STRUN;
7398 }
7399 }
7400 else {
7401 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007402 for (l = p->listen; l != NULL; l = l->next) {
7403 FD_CLR(l->fd, StaticReadEvent);
7404 }
willy tarreau0f7af912005-12-17 12:21:26 +01007405 p->state = PR_STIDLE;
7406 }
7407 }
7408 p = p->next;
7409 }
7410 }
7411 else { /* block all proxies */
7412 while (p) {
7413 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007414 for (l = p->listen; l != NULL; l = l->next) {
7415 FD_CLR(l->fd, StaticReadEvent);
7416 }
willy tarreau0f7af912005-12-17 12:21:26 +01007417 p->state = PR_STIDLE;
7418 }
7419 p = p->next;
7420 }
7421 }
7422
willy tarreau5cbea6f2005-12-17 12:48:26 +01007423 if (stopping) {
7424 p = proxy;
7425 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007426 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007427 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01007428 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007429 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007430 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01007431 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01007432
willy tarreaua41a8b42005-12-17 14:02:24 +01007433 for (l = p->listen; l != NULL; l = l->next) {
7434 fd_delete(l->fd);
7435 listeners--;
7436 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007437 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007438 }
7439 else {
7440 tleft = MINTIME(t, tleft);
7441 }
7442 }
7443 p = p->next;
7444 }
7445 }
7446 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01007447}
7448
7449/*
7450 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01007451 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
7452 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01007453 */
7454static void soft_stop(void) {
7455 struct proxy *p;
7456
7457 stopping = 1;
7458 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007459 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01007460 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01007461 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007462 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01007463 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01007464 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01007465 }
willy tarreau0f7af912005-12-17 12:21:26 +01007466 p = p->next;
7467 }
7468}
7469
willy tarreaufac1a862006-05-21 10:20:28 +02007470/*
7471 * Linux unbinds the listen socket after a SHUT_RD, and ignores SHUT_WR.
7472 * Solaris refuses either shutdown().
7473 * OpenBSD ignores SHUT_RD but closes upon SHUT_WR and refuses to rebind.
7474 * So a common validation path involves SHUT_WR && listen && SHUT_RD.
7475 * If disabling at least one listener returns an error, then the proxy
7476 * state is set to PR_STERROR because we don't know how to resume from this.
7477 */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007478static void pause_proxy(struct proxy *p) {
7479 struct listener *l;
7480 for (l = p->listen; l != NULL; l = l->next) {
willy tarreaufac1a862006-05-21 10:20:28 +02007481 if (shutdown(l->fd, SHUT_WR) == 0 && listen(l->fd, p->maxconn) == 0 &&
7482 shutdown(l->fd, SHUT_RD) == 0) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007483 FD_CLR(l->fd, StaticReadEvent);
willy tarreaufac1a862006-05-21 10:20:28 +02007484 if (p->state != PR_STERROR)
7485 p->state = PR_STPAUSED;
Willy TARREAU007aa462006-05-14 09:55:23 +02007486 }
willy tarreaufac1a862006-05-21 10:20:28 +02007487 else
7488 p->state = PR_STERROR;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007489 }
7490}
7491
7492/*
7493 * This function temporarily disables listening so that another new instance
7494 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01007495 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01007496 * the proxy, or a SIGTTIN can be sent to listen again.
7497 */
7498static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007499 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007500 struct proxy *p;
7501
Willy TARREAU007aa462006-05-14 09:55:23 +02007502 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007503 p = proxy;
7504 tv_now(&now); /* else, the old time before select will be used */
7505 while (p) {
willy tarreaufac1a862006-05-21 10:20:28 +02007506 if (p->state != PR_STERROR && p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007507 Warning("Pausing proxy %s.\n", p->id);
7508 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
7509 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02007510 if (p->state != PR_STPAUSED) {
7511 err |= 1;
7512 Warning("Proxy %s failed to enter pause mode.\n", p->id);
7513 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
7514 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007515 }
7516 p = p->next;
7517 }
Willy TARREAU007aa462006-05-14 09:55:23 +02007518 if (err) {
7519 Warning("Some proxies refused to pause, performing soft stop now.\n");
7520 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
7521 soft_stop();
7522 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007523}
7524
7525
7526/*
7527 * This function reactivates listening. This can be used after a call to
7528 * sig_pause(), for example when a new instance has failed starting up.
7529 * It is designed to be called upon reception of a SIGTTIN.
7530 */
7531static void listen_proxies(void) {
7532 struct proxy *p;
7533 struct listener *l;
7534
7535 p = proxy;
7536 tv_now(&now); /* else, the old time before select will be used */
7537 while (p) {
7538 if (p->state == PR_STPAUSED) {
7539 Warning("Enabling proxy %s.\n", p->id);
7540 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
7541
7542 for (l = p->listen; l != NULL; l = l->next) {
7543 if (listen(l->fd, p->maxconn) == 0) {
7544 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
7545 FD_SET(l->fd, StaticReadEvent);
7546 p->state = PR_STRUN;
7547 }
7548 else
7549 p->state = PR_STIDLE;
7550 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01007551 int port;
7552
7553 if (l->addr.ss_family == AF_INET6)
7554 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
7555 else
7556 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
7557
willy tarreaudbd3bef2006-01-20 19:35:18 +01007558 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007559 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007560 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007561 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007562 /* Another port might have been enabled. Let's stop everything. */
7563 pause_proxy(p);
7564 break;
7565 }
7566 }
7567 }
7568 p = p->next;
7569 }
7570}
7571
7572
willy tarreau0f7af912005-12-17 12:21:26 +01007573/*
7574 * upon SIGUSR1, let's have a soft stop.
7575 */
7576void sig_soft_stop(int sig) {
7577 soft_stop();
7578 signal(sig, SIG_IGN);
7579}
7580
willy tarreaudbd3bef2006-01-20 19:35:18 +01007581/*
7582 * upon SIGTTOU, we pause everything
7583 */
7584void sig_pause(int sig) {
7585 pause_proxies();
7586 signal(sig, sig_pause);
7587}
willy tarreau0f7af912005-12-17 12:21:26 +01007588
willy tarreau8337c6b2005-12-17 13:41:01 +01007589/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01007590 * upon SIGTTIN, let's have a soft stop.
7591 */
7592void sig_listen(int sig) {
7593 listen_proxies();
7594 signal(sig, sig_listen);
7595}
7596
7597/*
willy tarreau8337c6b2005-12-17 13:41:01 +01007598 * this function dumps every server's state when the process receives SIGHUP.
7599 */
7600void sig_dump_state(int sig) {
7601 struct proxy *p = proxy;
7602
7603 Warning("SIGHUP received, dumping servers states.\n");
7604 while (p) {
7605 struct server *s = p->srv;
7606
willy tarreau4632c212006-05-02 23:32:51 +02007607 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01007608 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02007609 snprintf(trash, sizeof(trash),
7610 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
7611 p->id, s->id,
7612 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
7613 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02007614 Warning("%s\n", trash);
7615 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01007616 s = s->next;
7617 }
willy tarreaudd07e972005-12-18 00:48:48 +01007618
willy tarreau62084d42006-03-24 18:57:41 +01007619 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02007620 snprintf(trash, sizeof(trash),
7621 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
7622 p->id,
7623 (p->srv_bck) ? "is running on backup servers" : "has no server available",
7624 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007625 } else {
7626 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02007627 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
7628 " Conn: %d act, %d pend (%d unass), %d tot.",
7629 p->id, p->srv_act, p->srv_bck,
7630 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007631 }
7632 Warning("%s\n", trash);
7633 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01007634
willy tarreau8337c6b2005-12-17 13:41:01 +01007635 p = p->next;
7636 }
7637 signal(sig, sig_dump_state);
7638}
7639
willy tarreau0f7af912005-12-17 12:21:26 +01007640void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007641 struct task *t, *tnext;
7642 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01007643
willy tarreau5e698ef2006-05-02 14:51:00 +02007644 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
7645 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007646 tnext = t->next;
7647 s = t->context;
7648 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
7649 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
7650 "req=%d, rep=%d, clifd=%d\n",
7651 s, tv_remain(&now, &t->expire),
7652 s->cli_state,
7653 s->srv_state,
7654 FD_ISSET(s->cli_fd, StaticReadEvent),
7655 FD_ISSET(s->cli_fd, StaticWriteEvent),
7656 FD_ISSET(s->srv_fd, StaticReadEvent),
7657 FD_ISSET(s->srv_fd, StaticWriteEvent),
7658 s->req->l, s->rep?s->rep->l:0, s->cli_fd
7659 );
willy tarreau0f7af912005-12-17 12:21:26 +01007660 }
willy tarreau12350152005-12-18 01:03:27 +01007661}
7662
willy tarreau64a3cc32005-12-18 01:13:11 +01007663#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007664static void fast_stop(void)
7665{
7666 struct proxy *p;
7667 p = proxy;
7668 while (p) {
7669 p->grace = 0;
7670 p = p->next;
7671 }
7672 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01007673}
7674
willy tarreau12350152005-12-18 01:03:27 +01007675void sig_int(int sig) {
7676 /* This would normally be a hard stop,
7677 but we want to be sure about deallocation,
7678 and so on, so we do a soft stop with
7679 0 GRACE time
7680 */
7681 fast_stop();
7682 /* If we are killed twice, we decide to die*/
7683 signal(sig, SIG_DFL);
7684}
7685
7686void sig_term(int sig) {
7687 /* This would normally be a hard stop,
7688 but we want to be sure about deallocation,
7689 and so on, so we do a soft stop with
7690 0 GRACE time
7691 */
7692 fast_stop();
7693 /* If we are killed twice, we decide to die*/
7694 signal(sig, SIG_DFL);
7695}
willy tarreau64a3cc32005-12-18 01:13:11 +01007696#endif
willy tarreau12350152005-12-18 01:03:27 +01007697
willy tarreauc1f47532005-12-18 01:08:26 +01007698/* returns the pointer to an error in the replacement string, or NULL if OK */
7699char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01007700 struct hdr_exp *exp;
7701
willy tarreauc1f47532005-12-18 01:08:26 +01007702 if (replace != NULL) {
7703 char *err;
7704 err = check_replace_string(replace);
7705 if (err)
7706 return err;
7707 }
7708
willy tarreaue39cd132005-12-17 13:00:18 +01007709 while (*head != NULL)
7710 head = &(*head)->next;
7711
7712 exp = calloc(1, sizeof(struct hdr_exp));
7713
7714 exp->preg = preg;
7715 exp->replace = replace;
7716 exp->action = action;
7717 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01007718
7719 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007720}
7721
willy tarreau9fe663a2005-12-17 13:02:59 +01007722
willy tarreau0f7af912005-12-17 12:21:26 +01007723/*
willy tarreau9fe663a2005-12-17 13:02:59 +01007724 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01007725 */
willy tarreau9fe663a2005-12-17 13:02:59 +01007726int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01007727
willy tarreau9fe663a2005-12-17 13:02:59 +01007728 if (!strcmp(args[0], "global")) { /* new section */
7729 /* no option, nothing special to do */
7730 return 0;
7731 }
7732 else if (!strcmp(args[0], "daemon")) {
7733 global.mode |= MODE_DAEMON;
7734 }
7735 else if (!strcmp(args[0], "debug")) {
7736 global.mode |= MODE_DEBUG;
7737 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007738 else if (!strcmp(args[0], "noepoll")) {
7739 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7740 }
7741 else if (!strcmp(args[0], "nopoll")) {
7742 cfg_polling_mechanism &= ~POLL_USE_POLL;
7743 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007744 else if (!strcmp(args[0], "quiet")) {
7745 global.mode |= MODE_QUIET;
7746 }
7747 else if (!strcmp(args[0], "stats")) {
7748 global.mode |= MODE_STATS;
7749 }
7750 else if (!strcmp(args[0], "uid")) {
7751 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007752 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007753 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007754 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007755 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007756 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007757 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007758 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007759 global.uid = atol(args[1]);
7760 }
7761 else if (!strcmp(args[0], "gid")) {
7762 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007763 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007764 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007765 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007766 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007767 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007768 return -1;
7769 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007770 global.gid = atol(args[1]);
7771 }
7772 else if (!strcmp(args[0], "nbproc")) {
7773 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007774 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007775 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007776 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007777 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007778 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007779 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007781 global.nbproc = atol(args[1]);
7782 }
7783 else if (!strcmp(args[0], "maxconn")) {
7784 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007785 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007786 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007787 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007788 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007789 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007790 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007791 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007792 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007793#ifdef SYSTEM_MAXCONN
7794 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7795 Alert("parsing [%s:%d] : maxconn value %d too high for this system.\nLimiting to %d. Please use '-n' to force the value.\n", file, linenum, global.maxconn, DEFAULT_MAXCONN);
7796 global.maxconn = DEFAULT_MAXCONN;
7797 }
7798#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007799 }
willy tarreaub1285d52005-12-18 01:20:14 +01007800 else if (!strcmp(args[0], "ulimit-n")) {
7801 if (global.rlimit_nofile != 0) {
7802 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7803 return 0;
7804 }
7805 if (*(args[1]) == 0) {
7806 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7807 return -1;
7808 }
7809 global.rlimit_nofile = atol(args[1]);
7810 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007811 else if (!strcmp(args[0], "chroot")) {
7812 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007813 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007814 return 0;
7815 }
7816 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007817 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007818 return -1;
7819 }
7820 global.chroot = strdup(args[1]);
7821 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007822 else if (!strcmp(args[0], "pidfile")) {
7823 if (global.pidfile != NULL) {
7824 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7825 return 0;
7826 }
7827 if (*(args[1]) == 0) {
7828 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7829 return -1;
7830 }
7831 global.pidfile = strdup(args[1]);
7832 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007833 else if (!strcmp(args[0], "log")) { /* syslog server address */
7834 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007835 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007836
7837 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007838 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007839 return -1;
7840 }
7841
7842 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7843 if (!strcmp(log_facilities[facility], args[2]))
7844 break;
7845
7846 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007847 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007848 exit(1);
7849 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007850
7851 level = 7; /* max syslog level = debug */
7852 if (*(args[3])) {
7853 while (level >= 0 && strcmp(log_levels[level], args[3]))
7854 level--;
7855 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007856 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007857 exit(1);
7858 }
7859 }
7860
willy tarreau9fe663a2005-12-17 13:02:59 +01007861 sa = str2sa(args[1]);
7862 if (!sa->sin_port)
7863 sa->sin_port = htons(SYSLOG_PORT);
7864
7865 if (global.logfac1 == -1) {
7866 global.logsrv1 = *sa;
7867 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007868 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007869 }
7870 else if (global.logfac2 == -1) {
7871 global.logsrv2 = *sa;
7872 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007873 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007874 }
7875 else {
7876 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7877 return -1;
7878 }
7879
7880 }
7881 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007882 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007883 return -1;
7884 }
7885 return 0;
7886}
7887
7888
willy tarreaua41a8b42005-12-17 14:02:24 +01007889void init_default_instance() {
7890 memset(&defproxy, 0, sizeof(defproxy));
7891 defproxy.mode = PR_MODE_TCP;
7892 defproxy.state = PR_STNEW;
7893 defproxy.maxconn = cfg_maxpconn;
7894 defproxy.conn_retries = CONN_RETRIES;
7895 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7896}
7897
willy tarreau9fe663a2005-12-17 13:02:59 +01007898/*
7899 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7900 */
7901int cfg_parse_listen(char *file, int linenum, char **args) {
7902 static struct proxy *curproxy = NULL;
7903 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007904 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007905 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007906
7907 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007908 if (!*args[1]) {
7909 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7910 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007911 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007912 return -1;
7913 }
7914
7915 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007916 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007917 return -1;
7918 }
willy tarreaudfece232006-05-02 00:19:57 +02007919
willy tarreau9fe663a2005-12-17 13:02:59 +01007920 curproxy->next = proxy;
7921 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007922 LIST_INIT(&curproxy->pendconns);
7923
willy tarreau9fe663a2005-12-17 13:02:59 +01007924 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007925
7926 /* parse the listener address if any */
7927 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007928 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007929 if (!curproxy->listen)
7930 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007931 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007932 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007933
willy tarreau9fe663a2005-12-17 13:02:59 +01007934 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007935 curproxy->state = defproxy.state;
7936 curproxy->maxconn = defproxy.maxconn;
7937 curproxy->conn_retries = defproxy.conn_retries;
7938 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007939
7940 if (defproxy.check_req)
7941 curproxy->check_req = strdup(defproxy.check_req);
7942 curproxy->check_len = defproxy.check_len;
7943
7944 if (defproxy.cookie_name)
7945 curproxy->cookie_name = strdup(defproxy.cookie_name);
7946 curproxy->cookie_len = defproxy.cookie_len;
7947
7948 if (defproxy.capture_name)
7949 curproxy->capture_name = strdup(defproxy.capture_name);
7950 curproxy->capture_namelen = defproxy.capture_namelen;
7951 curproxy->capture_len = defproxy.capture_len;
7952
7953 if (defproxy.errmsg.msg400)
7954 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7955 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7956
7957 if (defproxy.errmsg.msg403)
7958 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7959 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7960
7961 if (defproxy.errmsg.msg408)
7962 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7963 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7964
7965 if (defproxy.errmsg.msg500)
7966 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7967 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7968
7969 if (defproxy.errmsg.msg502)
7970 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7971 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7972
7973 if (defproxy.errmsg.msg503)
7974 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7975 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7976
7977 if (defproxy.errmsg.msg504)
7978 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7979 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7980
willy tarreaua41a8b42005-12-17 14:02:24 +01007981 curproxy->clitimeout = defproxy.clitimeout;
7982 curproxy->contimeout = defproxy.contimeout;
7983 curproxy->srvtimeout = defproxy.srvtimeout;
7984 curproxy->mode = defproxy.mode;
7985 curproxy->logfac1 = defproxy.logfac1;
7986 curproxy->logsrv1 = defproxy.logsrv1;
7987 curproxy->loglev1 = defproxy.loglev1;
7988 curproxy->logfac2 = defproxy.logfac2;
7989 curproxy->logsrv2 = defproxy.logsrv2;
7990 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007991 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007992 curproxy->grace = defproxy.grace;
willy tarreau1f431b52006-05-21 14:46:15 +02007993 curproxy->uri_auth = defproxy.uri_auth;
willy tarreaua41a8b42005-12-17 14:02:24 +01007994 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007995 curproxy->mon_net = defproxy.mon_net;
7996 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007997 return 0;
7998 }
7999 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008000 /* some variables may have already been initialized earlier */
8001 if (defproxy.check_req) free(defproxy.check_req);
8002 if (defproxy.cookie_name) free(defproxy.cookie_name);
8003 if (defproxy.capture_name) free(defproxy.capture_name);
8004 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
8005 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
8006 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
8007 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
8008 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
8009 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
8010 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
willy tarreau1f431b52006-05-21 14:46:15 +02008011 /* we cannot free uri_auth because it might already be used */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008012 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01008013 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01008014 return 0;
8015 }
8016 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008017 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008018 return -1;
8019 }
8020
willy tarreaua41a8b42005-12-17 14:02:24 +01008021 if (!strcmp(args[0], "bind")) { /* new listen addresses */
8022 if (curproxy == &defproxy) {
8023 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8024 return -1;
8025 }
8026
8027 if (strchr(args[1], ':') == NULL) {
8028 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
8029 file, linenum, args[0]);
8030 return -1;
8031 }
8032 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01008033 if (!curproxy->listen)
8034 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008035 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008036 return 0;
8037 }
willy tarreaub1285d52005-12-18 01:20:14 +01008038 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
8039 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
8040 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
8041 file, linenum, args[0]);
8042 return -1;
8043 }
8044 /* flush useless bits */
8045 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
8046 return 0;
8047 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008048 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01008049 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
8050 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
8051 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
8052 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008053 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008054 return -1;
8055 }
8056 }
8057 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01008058 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008059 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008060 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
8061 curproxy->state = PR_STNEW;
8062 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008063 else if (!strcmp(args[0], "cookie")) { /* cookie name */
8064 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008065// if (curproxy == &defproxy) {
8066// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8067// return -1;
8068// }
willy tarreaua41a8b42005-12-17 14:02:24 +01008069
willy tarreau9fe663a2005-12-17 13:02:59 +01008070 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008071// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8072// file, linenum);
8073// return 0;
8074 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008075 }
8076
8077 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008078 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
8079 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008080 return -1;
8081 }
8082 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008083 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01008084
8085 cur_arg = 2;
8086 while (*(args[cur_arg])) {
8087 if (!strcmp(args[cur_arg], "rewrite")) {
8088 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01008089 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008090 else if (!strcmp(args[cur_arg], "indirect")) {
8091 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01008092 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008093 else if (!strcmp(args[cur_arg], "insert")) {
8094 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01008095 }
willy tarreau240afa62005-12-17 13:14:35 +01008096 else if (!strcmp(args[cur_arg], "nocache")) {
8097 curproxy->options |= PR_O_COOK_NOC;
8098 }
willy tarreaucd878942005-12-17 13:27:43 +01008099 else if (!strcmp(args[cur_arg], "postonly")) {
8100 curproxy->options |= PR_O_COOK_POST;
8101 }
willy tarreau0174f312005-12-18 01:02:42 +01008102 else if (!strcmp(args[cur_arg], "prefix")) {
8103 curproxy->options |= PR_O_COOK_PFX;
8104 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008105 else {
willy tarreau0174f312005-12-18 01:02:42 +01008106 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008107 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008108 return -1;
8109 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008110 cur_arg++;
8111 }
willy tarreau0174f312005-12-18 01:02:42 +01008112 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
8113 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
8114 file, linenum);
8115 return -1;
8116 }
8117
8118 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
8119 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008120 file, linenum);
8121 return -1;
8122 }
willy tarreau12350152005-12-18 01:03:27 +01008123 }/* end else if (!strcmp(args[0], "cookie")) */
8124 else if (!strcmp(args[0], "appsession")) { /* cookie name */
8125// if (curproxy == &defproxy) {
8126// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8127// return -1;
8128// }
8129
8130 if (curproxy->appsession_name != NULL) {
8131// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
8132// file, linenum);
8133// return 0;
8134 free(curproxy->appsession_name);
8135 }
8136
8137 if (*(args[5]) == 0) {
8138 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
8139 file, linenum, args[0]);
8140 return -1;
8141 }
8142 have_appsession = 1;
8143 curproxy->appsession_name = strdup(args[1]);
8144 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
8145 curproxy->appsession_len = atoi(args[3]);
8146 curproxy->appsession_timeout = atoi(args[5]);
8147 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
8148 if (rc) {
8149 Alert("Error Init Appsession Hashtable.\n");
8150 return -1;
8151 }
8152 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01008153 else if (!strcmp(args[0], "capture")) {
8154 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
8155 // if (curproxy == &defproxy) {
8156 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8157 // return -1;
8158 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008159
willy tarreau4302f492005-12-18 01:00:37 +01008160 if (curproxy->capture_name != NULL) {
8161 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8162 // file, linenum, args[0]);
8163 // return 0;
8164 free(curproxy->capture_name);
8165 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008166
willy tarreau4302f492005-12-18 01:00:37 +01008167 if (*(args[4]) == 0) {
8168 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
8169 file, linenum, args[0]);
8170 return -1;
8171 }
8172 curproxy->capture_name = strdup(args[2]);
8173 curproxy->capture_namelen = strlen(curproxy->capture_name);
8174 curproxy->capture_len = atol(args[4]);
8175 if (curproxy->capture_len >= CAPTURE_LEN) {
8176 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
8177 file, linenum, CAPTURE_LEN - 1);
8178 curproxy->capture_len = CAPTURE_LEN - 1;
8179 }
8180 curproxy->to_log |= LW_COOKIE;
8181 }
8182 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
8183 struct cap_hdr *hdr;
8184
8185 if (curproxy == &defproxy) {
8186 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8187 return -1;
8188 }
8189
8190 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8191 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8192 file, linenum, args[0], args[1]);
8193 return -1;
8194 }
8195
8196 hdr = calloc(sizeof(struct cap_hdr), 1);
8197 hdr->next = curproxy->req_cap;
8198 hdr->name = strdup(args[3]);
8199 hdr->namelen = strlen(args[3]);
8200 hdr->len = atol(args[5]);
8201 hdr->index = curproxy->nb_req_cap++;
8202 curproxy->req_cap = hdr;
8203 curproxy->to_log |= LW_REQHDR;
8204 }
8205 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
8206 struct cap_hdr *hdr;
8207
8208 if (curproxy == &defproxy) {
8209 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8210 return -1;
8211 }
8212
8213 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8214 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8215 file, linenum, args[0], args[1]);
8216 return -1;
8217 }
8218 hdr = calloc(sizeof(struct cap_hdr), 1);
8219 hdr->next = curproxy->rsp_cap;
8220 hdr->name = strdup(args[3]);
8221 hdr->namelen = strlen(args[3]);
8222 hdr->len = atol(args[5]);
8223 hdr->index = curproxy->nb_rsp_cap++;
8224 curproxy->rsp_cap = hdr;
8225 curproxy->to_log |= LW_RSPHDR;
8226 }
8227 else {
8228 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008229 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008230 return -1;
8231 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008232 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008233 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008234 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008235 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008236 return 0;
8237 }
8238 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008239 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8240 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008241 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008242 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008243 curproxy->contimeout = atol(args[1]);
8244 }
8245 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008246 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008247 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8248 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008249 return 0;
8250 }
8251 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008252 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8253 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008254 return -1;
8255 }
8256 curproxy->clitimeout = atol(args[1]);
8257 }
8258 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008259 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008260 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008261 return 0;
8262 }
8263 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008264 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8265 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008266 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008267 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008268 curproxy->srvtimeout = atol(args[1]);
8269 }
8270 else if (!strcmp(args[0], "retries")) { /* connection retries */
8271 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008272 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
8273 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008274 return -1;
8275 }
8276 curproxy->conn_retries = atol(args[1]);
8277 }
willy tarreau9e138862006-05-14 23:06:28 +02008278 else if (!strcmp(args[0], "stats")) {
willy tarreau1f431b52006-05-21 14:46:15 +02008279 if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
8280 curproxy->uri_auth = NULL; /* we must detach from the default config */
8281
willy tarreau9e138862006-05-14 23:06:28 +02008282 if (*(args[1]) == 0) {
willy tarreau1f431b52006-05-21 14:46:15 +02008283 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
willy tarreau9e138862006-05-14 23:06:28 +02008284 return -1;
8285 } else if (!strcmp(args[1], "uri")) {
8286 if (*(args[2]) == 0) {
8287 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
8288 return -1;
8289 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
8290 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8291 return -1;
8292 }
8293 } else if (!strcmp(args[1], "realm")) {
8294 if (*(args[2]) == 0) {
8295 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
8296 return -1;
8297 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
8298 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8299 return -1;
8300 }
8301 } else if (!strcmp(args[1], "auth")) {
8302 if (*(args[2]) == 0) {
8303 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
8304 return -1;
8305 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
8306 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8307 return -1;
8308 }
willy tarreau1f431b52006-05-21 14:46:15 +02008309 } else if (!strcmp(args[1], "scope")) {
8310 if (*(args[2]) == 0) {
8311 Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
8312 return -1;
8313 } else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
8314 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8315 return -1;
8316 }
willy tarreau9e138862006-05-14 23:06:28 +02008317 } else if (!strcmp(args[1], "enable")) {
8318 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
8319 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8320 return -1;
8321 }
8322 } else {
8323 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
8324 file, linenum, args[0]);
8325 return -1;
8326 }
8327 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008328 else if (!strcmp(args[0], "option")) {
8329 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008330 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008331 return -1;
8332 }
8333 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008334 /* enable reconnections to dispatch */
8335 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01008336#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008337 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008338 /* enable transparent proxy connections */
8339 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01008340#endif
8341 else if (!strcmp(args[1], "keepalive"))
8342 /* enable keep-alive */
8343 curproxy->options |= PR_O_KEEPALIVE;
8344 else if (!strcmp(args[1], "forwardfor"))
8345 /* insert x-forwarded-for field */
8346 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01008347 else if (!strcmp(args[1], "logasap"))
8348 /* log as soon as possible, without waiting for the session to complete */
8349 curproxy->options |= PR_O_LOGASAP;
willy tarreau03a92de2006-05-21 18:26:53 +02008350 else if (!strcmp(args[1], "abortonclose"))
8351 /* abort connection if client closes during queue or connect() */
8352 curproxy->options |= PR_O_ABRT_CLOSE;
willy tarreau25c4ea52005-12-18 00:49:49 +01008353 else if (!strcmp(args[1], "httpclose"))
8354 /* force connection: close in both directions in HTTP mode */
8355 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01008356 else if (!strcmp(args[1], "forceclose"))
8357 /* force connection: close in both directions in HTTP mode and enforce end of session */
8358 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01008359 else if (!strcmp(args[1], "checkcache"))
8360 /* require examination of cacheability of the 'set-cookie' field */
8361 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01008362 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01008363 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008364 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01008365 else if (!strcmp(args[1], "tcplog"))
8366 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008367 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01008368 else if (!strcmp(args[1], "dontlognull")) {
8369 /* don't log empty requests */
8370 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008371 }
willy tarreaub952e1d2005-12-18 01:31:20 +01008372 else if (!strcmp(args[1], "tcpka")) {
8373 /* enable TCP keep-alives on client and server sessions */
8374 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
8375 }
8376 else if (!strcmp(args[1], "clitcpka")) {
8377 /* enable TCP keep-alives on client sessions */
8378 curproxy->options |= PR_O_TCP_CLI_KA;
8379 }
8380 else if (!strcmp(args[1], "srvtcpka")) {
8381 /* enable TCP keep-alives on server sessions */
8382 curproxy->options |= PR_O_TCP_SRV_KA;
8383 }
Willy TARREAU3481c462006-03-01 22:37:57 +01008384 else if (!strcmp(args[1], "allbackups")) {
8385 /* Use all backup servers simultaneously */
8386 curproxy->options |= PR_O_USE_ALL_BK;
8387 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008388 else if (!strcmp(args[1], "httpchk")) {
8389 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008390 if (curproxy->check_req != NULL) {
8391 free(curproxy->check_req);
8392 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008393 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008394 if (!*args[2]) { /* no argument */
8395 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
8396 curproxy->check_len = strlen(DEF_CHECK_REQ);
8397 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01008398 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
8399 curproxy->check_req = (char *)malloc(reqlen);
8400 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8401 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008402 } else { /* more arguments : METHOD URI [HTTP_VER] */
8403 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
8404 if (*args[4])
8405 reqlen += strlen(args[4]);
8406 else
8407 reqlen += strlen("HTTP/1.0");
8408
8409 curproxy->check_req = (char *)malloc(reqlen);
8410 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8411 "%s %s %s\r\n\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
willy tarreau2f6ba652005-12-17 13:57:42 +01008412 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008413 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008414 else if (!strcmp(args[1], "persist")) {
8415 /* persist on using the server specified by the cookie, even when it's down */
8416 curproxy->options |= PR_O_PERSIST;
8417 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008418 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008419 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008420 return -1;
8421 }
8422 return 0;
8423 }
8424 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
8425 /* enable reconnections to dispatch */
8426 curproxy->options |= PR_O_REDISP;
8427 }
willy tarreaua1598082005-12-17 13:08:06 +01008428#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008429 else if (!strcmp(args[0], "transparent")) {
8430 /* enable transparent proxy connections */
8431 curproxy->options |= PR_O_TRANSP;
8432 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008433#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01008434 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
8435 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008436 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008437 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008438 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008439 curproxy->maxconn = atol(args[1]);
8440 }
8441 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
8442 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008443 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008444 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008445 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008446 curproxy->grace = atol(args[1]);
8447 }
8448 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01008449 if (curproxy == &defproxy) {
8450 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8451 return -1;
8452 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008453 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008454 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008455 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008456 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008457 curproxy->dispatch_addr = *str2sa(args[1]);
8458 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008459 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01008460 if (*(args[1])) {
8461 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008462 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01008463 }
willy tarreau1a3442d2006-03-24 21:03:20 +01008464 else if (!strcmp(args[1], "source")) {
8465 curproxy->options |= PR_O_BALANCE_SH;
8466 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008467 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01008468 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008469 return -1;
8470 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008471 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008472 else /* if no option is set, use round-robin by default */
8473 curproxy->options |= PR_O_BALANCE_RR;
8474 }
8475 else if (!strcmp(args[0], "server")) { /* server address */
8476 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008477 char *rport;
8478 char *raddr;
8479 short realport;
8480 int do_check;
8481
8482 if (curproxy == &defproxy) {
8483 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8484 return -1;
8485 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008486
willy tarreaua41a8b42005-12-17 14:02:24 +01008487 if (!*args[2]) {
8488 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008489 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008490 return -1;
8491 }
8492 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
8493 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8494 return -1;
8495 }
willy tarreau0174f312005-12-18 01:02:42 +01008496
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008497 /* the servers are linked backwards first */
8498 newsrv->next = curproxy->srv;
8499 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01008500 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008501
willy tarreau18a957c2006-04-12 19:26:23 +02008502 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01008503 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01008504 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01008505 newsrv->id = strdup(args[1]);
8506
8507 /* several ways to check the port component :
8508 * - IP => port=+0, relative
8509 * - IP: => port=+0, relative
8510 * - IP:N => port=N, absolute
8511 * - IP:+N => port=+N, relative
8512 * - IP:-N => port=-N, relative
8513 */
8514 raddr = strdup(args[2]);
8515 rport = strchr(raddr, ':');
8516 if (rport) {
8517 *rport++ = 0;
8518 realport = atol(rport);
8519 if (!isdigit((int)*rport))
8520 newsrv->state |= SRV_MAPPORTS;
8521 } else {
8522 realport = 0;
8523 newsrv->state |= SRV_MAPPORTS;
8524 }
8525
8526 newsrv->addr = *str2sa(raddr);
8527 newsrv->addr.sin_port = htons(realport);
8528 free(raddr);
8529
willy tarreau9fe663a2005-12-17 13:02:59 +01008530 newsrv->curfd = -1; /* no health-check in progress */
8531 newsrv->inter = DEF_CHKINTR;
8532 newsrv->rise = DEF_RISETIME;
8533 newsrv->fall = DEF_FALLTIME;
8534 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
8535 cur_arg = 3;
8536 while (*args[cur_arg]) {
8537 if (!strcmp(args[cur_arg], "cookie")) {
8538 newsrv->cookie = strdup(args[cur_arg + 1]);
8539 newsrv->cklen = strlen(args[cur_arg + 1]);
8540 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008541 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008542 else if (!strcmp(args[cur_arg], "rise")) {
8543 newsrv->rise = atol(args[cur_arg + 1]);
8544 newsrv->health = newsrv->rise;
8545 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008546 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008547 else if (!strcmp(args[cur_arg], "fall")) {
8548 newsrv->fall = atol(args[cur_arg + 1]);
8549 cur_arg += 2;
8550 }
8551 else if (!strcmp(args[cur_arg], "inter")) {
8552 newsrv->inter = atol(args[cur_arg + 1]);
8553 cur_arg += 2;
8554 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008555 else if (!strcmp(args[cur_arg], "port")) {
8556 newsrv->check_port = atol(args[cur_arg + 1]);
8557 cur_arg += 2;
8558 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008559 else if (!strcmp(args[cur_arg], "backup")) {
8560 newsrv->state |= SRV_BACKUP;
8561 cur_arg ++;
8562 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008563 else if (!strcmp(args[cur_arg], "weight")) {
8564 int w;
8565 w = atol(args[cur_arg + 1]);
8566 if (w < 1 || w > 256) {
8567 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
8568 file, linenum, newsrv->id, w);
8569 return -1;
8570 }
8571 newsrv->uweight = w - 1;
8572 cur_arg += 2;
8573 }
willy tarreauf76e6ca2006-05-21 21:09:55 +02008574 else if (!strcmp(args[cur_arg], "minconn")) {
8575 newsrv->minconn = atol(args[cur_arg + 1]);
8576 cur_arg += 2;
8577 }
willy tarreau18a957c2006-04-12 19:26:23 +02008578 else if (!strcmp(args[cur_arg], "maxconn")) {
8579 newsrv->maxconn = atol(args[cur_arg + 1]);
8580 cur_arg += 2;
8581 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008582 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01008583 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008584 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008585 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008586 }
willy tarreau0174f312005-12-18 01:02:42 +01008587 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
8588 if (!*args[cur_arg + 1]) {
8589 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
8590 file, linenum, "source");
8591 return -1;
8592 }
8593 newsrv->state |= SRV_BIND_SRC;
8594 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
8595 cur_arg += 2;
8596 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008597 else {
willy tarreauf76e6ca2006-05-21 21:09:55 +02008598 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', 'minconn', 'maxconn' and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01008599 file, linenum, newsrv->id);
8600 return -1;
8601 }
8602 }
8603
8604 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008605 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
8606 newsrv->check_port = realport; /* by default */
8607 if (!newsrv->check_port) {
8608 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008609 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008610 return -1;
8611 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008612 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008613 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008614
willy tarreau62084d42006-03-24 18:57:41 +01008615 if (newsrv->state & SRV_BACKUP)
8616 curproxy->srv_bck++;
8617 else
8618 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01008619 }
8620 else if (!strcmp(args[0], "log")) { /* syslog server address */
8621 struct sockaddr_in *sa;
8622 int facility;
8623
8624 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
8625 curproxy->logfac1 = global.logfac1;
8626 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01008627 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008628 curproxy->logfac2 = global.logfac2;
8629 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01008630 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01008631 }
8632 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01008633 int level;
8634
willy tarreau0f7af912005-12-17 12:21:26 +01008635 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
8636 if (!strcmp(log_facilities[facility], args[2]))
8637 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01008638
willy tarreau0f7af912005-12-17 12:21:26 +01008639 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008640 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01008641 exit(1);
8642 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008643
willy tarreau8337c6b2005-12-17 13:41:01 +01008644 level = 7; /* max syslog level = debug */
8645 if (*(args[3])) {
8646 while (level >= 0 && strcmp(log_levels[level], args[3]))
8647 level--;
8648 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008649 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008650 exit(1);
8651 }
8652 }
8653
willy tarreau0f7af912005-12-17 12:21:26 +01008654 sa = str2sa(args[1]);
8655 if (!sa->sin_port)
8656 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01008657
willy tarreau0f7af912005-12-17 12:21:26 +01008658 if (curproxy->logfac1 == -1) {
8659 curproxy->logsrv1 = *sa;
8660 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008661 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008662 }
8663 else if (curproxy->logfac2 == -1) {
8664 curproxy->logsrv2 = *sa;
8665 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008666 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008667 }
8668 else {
8669 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008670 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008671 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008672 }
8673 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008674 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008675 file, linenum);
8676 return -1;
8677 }
8678 }
willy tarreaua1598082005-12-17 13:08:06 +01008679 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01008680 if (!*args[1]) {
8681 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008682 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01008683 return -1;
8684 }
8685
8686 curproxy->source_addr = *str2sa(args[1]);
8687 curproxy->options |= PR_O_BIND_SRC;
8688 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008689 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
8690 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008691 if (curproxy == &defproxy) {
8692 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8693 return -1;
8694 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008695
8696 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008697 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8698 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008699 return -1;
8700 }
8701
8702 preg = calloc(1, sizeof(regex_t));
8703 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008704 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008705 return -1;
8706 }
8707
willy tarreauc1f47532005-12-18 01:08:26 +01008708 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8709 if (err) {
8710 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8711 file, linenum, *err);
8712 return -1;
8713 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008714 }
8715 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
8716 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008717 if (curproxy == &defproxy) {
8718 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8719 return -1;
8720 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008721
8722 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008723 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008724 return -1;
8725 }
8726
8727 preg = calloc(1, sizeof(regex_t));
8728 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008729 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008730 return -1;
8731 }
8732
8733 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8734 }
8735 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
8736 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008737 if (curproxy == &defproxy) {
8738 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8739 return -1;
8740 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008741
8742 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008743 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008744 return -1;
8745 }
8746
8747 preg = calloc(1, sizeof(regex_t));
8748 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008749 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008750 return -1;
8751 }
8752
8753 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8754 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008755 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
8756 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008757 if (curproxy == &defproxy) {
8758 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8759 return -1;
8760 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008761
8762 if (*(args[1]) == 0) {
8763 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8764 return -1;
8765 }
8766
8767 preg = calloc(1, sizeof(regex_t));
8768 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8769 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8770 return -1;
8771 }
8772
8773 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8774 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008775 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
8776 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008777 if (curproxy == &defproxy) {
8778 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8779 return -1;
8780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008781
8782 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008783 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008784 return -1;
8785 }
8786
8787 preg = calloc(1, sizeof(regex_t));
8788 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008789 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008790 return -1;
8791 }
8792
8793 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8794 }
8795 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8796 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008797 if (curproxy == &defproxy) {
8798 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8799 return -1;
8800 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008801
8802 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008803 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8804 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008805 return -1;
8806 }
8807
8808 preg = calloc(1, sizeof(regex_t));
8809 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008810 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008811 return -1;
8812 }
8813
willy tarreauc1f47532005-12-18 01:08:26 +01008814 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8815 if (err) {
8816 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8817 file, linenum, *err);
8818 return -1;
8819 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008820 }
8821 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8822 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008823 if (curproxy == &defproxy) {
8824 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8825 return -1;
8826 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008827
8828 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008829 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008830 return -1;
8831 }
8832
8833 preg = calloc(1, sizeof(regex_t));
8834 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008835 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008836 return -1;
8837 }
8838
8839 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8840 }
8841 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8842 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008843 if (curproxy == &defproxy) {
8844 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8845 return -1;
8846 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008847
8848 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008849 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008850 return -1;
8851 }
8852
8853 preg = calloc(1, sizeof(regex_t));
8854 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008855 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008856 return -1;
8857 }
8858
8859 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8860 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008861 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8862 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008863 if (curproxy == &defproxy) {
8864 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8865 return -1;
8866 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008867
8868 if (*(args[1]) == 0) {
8869 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8870 return -1;
8871 }
8872
8873 preg = calloc(1, sizeof(regex_t));
8874 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8875 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8876 return -1;
8877 }
8878
8879 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8880 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008881 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8882 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008883 if (curproxy == &defproxy) {
8884 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8885 return -1;
8886 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008887
8888 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008889 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008890 return -1;
8891 }
8892
8893 preg = calloc(1, sizeof(regex_t));
8894 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008895 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008896 return -1;
8897 }
8898
8899 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8900 }
8901 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008902 if (curproxy == &defproxy) {
8903 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8904 return -1;
8905 }
8906
willy tarreau9fe663a2005-12-17 13:02:59 +01008907 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008908 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008909 return 0;
8910 }
8911
8912 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008913 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008914 return -1;
8915 }
8916
willy tarreau4302f492005-12-18 01:00:37 +01008917 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8918 }
8919 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8920 regex_t *preg;
8921
8922 if (*(args[1]) == 0 || *(args[2]) == 0) {
8923 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8924 file, linenum, args[0]);
8925 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008926 }
willy tarreau4302f492005-12-18 01:00:37 +01008927
8928 preg = calloc(1, sizeof(regex_t));
8929 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8930 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8931 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008932 }
willy tarreau4302f492005-12-18 01:00:37 +01008933
willy tarreauc1f47532005-12-18 01:08:26 +01008934 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8935 if (err) {
8936 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8937 file, linenum, *err);
8938 return -1;
8939 }
willy tarreau4302f492005-12-18 01:00:37 +01008940 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008941 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8942 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008943 if (curproxy == &defproxy) {
8944 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8945 return -1;
8946 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008947
8948 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008949 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008950 return -1;
8951 }
willy tarreaue39cd132005-12-17 13:00:18 +01008952
willy tarreau9fe663a2005-12-17 13:02:59 +01008953 preg = calloc(1, sizeof(regex_t));
8954 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008955 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008956 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008957 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008958
willy tarreauc1f47532005-12-18 01:08:26 +01008959 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8960 if (err) {
8961 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8962 file, linenum, *err);
8963 return -1;
8964 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008965 }
willy tarreau982249e2005-12-18 00:57:06 +01008966 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8967 regex_t *preg;
8968 if (curproxy == &defproxy) {
8969 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8970 return -1;
8971 }
8972
8973 if (*(args[1]) == 0) {
8974 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8975 return -1;
8976 }
8977
8978 preg = calloc(1, sizeof(regex_t));
8979 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8980 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8981 return -1;
8982 }
8983
willy tarreauc1f47532005-12-18 01:08:26 +01008984 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8985 if (err) {
8986 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8987 file, linenum, *err);
8988 return -1;
8989 }
willy tarreau982249e2005-12-18 00:57:06 +01008990 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008991 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008992 regex_t *preg;
8993 if (curproxy == &defproxy) {
8994 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8995 return -1;
8996 }
willy tarreaue39cd132005-12-17 13:00:18 +01008997
willy tarreaua41a8b42005-12-17 14:02:24 +01008998 if (*(args[1]) == 0 || *(args[2]) == 0) {
8999 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
9000 file, linenum, args[0]);
9001 return -1;
9002 }
willy tarreaue39cd132005-12-17 13:00:18 +01009003
willy tarreaua41a8b42005-12-17 14:02:24 +01009004 preg = calloc(1, sizeof(regex_t));
9005 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
9006 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
9007 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01009008 }
willy tarreaua41a8b42005-12-17 14:02:24 +01009009
willy tarreauc1f47532005-12-18 01:08:26 +01009010 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
9011 if (err) {
9012 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9013 file, linenum, *err);
9014 return -1;
9015 }
willy tarreaua41a8b42005-12-17 14:02:24 +01009016 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009017 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
9018 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01009019 if (curproxy == &defproxy) {
9020 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9021 return -1;
9022 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009023
9024 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009025 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009026 return -1;
9027 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009028
willy tarreau9fe663a2005-12-17 13:02:59 +01009029 preg = calloc(1, sizeof(regex_t));
9030 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009031 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009032 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009033 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009034
willy tarreauc1f47532005-12-18 01:08:26 +01009035 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
9036 if (err) {
9037 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9038 file, linenum, *err);
9039 return -1;
9040 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009041 }
willy tarreau982249e2005-12-18 00:57:06 +01009042 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
9043 regex_t *preg;
9044 if (curproxy == &defproxy) {
9045 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9046 return -1;
9047 }
9048
9049 if (*(args[1]) == 0) {
9050 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
9051 return -1;
9052 }
9053
9054 preg = calloc(1, sizeof(regex_t));
9055 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
9056 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
9057 return -1;
9058 }
9059
willy tarreauc1f47532005-12-18 01:08:26 +01009060 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
9061 if (err) {
9062 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
9063 file, linenum, *err);
9064 return -1;
9065 }
willy tarreau982249e2005-12-18 00:57:06 +01009066 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009067 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01009068 if (curproxy == &defproxy) {
9069 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9070 return -1;
9071 }
9072
willy tarreau9fe663a2005-12-17 13:02:59 +01009073 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009074 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009075 return 0;
9076 }
9077
9078 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01009079 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009080 return -1;
9081 }
9082
9083 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
9084 }
willy tarreauc1f47532005-12-18 01:08:26 +01009085 else if (!strcmp(args[0], "errorloc") ||
9086 !strcmp(args[0], "errorloc302") ||
9087 !strcmp(args[0], "errorloc303")) { /* error location */
9088 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009089 char *err;
9090
willy tarreaueedaa9f2005-12-17 14:08:03 +01009091 // if (curproxy == &defproxy) {
9092 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
9093 // return -1;
9094 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01009095
willy tarreau8337c6b2005-12-17 13:41:01 +01009096 if (*(args[2]) == 0) {
9097 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
9098 return -1;
9099 }
9100
9101 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01009102 if (!strcmp(args[0], "errorloc303")) {
9103 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
9104 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
9105 } else {
9106 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
9107 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
9108 }
willy tarreau8337c6b2005-12-17 13:41:01 +01009109
9110 if (errnum == 400) {
9111 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009112 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009113 free(curproxy->errmsg.msg400);
9114 }
9115 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009116 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009117 }
9118 else if (errnum == 403) {
9119 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009120 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009121 free(curproxy->errmsg.msg403);
9122 }
9123 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009124 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009125 }
9126 else if (errnum == 408) {
9127 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009128 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009129 free(curproxy->errmsg.msg408);
9130 }
9131 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009132 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009133 }
9134 else if (errnum == 500) {
9135 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009136 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009137 free(curproxy->errmsg.msg500);
9138 }
9139 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009140 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009141 }
9142 else if (errnum == 502) {
9143 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009144 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009145 free(curproxy->errmsg.msg502);
9146 }
9147 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009148 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009149 }
9150 else if (errnum == 503) {
9151 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009152 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009153 free(curproxy->errmsg.msg503);
9154 }
9155 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009156 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009157 }
9158 else if (errnum == 504) {
9159 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01009160 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01009161 free(curproxy->errmsg.msg504);
9162 }
9163 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01009164 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01009165 }
9166 else {
9167 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
9168 free(err);
9169 }
9170 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009171 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01009172 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01009173 return -1;
9174 }
9175 return 0;
9176}
willy tarreaue39cd132005-12-17 13:00:18 +01009177
willy tarreau5cbea6f2005-12-17 12:48:26 +01009178
willy tarreau9fe663a2005-12-17 13:02:59 +01009179/*
9180 * This function reads and parses the configuration file given in the argument.
9181 * returns 0 if OK, -1 if error.
9182 */
9183int readcfgfile(char *file) {
9184 char thisline[256];
9185 char *line;
9186 FILE *f;
9187 int linenum = 0;
9188 char *end;
9189 char *args[MAX_LINE_ARGS];
9190 int arg;
9191 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01009192 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01009193 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01009194
willy tarreau9fe663a2005-12-17 13:02:59 +01009195 struct proxy *curproxy = NULL;
9196 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01009197
willy tarreau9fe663a2005-12-17 13:02:59 +01009198 if ((f=fopen(file,"r")) == NULL)
9199 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01009200
willy tarreaueedaa9f2005-12-17 14:08:03 +01009201 init_default_instance();
9202
willy tarreau9fe663a2005-12-17 13:02:59 +01009203 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
9204 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009205
willy tarreau9fe663a2005-12-17 13:02:59 +01009206 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01009207
willy tarreau9fe663a2005-12-17 13:02:59 +01009208 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01009209 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01009210 line++;
9211
9212 arg = 0;
9213 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01009214
willy tarreau9fe663a2005-12-17 13:02:59 +01009215 while (*line && arg < MAX_LINE_ARGS) {
9216 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
9217 * C equivalent value. Other combinations left unchanged (eg: \1).
9218 */
9219 if (*line == '\\') {
9220 int skip = 0;
9221 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
9222 *line = line[1];
9223 skip = 1;
9224 }
9225 else if (line[1] == 'r') {
9226 *line = '\r';
9227 skip = 1;
9228 }
9229 else if (line[1] == 'n') {
9230 *line = '\n';
9231 skip = 1;
9232 }
9233 else if (line[1] == 't') {
9234 *line = '\t';
9235 skip = 1;
9236 }
willy tarreauc1f47532005-12-18 01:08:26 +01009237 else if (line[1] == 'x') {
9238 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
9239 unsigned char hex1, hex2;
9240 hex1 = toupper(line[2]) - '0';
9241 hex2 = toupper(line[3]) - '0';
9242 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
9243 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
9244 *line = (hex1<<4) + hex2;
9245 skip = 3;
9246 }
9247 else {
9248 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
9249 return -1;
9250 }
9251 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009252 if (skip) {
9253 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
9254 end -= skip;
9255 }
9256 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009257 }
willy tarreaua1598082005-12-17 13:08:06 +01009258 else if (*line == '#' || *line == '\n' || *line == '\r') {
9259 /* end of string, end of loop */
9260 *line = 0;
9261 break;
9262 }
willy tarreauc29948c2005-12-17 13:10:27 +01009263 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009264 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01009265 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01009266 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01009267 line++;
9268 args[++arg] = line;
9269 }
9270 else {
9271 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009272 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009273 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009274
willy tarreau9fe663a2005-12-17 13:02:59 +01009275 /* empty line */
9276 if (!**args)
9277 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01009278
willy tarreau9fe663a2005-12-17 13:02:59 +01009279 /* zero out remaining args */
9280 while (++arg < MAX_LINE_ARGS) {
9281 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009282 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009283
willy tarreaua41a8b42005-12-17 14:02:24 +01009284 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01009285 confsect = CFG_LISTEN;
9286 else if (!strcmp(args[0], "global")) /* global config */
9287 confsect = CFG_GLOBAL;
9288 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01009289
willy tarreau9fe663a2005-12-17 13:02:59 +01009290 switch (confsect) {
9291 case CFG_LISTEN:
9292 if (cfg_parse_listen(file, linenum, args) < 0)
9293 return -1;
9294 break;
9295 case CFG_GLOBAL:
9296 if (cfg_parse_global(file, linenum, args) < 0)
9297 return -1;
9298 break;
9299 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01009300 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009301 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01009302 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009303
9304
willy tarreau0f7af912005-12-17 12:21:26 +01009305 }
9306 fclose(f);
9307
9308 /*
9309 * Now, check for the integrity of all that we have collected.
9310 */
9311
Willy TARREAU3759f982006-03-01 22:44:17 +01009312 /* will be needed further to delay some tasks */
9313 tv_now(&now);
9314
willy tarreau0f7af912005-12-17 12:21:26 +01009315 if ((curproxy = proxy) == NULL) {
9316 Alert("parsing %s : no <listen> line. Nothing to do !\n",
9317 file);
9318 return -1;
9319 }
9320
9321 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01009322 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01009323 curproxy = curproxy->next;
9324 continue;
9325 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009326
9327 if (curproxy->listen == NULL) {
9328 Alert("parsing %s : listener %s has no listen address. Please either specify a valid address on the <listen> line, or use the <bind> keyword.\n", file, curproxy->id);
9329 cfgerr++;
9330 }
9331 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01009332 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01009333 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009334 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
9335 file, curproxy->id);
9336 cfgerr++;
9337 }
9338 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
9339 if (curproxy->options & PR_O_TRANSP) {
9340 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
9341 file, curproxy->id);
9342 cfgerr++;
9343 }
willy tarreau38d79062006-05-21 14:47:13 +02009344#ifdef WE_DONT_SUPPORT_SERVERLESS_LISTENERS
willy tarreau5cbea6f2005-12-17 12:48:26 +01009345 else if (curproxy->srv == NULL) {
9346 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
9347 file, curproxy->id);
9348 cfgerr++;
9349 }
willy tarreau38d79062006-05-21 14:47:13 +02009350#endif
willy tarreaua1598082005-12-17 13:08:06 +01009351 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009352 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
9353 file, curproxy->id);
9354 }
9355 }
9356 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01009357 if (curproxy->cookie_name != NULL) {
9358 Warning("parsing %s : cookie will be ignored for listener %s.\n",
9359 file, curproxy->id);
9360 }
9361 if ((newsrv = curproxy->srv) != NULL) {
9362 Warning("parsing %s : servers will be ignored for listener %s.\n",
9363 file, curproxy->id);
9364 }
willy tarreaue39cd132005-12-17 13:00:18 +01009365 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009366 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
9367 file, curproxy->id);
9368 }
willy tarreaue39cd132005-12-17 13:00:18 +01009369 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009370 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
9371 file, curproxy->id);
9372 }
9373 }
9374 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
9375 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
9376 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
9377 file, curproxy->id);
9378 cfgerr++;
9379 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009380 }
willy tarreaue3f023f2006-04-08 21:52:24 +02009381
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009382 /* first, we will invert the servers list order */
9383 newsrv = NULL;
9384 while (curproxy->srv) {
9385 struct server *next;
9386
9387 next = curproxy->srv->next;
9388 curproxy->srv->next = newsrv;
9389 newsrv = curproxy->srv;
9390 if (!next)
9391 break;
9392 curproxy->srv = next;
9393 }
9394
9395 /* now, newsrv == curproxy->srv */
9396 if (newsrv) {
9397 struct server *srv;
9398 int pgcd;
9399 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02009400
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009401 /* We will factor the weights to reduce the table,
9402 * using Euclide's largest common divisor algorithm
9403 */
9404 pgcd = newsrv->uweight + 1;
9405 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
9406 int t, w;
9407
9408 w = srv->uweight + 1;
9409 while (w) {
9410 t = pgcd % w;
9411 pgcd = w;
9412 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02009413 }
willy tarreau0f7af912005-12-17 12:21:26 +01009414 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009415
9416 act = bck = 0;
9417 for (srv = newsrv; srv; srv = srv->next) {
9418 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
9419 if (srv->state & SRV_BACKUP)
9420 bck += srv->eweight + 1;
9421 else
9422 act += srv->eweight + 1;
9423 }
9424
9425 /* this is the largest map we will ever need for this servers list */
9426 if (act < bck)
9427 act = bck;
9428
9429 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
9430 /* recounts servers and their weights */
9431 recount_servers(curproxy);
9432 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01009433 }
willy tarreau25c4ea52005-12-18 00:49:49 +01009434
9435 if (curproxy->options & PR_O_LOGASAP)
9436 curproxy->to_log &= ~LW_BYTES;
9437
willy tarreau8337c6b2005-12-17 13:41:01 +01009438 if (curproxy->errmsg.msg400 == NULL) {
9439 curproxy->errmsg.msg400 = (char *)HTTP_400;
9440 curproxy->errmsg.len400 = strlen(HTTP_400);
9441 }
9442 if (curproxy->errmsg.msg403 == NULL) {
9443 curproxy->errmsg.msg403 = (char *)HTTP_403;
9444 curproxy->errmsg.len403 = strlen(HTTP_403);
9445 }
9446 if (curproxy->errmsg.msg408 == NULL) {
9447 curproxy->errmsg.msg408 = (char *)HTTP_408;
9448 curproxy->errmsg.len408 = strlen(HTTP_408);
9449 }
9450 if (curproxy->errmsg.msg500 == NULL) {
9451 curproxy->errmsg.msg500 = (char *)HTTP_500;
9452 curproxy->errmsg.len500 = strlen(HTTP_500);
9453 }
9454 if (curproxy->errmsg.msg502 == NULL) {
9455 curproxy->errmsg.msg502 = (char *)HTTP_502;
9456 curproxy->errmsg.len502 = strlen(HTTP_502);
9457 }
9458 if (curproxy->errmsg.msg503 == NULL) {
9459 curproxy->errmsg.msg503 = (char *)HTTP_503;
9460 curproxy->errmsg.len503 = strlen(HTTP_503);
9461 }
9462 if (curproxy->errmsg.msg504 == NULL) {
9463 curproxy->errmsg.msg504 = (char *)HTTP_504;
9464 curproxy->errmsg.len504 = strlen(HTTP_504);
9465 }
Willy TARREAU3759f982006-03-01 22:44:17 +01009466
willy tarreau59a6cc22006-05-12 01:29:08 +02009467 /*
9468 * If this server supports a maxconn parameter, it needs a dedicated
9469 * tasks to fill the emptied slots when a connection leaves.
9470 */
9471 newsrv = curproxy->srv;
9472 while (newsrv != NULL) {
willy tarreau2b598cc2006-05-21 22:07:31 +02009473 if (newsrv->minconn >= newsrv->maxconn) {
9474 /* Only 'minconn' was specified, or it was higher than or equal
9475 * to 'maxconn'. Let's turn this into maxconn and clean it, as
9476 * this will avoid further useless expensive computations.
9477 */
willy tarreauf76e6ca2006-05-21 21:09:55 +02009478 newsrv->maxconn = newsrv->minconn;
9479 newsrv->minconn = 0;
9480 }
9481
willy tarreau59a6cc22006-05-12 01:29:08 +02009482 if (newsrv->maxconn > 0) {
9483 struct task *t;
9484
9485 if ((t = pool_alloc(task)) == NULL) {
9486 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9487 return -1;
9488 }
9489
9490 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
9491 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
9492 t->state = TASK_IDLE;
9493 t->process = process_srv_queue;
9494 t->context = newsrv;
9495 newsrv->queue_mgt = t;
9496
9497 /* never run it unless specifically woken up */
9498 tv_eternity(&t->expire);
9499 task_queue(t);
9500 }
9501 newsrv = newsrv->next;
9502 }
9503
Willy TARREAU3759f982006-03-01 22:44:17 +01009504 /* now we'll start this proxy's health checks if any */
9505 /* 1- count the checkers to run simultaneously */
9506 nbchk = 0;
9507 mininter = 0;
9508 newsrv = curproxy->srv;
9509 while (newsrv != NULL) {
9510 if (newsrv->state & SRV_CHECKED) {
9511 if (!mininter || mininter > newsrv->inter)
9512 mininter = newsrv->inter;
9513 nbchk++;
9514 }
9515 newsrv = newsrv->next;
9516 }
9517
9518 /* 2- start them as far as possible from each others while respecting
9519 * their own intervals. For this, we will start them after their own
9520 * interval added to the min interval divided by the number of servers,
9521 * weighted by the server's position in the list.
9522 */
9523 if (nbchk > 0) {
9524 struct task *t;
9525 int srvpos;
9526
9527 newsrv = curproxy->srv;
9528 srvpos = 0;
9529 while (newsrv != NULL) {
9530 /* should this server be checked ? */
9531 if (newsrv->state & SRV_CHECKED) {
9532 if ((t = pool_alloc(task)) == NULL) {
9533 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9534 return -1;
9535 }
9536
9537 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02009538 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01009539 t->state = TASK_IDLE;
9540 t->process = process_chk;
9541 t->context = newsrv;
9542
9543 /* check this every ms */
9544 tv_delayfrom(&t->expire, &now,
9545 newsrv->inter + mininter * srvpos / nbchk);
9546 task_queue(t);
9547 //task_wakeup(&rq, t);
9548 srvpos++;
9549 }
9550 newsrv = newsrv->next;
9551 }
9552 }
9553
willy tarreau0f7af912005-12-17 12:21:26 +01009554 curproxy = curproxy->next;
9555 }
9556 if (cfgerr > 0) {
9557 Alert("Errors found in configuration file, aborting.\n");
9558 return -1;
9559 }
9560 else
9561 return 0;
9562}
9563
9564
9565/*
9566 * This function initializes all the necessary variables. It only returns
9567 * if everything is OK. If something fails, it exits.
9568 */
9569void init(int argc, char **argv) {
9570 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01009571 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01009572 char *old_argv = *argv;
9573 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009574 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009575
9576 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01009577 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01009578 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01009579 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01009580 exit(1);
9581 }
9582
willy tarreau746e26b2006-03-25 11:14:35 +01009583#ifdef HAPROXY_MEMMAX
9584 global.rlimit_memmax = HAPROXY_MEMMAX;
9585#endif
9586
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009587 /* initialize the libc's localtime structures once for all so that we
9588 * won't be missing memory if we want to send alerts under OOM conditions.
9589 */
9590 tv_now(&now);
9591 localtime(&now.tv_sec);
willy tarreaue0331262006-05-15 03:02:46 +02009592 start_date = now;
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009593
willy tarreau4302f492005-12-18 01:00:37 +01009594 /* initialize the log header encoding map : '{|}"#' should be encoded with
9595 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
9596 * URL encoding only requires '"', '#' to be encoded as well as non-
9597 * printable characters above.
9598 */
9599 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
9600 memset(url_encode_map, 0, sizeof(url_encode_map));
9601 for (i = 0; i < 32; i++) {
9602 FD_SET(i, hdr_encode_map);
9603 FD_SET(i, url_encode_map);
9604 }
9605 for (i = 127; i < 256; i++) {
9606 FD_SET(i, hdr_encode_map);
9607 FD_SET(i, url_encode_map);
9608 }
9609
9610 tmp = "\"#{|}";
9611 while (*tmp) {
9612 FD_SET(*tmp, hdr_encode_map);
9613 tmp++;
9614 }
9615
9616 tmp = "\"#";
9617 while (*tmp) {
9618 FD_SET(*tmp, url_encode_map);
9619 tmp++;
9620 }
9621
willy tarreau64a3cc32005-12-18 01:13:11 +01009622 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
9623#if defined(ENABLE_POLL)
9624 cfg_polling_mechanism |= POLL_USE_POLL;
9625#endif
9626#if defined(ENABLE_EPOLL)
9627 cfg_polling_mechanism |= POLL_USE_EPOLL;
9628#endif
9629
willy tarreau0f7af912005-12-17 12:21:26 +01009630 pid = getpid();
9631 progname = *argv;
9632 while ((tmp = strchr(progname, '/')) != NULL)
9633 progname = tmp + 1;
9634
9635 argc--; argv++;
9636 while (argc > 0) {
9637 char *flag;
9638
9639 if (**argv == '-') {
9640 flag = *argv+1;
9641
9642 /* 1 arg */
9643 if (*flag == 'v') {
9644 display_version();
9645 exit(0);
9646 }
willy tarreau1c2ad212005-12-18 01:11:29 +01009647#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009648 else if (*flag == 'd' && flag[1] == 'e')
9649 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009650#endif
9651#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009652 else if (*flag == 'd' && flag[1] == 'p')
9653 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009654#endif
willy tarreau982249e2005-12-18 00:57:06 +01009655 else if (*flag == 'V')
9656 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009657 else if (*flag == 'd' && flag[1] == 'b')
9658 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01009659 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01009660 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01009661 else if (*flag == 'c')
9662 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01009663 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01009664 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009665 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01009666 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01009667 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
9668 /* list of pids to finish ('f') or terminate ('t') */
9669
9670 if (flag[1] == 'f')
9671 oldpids_sig = SIGUSR1; /* finish then exit */
9672 else
9673 oldpids_sig = SIGTERM; /* terminate immediately */
9674 argv++; argc--;
9675
9676 if (argc > 0) {
9677 oldpids = calloc(argc, sizeof(int));
9678 while (argc > 0) {
9679 oldpids[nb_oldpids] = atol(*argv);
9680 if (oldpids[nb_oldpids] <= 0)
9681 usage(old_argv);
9682 argc--; argv++;
9683 nb_oldpids++;
9684 }
9685 }
9686 }
willy tarreau2c513732006-04-15 19:25:16 +02009687#if STATTIME > 0
9688 else if (*flag == 's')
9689 arg_mode |= MODE_STATS;
9690 else if (*flag == 'l')
9691 arg_mode |= MODE_LOG;
9692#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009693 else { /* >=2 args */
9694 argv++; argc--;
9695 if (argc == 0)
9696 usage(old_argv);
9697
9698 switch (*flag) {
9699 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01009700 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01009701 case 'N' : cfg_maxpconn = atol(*argv); break;
9702 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009703 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01009704 default: usage(old_argv);
9705 }
9706 }
9707 }
9708 else
9709 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01009710 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01009711 }
9712
willy tarreaud0fb4652005-12-18 01:32:04 +01009713 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009714 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
9715 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01009716
willy tarreau0f7af912005-12-17 12:21:26 +01009717 if (!cfg_cfgfile)
9718 usage(old_argv);
9719
9720 gethostname(hostname, MAX_HOSTNAME_LEN);
9721
willy tarreau12350152005-12-18 01:03:27 +01009722 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01009723 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01009724 if (readcfgfile(cfg_cfgfile) < 0) {
9725 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
9726 exit(1);
9727 }
willy tarreau12350152005-12-18 01:03:27 +01009728 if (have_appsession)
9729 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01009730
willy tarreau982249e2005-12-18 00:57:06 +01009731 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01009732 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
9733 exit(0);
9734 }
9735
willy tarreau9fe663a2005-12-17 13:02:59 +01009736 if (cfg_maxconn > 0)
9737 global.maxconn = cfg_maxconn;
9738
willy tarreaufe2c5c12005-12-17 14:14:34 +01009739 if (cfg_pidfile) {
9740 if (global.pidfile)
9741 free(global.pidfile);
9742 global.pidfile = strdup(cfg_pidfile);
9743 }
9744
willy tarreau9fe663a2005-12-17 13:02:59 +01009745 if (global.maxconn == 0)
9746 global.maxconn = DEFAULT_MAXCONN;
9747
Willy TARREAU203b0b62006-03-12 18:00:28 +01009748 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01009749
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009750 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009751 /* command line debug mode inhibits configuration mode */
9752 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9753 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009754 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
9755 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01009756
9757 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
9758 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
9759 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9760 }
9761
9762 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009763 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
9764 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01009765 global.nbproc = 1;
9766 }
9767
9768 if (global.nbproc < 1)
9769 global.nbproc = 1;
9770
willy tarreau0f7af912005-12-17 12:21:26 +01009771 StaticReadEvent = (fd_set *)calloc(1,
9772 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009773 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009774 StaticWriteEvent = (fd_set *)calloc(1,
9775 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009776 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009777
9778 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01009779 sizeof(struct fdtab) * (global.maxsock));
9780 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01009781 fdtab[i].state = FD_STCLOSE;
9782 }
9783}
9784
9785/*
willy tarreau41310e72006-03-25 18:17:56 +01009786 * this function starts all the proxies. Its return value is composed from
9787 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
9788 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01009789 */
willy tarreau41310e72006-03-25 18:17:56 +01009790int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01009791 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01009792 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01009793 int err = ERR_NONE;
9794 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01009795
9796 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009797 if (curproxy->state != PR_STNEW)
9798 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009799
willy tarreau41310e72006-03-25 18:17:56 +01009800 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009801 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009802 if (listener->fd != -1)
9803 continue; /* already initialized */
9804
9805 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9806 if (verbose)
9807 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9808 curproxy->id);
9809 err |= ERR_RETRYABLE;
9810 pxerr |= 1;
9811 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009812 }
willy tarreau0f7af912005-12-17 12:21:26 +01009813
willy tarreaua41a8b42005-12-17 14:02:24 +01009814 if (fd >= global.maxsock) {
9815 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9816 curproxy->id);
9817 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009818 err |= ERR_FATAL;
9819 pxerr |= 1;
9820 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009821 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009822
willy tarreaua41a8b42005-12-17 14:02:24 +01009823 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9824 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9825 (char *) &one, sizeof(one)) == -1)) {
9826 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9827 curproxy->id);
9828 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009829 err |= ERR_FATAL;
9830 pxerr |= 1;
9831 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009832 }
willy tarreau0f7af912005-12-17 12:21:26 +01009833
willy tarreaua41a8b42005-12-17 14:02:24 +01009834 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9835 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9836 curproxy->id);
9837 }
willy tarreau0f7af912005-12-17 12:21:26 +01009838
willy tarreaufac1a862006-05-21 10:20:28 +02009839#ifdef SO_REUSEPORT
9840 /* OpenBSD supports this. As it's present in old libc versions of Linux,
9841 * it might return an error that we will silently ignore.
9842 */
9843 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
9844#endif
willy tarreaua41a8b42005-12-17 14:02:24 +01009845 if (bind(fd,
9846 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009847 listener->addr.ss_family == AF_INET6 ?
9848 sizeof(struct sockaddr_in6) :
9849 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009850 if (verbose)
9851 Alert("cannot bind socket for proxy %s. Aborting.\n",
9852 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009853 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009854 err |= ERR_RETRYABLE;
9855 pxerr |= 1;
9856 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009857 }
willy tarreau0f7af912005-12-17 12:21:26 +01009858
willy tarreaua41a8b42005-12-17 14:02:24 +01009859 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009860 if (verbose)
9861 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9862 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009863 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009864 err |= ERR_RETRYABLE;
9865 pxerr |= 1;
9866 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009867 }
willy tarreau0f7af912005-12-17 12:21:26 +01009868
willy tarreau41310e72006-03-25 18:17:56 +01009869 /* the socket is ready */
9870 listener->fd = fd;
9871
willy tarreaua41a8b42005-12-17 14:02:24 +01009872 /* the function for the accept() event */
9873 fdtab[fd].read = &event_accept;
9874 fdtab[fd].write = NULL; /* never called */
9875 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009876 fdtab[fd].state = FD_STLISTEN;
9877 FD_SET(fd, StaticReadEvent);
9878 fd_insert(fd);
9879 listeners++;
9880 }
willy tarreau41310e72006-03-25 18:17:56 +01009881
9882 if (!pxerr) {
9883 curproxy->state = PR_STRUN;
9884 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9885 }
willy tarreau0f7af912005-12-17 12:21:26 +01009886 }
willy tarreau41310e72006-03-25 18:17:56 +01009887
9888 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009889}
9890
willy tarreaub952e1d2005-12-18 01:31:20 +01009891int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009892
9893 appsess *temp1,*temp2;
9894 temp1 = (appsess *)key1;
9895 temp2 = (appsess *)key2;
9896
9897 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9898 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9899
9900 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9901}/* end match_str */
9902
willy tarreaub952e1d2005-12-18 01:31:20 +01009903void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009904 appsess *temp1;
9905
9906 //printf("destroy called\n");
9907 temp1 = (appsess *)data;
9908
9909 if (temp1->sessid)
9910 pool_free_to(apools.sessid, temp1->sessid);
9911
9912 if (temp1->serverid)
9913 pool_free_to(apools.serverid, temp1->serverid);
9914
9915 pool_free(appsess, temp1);
9916} /* end destroy */
9917
9918void appsession_cleanup( void )
9919{
9920 struct proxy *p = proxy;
9921
9922 while(p) {
9923 chtbl_destroy(&(p->htbl_proxy));
9924 p = p->next;
9925 }
9926}/* end appsession_cleanup() */
9927
9928void pool_destroy(void **pool)
9929{
9930 void *temp, *next;
9931 next = pool;
9932 while (next) {
9933 temp = next;
9934 next = *(void **)temp;
9935 free(temp);
9936 }
9937}/* end pool_destroy() */
9938
willy tarreaub952e1d2005-12-18 01:31:20 +01009939void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009940 struct proxy *p = proxy;
9941 struct cap_hdr *h,*h_next;
9942 struct server *s,*s_next;
9943 struct listener *l,*l_next;
9944
9945 while (p) {
9946 if (p->id)
9947 free(p->id);
9948
9949 if (p->check_req)
9950 free(p->check_req);
9951
9952 if (p->cookie_name)
9953 free(p->cookie_name);
9954
9955 if (p->capture_name)
9956 free(p->capture_name);
9957
9958 /* only strup if the user have set in config.
9959 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009960 if (p->errmsg.msg400) free(p->errmsg.msg400);
9961 if (p->errmsg.msg403) free(p->errmsg.msg403);
9962 if (p->errmsg.msg408) free(p->errmsg.msg408);
9963 if (p->errmsg.msg500) free(p->errmsg.msg500);
9964 if (p->errmsg.msg502) free(p->errmsg.msg502);
9965 if (p->errmsg.msg503) free(p->errmsg.msg503);
9966 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009967 */
9968 if (p->appsession_name)
9969 free(p->appsession_name);
9970
9971 h = p->req_cap;
9972 while (h) {
9973 h_next = h->next;
9974 if (h->name)
9975 free(h->name);
9976 pool_destroy(h->pool);
9977 free(h);
9978 h = h_next;
9979 }/* end while(h) */
9980
9981 h = p->rsp_cap;
9982 while (h) {
9983 h_next = h->next;
9984 if (h->name)
9985 free(h->name);
9986
9987 pool_destroy(h->pool);
9988 free(h);
9989 h = h_next;
9990 }/* end while(h) */
9991
9992 s = p->srv;
9993 while (s) {
9994 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009995 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009996 free(s->id);
9997
willy tarreaub952e1d2005-12-18 01:31:20 +01009998 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009999 free(s->cookie);
10000
10001 free(s);
10002 s = s_next;
10003 }/* end while(s) */
10004
10005 l = p->listen;
10006 while (l) {
10007 l_next = l->next;
10008 free(l);
10009 l = l_next;
10010 }/* end while(l) */
10011
10012 pool_destroy((void **) p->req_cap_pool);
10013 pool_destroy((void **) p->rsp_cap_pool);
10014 p = p->next;
10015 }/* end while(p) */
10016
10017 if (global.chroot) free(global.chroot);
10018 if (global.pidfile) free(global.pidfile);
10019
willy tarreau12350152005-12-18 01:03:27 +010010020 if (StaticReadEvent) free(StaticReadEvent);
10021 if (StaticWriteEvent) free(StaticWriteEvent);
10022 if (fdtab) free(fdtab);
10023
10024 pool_destroy(pool_session);
10025 pool_destroy(pool_buffer);
10026 pool_destroy(pool_fdtab);
10027 pool_destroy(pool_requri);
10028 pool_destroy(pool_task);
10029 pool_destroy(pool_capture);
10030 pool_destroy(pool_appsess);
10031
10032 if (have_appsession) {
10033 pool_destroy(apools.serverid);
10034 pool_destroy(apools.sessid);
10035 }
10036} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +010010037
willy tarreau41310e72006-03-25 18:17:56 +010010038/* sends the signal <sig> to all pids found in <oldpids> */
10039static void tell_old_pids(int sig) {
10040 int p;
10041 for (p = 0; p < nb_oldpids; p++)
10042 kill(oldpids[p], sig);
10043}
10044
willy tarreau0f7af912005-12-17 12:21:26 +010010045int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +010010046 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +010010047 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010048 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +010010049 init(argc, argv);
10050
willy tarreau0f7af912005-12-17 12:21:26 +010010051 signal(SIGQUIT, dump);
10052 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +010010053 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +010010054#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +010010055 signal(SIGINT, sig_int);
10056 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +010010057#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010058
10059 /* on very high loads, a sigpipe sometimes happen just between the
10060 * getsockopt() which tells "it's OK to write", and the following write :-(
10061 */
willy tarreau3242e862005-12-17 12:27:53 +010010062#ifndef MSG_NOSIGNAL
10063 signal(SIGPIPE, SIG_IGN);
10064#endif
willy tarreau0f7af912005-12-17 12:21:26 +010010065
willy tarreau41310e72006-03-25 18:17:56 +010010066 /* We will loop at most 100 times with 10 ms delay each time.
10067 * That's at most 1 second. We only send a signal to old pids
10068 * if we cannot grab at least one port.
10069 */
10070 retry = MAX_START_RETRIES;
10071 err = ERR_NONE;
10072 while (retry >= 0) {
10073 struct timeval w;
10074 err = start_proxies(retry == 0 || nb_oldpids == 0);
10075 if (err != ERR_RETRYABLE)
10076 break;
10077 if (nb_oldpids == 0)
10078 break;
10079
Willy TARREAU007aa462006-05-14 09:55:23 +020010080 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
10081 * listening sockets. So on those platforms, it would be wiser to
10082 * simply send SIGUSR1, which will not be undoable.
10083 */
willy tarreau41310e72006-03-25 18:17:56 +010010084 tell_old_pids(SIGTTOU);
10085 /* give some time to old processes to stop listening */
10086 w.tv_sec = 0;
10087 w.tv_usec = 10*1000;
10088 select(0, NULL, NULL, NULL, &w);
10089 retry--;
10090 }
10091
10092 /* Note: start_proxies() sends an alert when it fails. */
10093 if (err != ERR_NONE) {
10094 if (retry != MAX_START_RETRIES && nb_oldpids)
10095 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +010010096 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +010010097 }
willy tarreaud0fb4652005-12-18 01:32:04 +010010098
10099 if (listeners == 0) {
10100 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010101 /* Note: we don't have to send anything to the old pids because we
10102 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +010010103 exit(1);
10104 }
10105
willy tarreaudbd3bef2006-01-20 19:35:18 +010010106 /* prepare pause/play signals */
10107 signal(SIGTTOU, sig_pause);
10108 signal(SIGTTIN, sig_listen);
10109
Willy TARREAUe3283d12006-03-01 22:15:29 +010010110 if (global.mode & MODE_DAEMON) {
10111 global.mode &= ~MODE_VERBOSE;
10112 global.mode |= MODE_QUIET;
10113 }
10114
willy tarreaud0fb4652005-12-18 01:32:04 +010010115 /* MODE_QUIET can inhibit alerts and warnings below this line */
10116
10117 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +010010118 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +010010119 /* detach from the tty */
10120 fclose(stdin); fclose(stdout); fclose(stderr);
10121 close(0); close(1); close(2);
10122 }
willy tarreau0f7af912005-12-17 12:21:26 +010010123
willy tarreaufe2c5c12005-12-17 14:14:34 +010010124 /* open log & pid files before the chroot */
10125 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
10126 int pidfd;
10127 unlink(global.pidfile);
10128 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
10129 if (pidfd < 0) {
10130 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +010010131 if (nb_oldpids)
10132 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +010010133 exit(1);
10134 }
10135 pidfile = fdopen(pidfd, "w");
10136 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010137
10138 /* chroot if needed */
10139 if (global.chroot != NULL) {
10140 if (chroot(global.chroot) == -1) {
10141 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +010010142 if (nb_oldpids)
10143 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +010010144 }
10145 chdir("/");
10146 }
10147
willy tarreaub1285d52005-12-18 01:20:14 +010010148 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +010010149 if (!global.rlimit_nofile)
10150 global.rlimit_nofile = global.maxsock;
10151
willy tarreaub1285d52005-12-18 01:20:14 +010010152 if (global.rlimit_nofile) {
10153 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
10154 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
10155 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
10156 }
willy tarreau746e26b2006-03-25 11:14:35 +010010157 }
10158
10159 if (global.rlimit_memmax) {
10160 limit.rlim_cur = limit.rlim_max =
10161 global.rlimit_memmax * 1048576 / global.nbproc;
10162#ifdef RLIMIT_AS
10163 if (setrlimit(RLIMIT_AS, &limit) == -1) {
10164 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10165 argv[0], global.rlimit_memmax);
10166 }
10167#else
10168 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
10169 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
10170 argv[0], global.rlimit_memmax);
10171 }
10172#endif
willy tarreaub1285d52005-12-18 01:20:14 +010010173 }
10174
willy tarreau41310e72006-03-25 18:17:56 +010010175 if (nb_oldpids)
10176 tell_old_pids(oldpids_sig);
10177
10178 /* Note that any error at this stage will be fatal because we will not
10179 * be able to restart the old pids.
10180 */
10181
willy tarreau9fe663a2005-12-17 13:02:59 +010010182 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +010010183 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010184 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
10185 exit(1);
10186 }
10187
willy tarreau036e1ce2005-12-17 13:46:33 +010010188 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +010010189 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
10190 exit(1);
10191 }
10192
willy tarreaub1285d52005-12-18 01:20:14 +010010193 /* check ulimits */
10194 limit.rlim_cur = limit.rlim_max = 0;
10195 getrlimit(RLIMIT_NOFILE, &limit);
10196 if (limit.rlim_cur < global.maxsock) {
10197 Warning("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
10198 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
10199 }
10200
willy tarreau9fe663a2005-12-17 13:02:59 +010010201 if (global.mode & MODE_DAEMON) {
10202 int ret = 0;
10203 int proc;
10204
10205 /* the father launches the required number of processes */
10206 for (proc = 0; proc < global.nbproc; proc++) {
10207 ret = fork();
10208 if (ret < 0) {
10209 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +010010210 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +010010211 exit(1); /* there has been an error */
10212 }
10213 else if (ret == 0) /* child breaks here */
10214 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +010010215 if (pidfile != NULL) {
10216 fprintf(pidfile, "%d\n", ret);
10217 fflush(pidfile);
10218 }
willy tarreau9fe663a2005-12-17 13:02:59 +010010219 }
willy tarreaufe2c5c12005-12-17 14:14:34 +010010220 /* close the pidfile both in children and father */
10221 if (pidfile != NULL)
10222 fclose(pidfile);
10223 free(global.pidfile);
10224
willy tarreau9fe663a2005-12-17 13:02:59 +010010225 if (proc == global.nbproc)
10226 exit(0); /* parent must leave */
10227
willy tarreau750a4722005-12-17 13:21:24 +010010228 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
10229 * that we can detach from the TTY. We MUST NOT do it in other cases since
10230 * it would have already be done, and 0-2 would have been affected to listening
10231 * sockets
10232 */
10233 if (!(global.mode & MODE_QUIET)) {
10234 /* detach from the tty */
10235 fclose(stdin); fclose(stdout); fclose(stderr);
10236 close(0); close(1); close(2); /* close all fd's */
10237 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
10238 }
willy tarreaua1598082005-12-17 13:08:06 +010010239 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +010010240 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +010010241 }
10242
willy tarreau1c2ad212005-12-18 01:11:29 +010010243#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010244 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010245 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
10246 epoll_loop(POLL_LOOP_ACTION_RUN);
10247 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010248 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010249 }
10250 else {
willy tarreau64a3cc32005-12-18 01:13:11 +010010251 Warning("epoll() is not available. Using poll()/select() instead.\n");
10252 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010253 }
10254 }
10255#endif
10256
10257#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010258 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010259 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
10260 poll_loop(POLL_LOOP_ACTION_RUN);
10261 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010262 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010263 }
10264 else {
10265 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +010010266 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010267 }
10268 }
10269#endif
willy tarreau64a3cc32005-12-18 01:13:11 +010010270 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010271 if (select_loop(POLL_LOOP_ACTION_INIT)) {
10272 select_loop(POLL_LOOP_ACTION_RUN);
10273 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010274 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +010010275 }
10276 }
10277
willy tarreau0f7af912005-12-17 12:21:26 +010010278
willy tarreau12350152005-12-18 01:03:27 +010010279 /* Free all Hash Keys and all Hash elements */
10280 appsession_cleanup();
10281 /* Do some cleanup */
10282 deinit();
10283
willy tarreau0f7af912005-12-17 12:21:26 +010010284 exit(0);
10285}
willy tarreau12350152005-12-18 01:03:27 +010010286
10287#if defined(DEBUG_HASH)
10288static void print_table(const CHTbl *htbl) {
10289
10290 ListElmt *element;
10291 int i;
10292 appsess *asession;
10293
10294 /*****************************************************************************
10295 * *
10296 * Display the chained hash table. *
10297 * *
10298 *****************************************************************************/
10299
10300 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
10301
10302 for (i = 0; i < TBLSIZ; i++) {
10303 fprintf(stdout, "Bucket[%03d]\n", i);
10304
10305 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10306 //fprintf(stdout, "%c", *(char *)list_data(element));
10307 asession = (appsess *)list_data(element);
10308 fprintf(stdout, "ELEM :%s:", asession->sessid);
10309 fprintf(stdout, " Server :%s: \n", asession->serverid);
10310 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
10311 }
10312
10313 fprintf(stdout, "\n");
10314 }
10315 return;
10316} /* end print_table */
10317#endif
10318
10319static int appsession_init(void)
10320{
10321 static int initialized = 0;
10322 int idlen;
10323 struct server *s;
10324 struct proxy *p = proxy;
10325
10326 if (!initialized) {
10327 if (!appsession_task_init()) {
10328 apools.sessid = NULL;
10329 apools.serverid = NULL;
10330 apools.ser_waste = 0;
10331 apools.ser_use = 0;
10332 apools.ser_msize = sizeof(void *);
10333 apools.ses_waste = 0;
10334 apools.ses_use = 0;
10335 apools.ses_msize = sizeof(void *);
10336 while (p) {
10337 s = p->srv;
10338 if (apools.ses_msize < p->appsession_len)
10339 apools.ses_msize = p->appsession_len;
10340 while (s) {
10341 idlen = strlen(s->id);
10342 if (apools.ser_msize < idlen)
10343 apools.ser_msize = idlen;
10344 s = s->next;
10345 }
10346 p = p->next;
10347 }
10348 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
10349 apools.ses_msize ++;
10350 }
10351 else {
10352 fprintf(stderr, "appsession_task_init failed\n");
10353 return -1;
10354 }
10355 initialized ++;
10356 }
10357 return 0;
10358}
10359
10360static int appsession_task_init(void)
10361{
10362 static int initialized = 0;
10363 struct task *t;
10364 if (!initialized) {
10365 if ((t = pool_alloc(task)) == NULL)
10366 return -1;
10367 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +020010368 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +010010369 t->state = TASK_IDLE;
10370 t->context = NULL;
10371 tv_delayfrom(&t->expire, &now, TBLCHKINT);
10372 task_queue(t);
10373 t->process = appsession_refresh;
10374 initialized ++;
10375 }
10376 return 0;
10377}
10378
10379static int appsession_refresh(struct task *t) {
10380 struct proxy *p = proxy;
10381 CHTbl *htbl;
10382 ListElmt *element, *last;
10383 int i;
10384 appsess *asession;
10385 void *data;
10386
10387 while (p) {
10388 if (p->appsession_name != NULL) {
10389 htbl = &p->htbl_proxy;
10390 /* if we ever give up the use of TBLSIZ, we need to change this */
10391 for (i = 0; i < TBLSIZ; i++) {
10392 last = NULL;
10393 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10394 asession = (appsess *)list_data(element);
10395 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
10396 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
10397 int len;
10398 /*
10399 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
10400 */
10401 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
10402 asession->sessid, asession->serverid?asession->serverid:"(null)");
10403 write(1, trash, len);
10404 }
10405 /* delete the expired element from within the hash table */
10406 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
10407 && (htbl->table[i].destroy != NULL)) {
10408 htbl->table[i].destroy(data);
10409 }
10410 if (last == NULL) {/* patient lost his head, get a new one */
10411 element = list_head(&htbl->table[i]);
10412 if (element == NULL) break; /* no heads left, go to next patient */
10413 }
10414 else
10415 element = last;
10416 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
10417 else
10418 last = element;
10419 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
10420 }
10421 }
10422 p = p->next;
10423 }
10424 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
10425 return TBLCHKINT;
10426} /* end appsession_refresh */
10427
willy tarreau18a957c2006-04-12 19:26:23 +020010428
10429/*
10430 * Local variables:
10431 * c-indent-level: 4
10432 * c-basic-offset: 4
10433 * End:
10434 */