blob: d8375bd9a11196b01a88c1cc0d775a6ea38ab2bf [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 TARREAU4404b7e2006-05-14 10:00:09 +020094#define HAPROXY_VERSION "1.2.13.1"
willy tarreaubfad5742006-03-23 14:19:11 +010095#endif
96
97#ifndef HAPROXY_DATE
Willy TARREAU4404b7e2006-05-14 10:00:09 +020098#define HAPROXY_DATE "2006/05/14"
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 tarreau0f7af912005-12-17 12:21:26 +0100339
willy tarreau5cbea6f2005-12-17 12:48:26 +0100340/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100341#define PR_MODE_TCP 0
342#define PR_MODE_HTTP 1
343#define PR_MODE_HEALTH 2
344
willy tarreau1c2ad212005-12-18 01:11:29 +0100345/* possible actions for the *poll() loops */
346#define POLL_LOOP_ACTION_INIT 0
347#define POLL_LOOP_ACTION_RUN 1
348#define POLL_LOOP_ACTION_CLEAN 2
349
willy tarreau64a3cc32005-12-18 01:13:11 +0100350/* poll mechanisms available */
351#define POLL_USE_SELECT (1<<0)
352#define POLL_USE_POLL (1<<1)
353#define POLL_USE_EPOLL (1<<2)
354
willy tarreau5cbea6f2005-12-17 12:48:26 +0100355/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100356#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
357#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
358#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
359#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
360#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
361#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
362#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
363#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100364#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
365#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
366#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
367#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
368#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
369#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
370#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
371#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
372#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
373#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
374#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100375#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
376#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100377#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100378#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100379#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
380#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100381
willy tarreaua5e8c662006-04-29 10:43:46 +0200382/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100383#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
384#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
385#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
386#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
387#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
388#define SN_POST 0x00000020 /* the request was an HTTP POST */
389
willy tarreaua5e8c662006-04-29 10:43:46 +0200390/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100391#define SN_CK_NONE 0x00000000 /* this session had no cookie */
392#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
393#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
394#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
395#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
396#define SN_CK_SHIFT 6 /* bit shift */
397
willy tarreaua5e8c662006-04-29 10:43:46 +0200398/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100399#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100400#define SN_ERR_CLITO 0x00000100 /* client time-out */
401#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
402#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
403#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
404#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100405#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
406#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100407#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
408#define SN_ERR_SHIFT 8 /* bit shift */
409
willy tarreaua5e8c662006-04-29 10:43:46 +0200410/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100411#define SN_FINST_R 0x00001000 /* session ended during client request */
412#define SN_FINST_C 0x00002000 /* session ended during server connect */
413#define SN_FINST_H 0x00003000 /* session ended during server headers */
414#define SN_FINST_D 0x00004000 /* session ended during data phase */
415#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
willy tarreau078c79a2006-05-13 12:23:58 +0200416#define SN_FINST_Q 0x00006000 /* session ended while waiting in queue for a server slot */
willy tarreau036e1ce2005-12-17 13:46:33 +0100417#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
418#define SN_FINST_SHIFT 12 /* bit shift */
419
willy tarreaua5e8c662006-04-29 10:43:46 +0200420/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100421#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
422#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
423#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
424#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
425#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100426#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100427#define SN_SCK_SHIFT 16 /* bit shift */
428
willy tarreaua5e8c662006-04-29 10:43:46 +0200429/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100430#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
431#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
432#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100433
willy tarreaua5e8c662006-04-29 10:43:46 +0200434/* various other session flags, bits values 0x400000 and above */
435#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200436#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
437#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaue0331262006-05-15 03:02:46 +0200438#define SN_SELF_GEN 0x02000000 /* the proxy generates data for the client (eg: stats) */
willy tarreaua5e8c662006-04-29 10:43:46 +0200439
willy tarreaue0331262006-05-15 03:02:46 +0200440/* various data sources for the responses */
441#define DATA_SRC_NONE 0
442#define DATA_SRC_STATS 1
willy tarreaua5e8c662006-04-29 10:43:46 +0200443
willy tarreau5cbea6f2005-12-17 12:48:26 +0100444/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100445#define CL_STHEADERS 0
446#define CL_STDATA 1
447#define CL_STSHUTR 2
448#define CL_STSHUTW 3
449#define CL_STCLOSE 4
450
willy tarreau5cbea6f2005-12-17 12:48:26 +0100451/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100452#define SV_STIDLE 0
willy tarreau9fea1942006-05-12 19:46:40 +0200453#define SV_STCONN 1
454#define SV_STHEADERS 2
455#define SV_STDATA 3
456#define SV_STSHUTR 4
457#define SV_STSHUTW 5
458#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100459
460/* result of an I/O event */
461#define RES_SILENT 0 /* didn't happen */
462#define RES_DATA 1 /* data were sent or received */
463#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
464#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
465
willy tarreau9fe663a2005-12-17 13:02:59 +0100466/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100467#define MODE_DEBUG 1
468#define MODE_STATS 2
469#define MODE_LOG 4
470#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100471#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100472#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100473#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100474#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100475#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100476
477/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100478#define SRV_RUNNING 1 /* the server is UP */
479#define SRV_BACKUP 2 /* this server is a backup server */
480#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100481#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100482#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100483
willy tarreaudfece232006-05-02 00:19:57 +0200484/* function which act on servers need to return various errors */
485#define SRV_STATUS_OK 0 /* everything is OK. */
486#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
487#define SRV_STATUS_NOSRV 2 /* no server is available */
488#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
489#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
490
willy tarreaue39cd132005-12-17 13:00:18 +0100491/* what to do when a header matches a regex */
492#define ACT_ALLOW 0 /* allow the request */
493#define ACT_REPLACE 1 /* replace the matching header */
494#define ACT_REMOVE 2 /* remove the matching header */
495#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100496#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100497
willy tarreau9fe663a2005-12-17 13:02:59 +0100498/* configuration sections */
499#define CFG_NONE 0
500#define CFG_GLOBAL 1
501#define CFG_LISTEN 2
502
willy tarreaua1598082005-12-17 13:08:06 +0100503/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100504#define LW_DATE 1 /* date */
505#define LW_CLIP 2 /* CLient IP */
506#define LW_SVIP 4 /* SerVer IP */
507#define LW_SVID 8 /* server ID */
508#define LW_REQ 16 /* http REQuest */
509#define LW_RESP 32 /* http RESPonse */
510#define LW_PXIP 64 /* proxy IP */
511#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100512#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100513#define LW_COOKIE 512 /* captured cookie */
514#define LW_REQHDR 1024 /* request header(s) */
515#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100516
willy tarreau41310e72006-03-25 18:17:56 +0100517#define ERR_NONE 0 /* no error */
518#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
519#define ERR_FATAL 2 /* fatal error, may be cumulated */
520
willy tarreau0f7af912005-12-17 12:21:26 +0100521/*********************************************************************/
522
523#define LIST_HEAD(a) ((void *)(&(a)))
524
525/*********************************************************************/
526
willy tarreau9e138862006-05-14 23:06:28 +0200527/* describes a chunk of string */
528struct chunk {
529 char *str; /* beginning of the string itself. Might not be 0-terminated */
530 int len; /* size of the string from first to last char. <0 = uninit. */
531};
532
willy tarreau4302f492005-12-18 01:00:37 +0100533struct cap_hdr {
534 struct cap_hdr *next;
535 char *name; /* header name, case insensitive */
536 int namelen; /* length of the header name, to speed-up lookups */
537 int len; /* capture length, not including terminal zero */
538 int index; /* index in the output array */
539 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
540};
541
willy tarreau0f7af912005-12-17 12:21:26 +0100542struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100543 struct hdr_exp *next;
544 regex_t *preg; /* expression to look for */
545 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
546 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100547};
548
549struct buffer {
550 unsigned int l; /* data length */
551 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100552 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100553 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100554 char data[BUFSIZE];
555};
556
willy tarreau18a957c2006-04-12 19:26:23 +0200557struct pendconn {
558 struct list list; /* chaining ... */
559 struct session *sess; /* the session waiting for a connection */
560 struct server *srv; /* the server we are waiting for */
561};
562
willy tarreau0f7af912005-12-17 12:21:26 +0100563struct server {
564 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100565 int state; /* server state (SRV_*) */
566 int cklen; /* the len of the cookie, to speed up checks */
567 char *cookie; /* the id set in the cookie */
568 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200569 struct list pendconns; /* pending connections */
willy tarreaucb406512006-05-18 00:52:35 +0200570 int nbpend, nbpend_max; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200571 struct task *queue_mgt; /* the task associated to the queue processing */
willy tarreau0f7af912005-12-17 12:21:26 +0100572 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100573 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100574 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100575 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100576 int rise, fall; /* time in iterations */
577 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100578 int result; /* 0 = connect OK, -1 = connect KO */
579 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200580 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200581 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaucb406512006-05-18 00:52:35 +0200582 int cur_sess, cur_sess_max; /* number of currently active sessions (including syn_sent) */
willy tarreaua647c702006-04-15 22:45:52 +0200583 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200584 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreaucb406512006-05-18 00:52:35 +0200585 unsigned failed_checks, down_trans; /* failed checks and up-down transitions */
willy tarreau535ae7a2005-12-17 12:58:00 +0100586 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100587};
588
willy tarreau5cbea6f2005-12-17 12:48:26 +0100589/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100590struct task {
591 struct task *next, *prev; /* chaining ... */
592 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100593 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100594 int state; /* task state : IDLE or RUNNING */
595 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100596 int (*process)(struct task *t); /* the function which processes the task */
597 void *context; /* the task's context */
598};
599
600/* WARNING: if new fields are added, they must be initialized in event_accept() */
601struct session {
602 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100603 /* application specific below */
604 struct timeval crexpire; /* expiration date for a client read */
605 struct timeval cwexpire; /* expiration date for a client write */
606 struct timeval srexpire; /* expiration date for a server read */
607 struct timeval swexpire; /* expiration date for a server write */
608 struct timeval cnexpire; /* expiration date for a connect */
609 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
610 struct proxy *proxy; /* the proxy this socket belongs to */
611 int cli_fd; /* the client side fd */
612 int srv_fd; /* the server side fd */
613 int cli_state; /* state of the client side */
614 int srv_state; /* state of the server side */
615 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100616 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100617 struct buffer *req; /* request buffer */
618 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100619 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100620 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100621 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200622 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100623 char **req_cap; /* array of captured request headers (may be NULL) */
624 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreau9e138862006-05-14 23:06:28 +0200625 struct chunk req_line; /* points to first line */
626 struct chunk auth_hdr; /* points to 'Authorization:' header */
willy tarreaua1598082005-12-17 13:08:06 +0100627 struct {
628 int logwait; /* log fields waiting to be collected : LW_* */
629 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
630 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200631 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100632 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
633 long t_data; /* delay before the first data byte from the server ... */
634 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200635 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
636 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 +0100637 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100638 char *cli_cookie; /* cookie presented by the client, in capture mode */
639 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100640 int status; /* HTTP status from the server, negative if from proxy */
641 long long bytes; /* number of bytes transferred from the server */
642 } logs;
willy tarreaue0331262006-05-15 03:02:46 +0200643 int data_source; /* where to get the data we generate ourselves */
644 union {
645 struct {
646 struct proxy *px;
647 struct server *sv;
648 } stats;
649 } data_ctx;
willy tarreau2f6ba652005-12-17 13:57:42 +0100650 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100651};
652
willy tarreaua41a8b42005-12-17 14:02:24 +0100653struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100654 int fd; /* the listen socket */
655 struct sockaddr_storage addr; /* the address we listen to */
656 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100657};
willy tarreauf32f5242006-05-02 22:54:52 +0200658
willy tarreau0f7af912005-12-17 12:21:26 +0100659struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100660 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100661 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 +0100662 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100663 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200664 struct server *srv; /* known servers */
665 int srv_act, srv_bck; /* # of running servers */
666 int tot_wact, tot_wbck; /* total weights of active and backup servers */
667 struct server **srv_map; /* the server map used to apply weights */
668 int srv_map_sz; /* the size of the effective server map */
669 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100670 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100671 int cookie_len; /* strlen(cookie_name), computed only once */
672 char *appsession_name; /* name of the cookie to look for */
673 int appsession_name_len; /* strlen(appsession_name), computed only once */
674 int appsession_len; /* length of the appsession cookie value to be used */
675 int appsession_timeout;
676 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100677 char *capture_name; /* beginning of the name of the cookie to capture */
678 int capture_namelen; /* length of the cookie name to match */
679 int capture_len; /* length of the string to be captured */
willy tarreau9e138862006-05-14 23:06:28 +0200680 struct uri_auth *uri_auth; /* if non-NULL, the (list of) per-URI authentications */
willy tarreau0f7af912005-12-17 12:21:26 +0100681 int clitimeout; /* client I/O timeout (in milliseconds) */
682 int srvtimeout; /* server I/O timeout (in milliseconds) */
683 int contimeout; /* connect timeout (in milliseconds) */
684 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200685 struct list pendconns; /* pending connections with no server assigned yet */
willy tarreaucb406512006-05-18 00:52:35 +0200686 int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200687 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreaucb406512006-05-18 00:52:35 +0200688 int nbconn, nbconn_max; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200689 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100690 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100691 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100692 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100693 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100694 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100695 struct proxy *next;
696 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100697 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100698 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100699 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100700 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100701 int nb_reqadd, nb_rspadd;
702 struct hdr_exp *req_exp; /* regular expressions for request headers */
703 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100704 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
705 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
706 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
707 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100708 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100709 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100710 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
711 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100712 struct {
713 char *msg400; /* message for error 400 */
714 int len400; /* message length for error 400 */
715 char *msg403; /* message for error 403 */
716 int len403; /* message length for error 403 */
717 char *msg408; /* message for error 408 */
718 int len408; /* message length for error 408 */
719 char *msg500; /* message for error 500 */
720 int len500; /* message length for error 500 */
721 char *msg502; /* message for error 502 */
722 int len502; /* message length for error 502 */
723 char *msg503; /* message for error 503 */
724 int len503; /* message length for error 503 */
725 char *msg504; /* message for error 504 */
726 int len504; /* message length for error 504 */
727 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100728};
729
730/* info about one given fd */
731struct fdtab {
732 int (*read)(int fd); /* read function */
733 int (*write)(int fd); /* write function */
734 struct task *owner; /* the session (or proxy) associated with this fd */
735 int state; /* the state of this fd */
736};
737
738/*********************************************************************/
739
willy tarreaub952e1d2005-12-18 01:31:20 +0100740int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100741int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100742char *cfg_cfgfile = NULL; /* configuration file */
743char *progname = NULL; /* program name */
744int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100745
746/* global options */
747static struct {
748 int uid;
749 int gid;
750 int nbproc;
751 int maxconn;
752 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100753 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100754 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100755 int mode;
756 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100757 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100758 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100759 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100760 struct sockaddr_in logsrv1, logsrv2;
761} global = {
762 logfac1 : -1,
763 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100764 loglev1 : 7, /* max syslog level : debug */
765 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100766 /* others NULL OK */
767};
768
willy tarreau0f7af912005-12-17 12:21:26 +0100769/*********************************************************************/
770
willy tarreau1c2ad212005-12-18 01:11:29 +0100771fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100772 *StaticWriteEvent;
773
willy tarreau64a3cc32005-12-18 01:13:11 +0100774int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100775
willy tarreau0f7af912005-12-17 12:21:26 +0100776void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200777 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100778 **pool_buffer = NULL,
779 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100780 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100781 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100782 **pool_capture = NULL,
783 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100784
785struct proxy *proxy = NULL; /* list of all existing proxies */
786struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100787struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200788struct task wait_queue[2] = { /* global wait queue */
789 {
790 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
791 next:LIST_HEAD(wait_queue[0]),
792 },
793 {
794 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
795 next:LIST_HEAD(wait_queue[1]),
796 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100797};
willy tarreau0f7af912005-12-17 12:21:26 +0100798
willy tarreau0f7af912005-12-17 12:21:26 +0100799static int totalconn = 0; /* total # of terminated sessions */
800static int actconn = 0; /* # of active sessions */
801static int maxfd = 0; /* # of the highest fd + 1 */
802static int listeners = 0; /* # of listeners */
803static int stopping = 0; /* non zero means stopping in progress */
804static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaue0331262006-05-15 03:02:46 +0200805static struct timeval start_date; /* the process's start date */
willy tarreaua41a8b42005-12-17 14:02:24 +0100806static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100807
willy tarreau53e99702006-03-25 18:53:50 +0100808/* Here we store informations about the pids of the processes we may pause
809 * or kill. We will send them a signal every 10 ms until we can bind to all
810 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100811 */
willy tarreau53e99702006-03-25 18:53:50 +0100812#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100813static int nb_oldpids = 0;
814static int *oldpids = NULL;
815static int oldpids_sig; /* use USR1 or TERM */
816
willy tarreau08dedbe2005-12-18 01:13:48 +0100817#if defined(ENABLE_EPOLL)
818/* FIXME: this is dirty, but at the moment, there's no other solution to remove
819 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
820 * structure with pointers to functions such as init_fd() and close_fd(), plus
821 * a private structure with several pointers to places such as below.
822 */
823
824static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
825#endif
826
willy tarreau0f7af912005-12-17 12:21:26 +0100827static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100828/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100829static char trash[BUFSIZE];
830
willy tarreaudd07e972005-12-18 00:48:48 +0100831const int zero = 0;
832const int one = 1;
833
willy tarreau0f7af912005-12-17 12:21:26 +0100834/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100835 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100836 */
837
838#define MAX_SYSLOG_LEN 1024
839#define NB_LOG_FACILITIES 24
840const char *log_facilities[NB_LOG_FACILITIES] = {
841 "kern", "user", "mail", "daemon",
842 "auth", "syslog", "lpr", "news",
843 "uucp", "cron", "auth2", "ftp",
844 "ntp", "audit", "alert", "cron2",
845 "local0", "local1", "local2", "local3",
846 "local4", "local5", "local6", "local7"
847};
848
849
850#define NB_LOG_LEVELS 8
851const char *log_levels[NB_LOG_LEVELS] = {
852 "emerg", "alert", "crit", "err",
853 "warning", "notice", "info", "debug"
854};
855
856#define SYSLOG_PORT 514
857
858const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
859 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100860
willy tarreaub1285d52005-12-18 01:20:14 +0100861const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200862const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100863const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
864const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
865 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
866 unknown, Set-cookie Rewritten */
867
willy tarreau0f7af912005-12-17 12:21:26 +0100868#define MAX_HOSTNAME_LEN 32
869static char hostname[MAX_HOSTNAME_LEN] = "";
870
willy tarreau8337c6b2005-12-17 13:41:01 +0100871const char *HTTP_302 =
872 "HTTP/1.0 302 Found\r\n"
873 "Cache-Control: no-cache\r\n"
874 "Connection: close\r\n"
875 "Location: "; /* not terminated since it will be concatenated with the URL */
876
willy tarreauc1f47532005-12-18 01:08:26 +0100877/* same as 302 except that the browser MUST retry with the GET method */
878const char *HTTP_303 =
879 "HTTP/1.0 303 See Other\r\n"
880 "Cache-Control: no-cache\r\n"
881 "Connection: close\r\n"
882 "Location: "; /* not terminated since it will be concatenated with the URL */
883
willy tarreaua1598082005-12-17 13:08:06 +0100884const char *HTTP_400 =
885 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100886 "Cache-Control: no-cache\r\n"
887 "Connection: close\r\n"
888 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100889 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100890
willy tarreau9e138862006-05-14 23:06:28 +0200891/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
892const char *HTTP_401_fmt =
893 "HTTP/1.0 401 Unauthorized\r\n"
894 "Cache-Control: no-cache\r\n"
895 "Connection: close\r\n"
896 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
897 "\r\n"
898 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
899
willy tarreaua1598082005-12-17 13:08:06 +0100900const char *HTTP_403 =
901 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100902 "Cache-Control: no-cache\r\n"
903 "Connection: close\r\n"
904 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100905 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
906
willy tarreau8337c6b2005-12-17 13:41:01 +0100907const char *HTTP_408 =
908 "HTTP/1.0 408 Request Time-out\r\n"
909 "Cache-Control: no-cache\r\n"
910 "Connection: close\r\n"
911 "\r\n"
912 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
913
willy tarreau750a4722005-12-17 13:21:24 +0100914const char *HTTP_500 =
915 "HTTP/1.0 500 Server Error\r\n"
916 "Cache-Control: no-cache\r\n"
917 "Connection: close\r\n"
918 "\r\n"
919 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100920
921const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100922 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100923 "Cache-Control: no-cache\r\n"
924 "Connection: close\r\n"
925 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100926 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
927
928const char *HTTP_503 =
929 "HTTP/1.0 503 Service Unavailable\r\n"
930 "Cache-Control: no-cache\r\n"
931 "Connection: close\r\n"
932 "\r\n"
933 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
934
935const char *HTTP_504 =
936 "HTTP/1.0 504 Gateway Time-out\r\n"
937 "Cache-Control: no-cache\r\n"
938 "Connection: close\r\n"
939 "\r\n"
940 "<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 +0100941
willy tarreau0f7af912005-12-17 12:21:26 +0100942/*********************************************************************/
943/* statistics ******************************************************/
944/*********************************************************************/
945
willy tarreau750a4722005-12-17 13:21:24 +0100946#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100947static int stats_tsk_lsrch, stats_tsk_rsrch,
948 stats_tsk_good, stats_tsk_right, stats_tsk_left,
949 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100950#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100951
952
953/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100954/* debugging *******************************************************/
955/*********************************************************************/
956#ifdef DEBUG_FULL
957static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau3504a012006-05-14 23:20:07 +0200958static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100959#endif
960
961/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100962/* function prototypes *********************************************/
963/*********************************************************************/
964
965int event_accept(int fd);
966int event_cli_read(int fd);
967int event_cli_write(int fd);
968int event_srv_read(int fd);
969int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100970int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100971
willy tarreau12350152005-12-18 01:03:27 +0100972static int appsession_task_init(void);
973static int appsession_init(void);
974static int appsession_refresh(struct task *t);
975
willy tarreau0f7af912005-12-17 12:21:26 +0100976/*********************************************************************/
977/* general purpose functions ***************************************/
978/*********************************************************************/
979
980void display_version() {
981 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100982 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100983}
984
985/*
986 * This function prints the command line usage and exits
987 */
988void usage(char *name) {
989 display_version();
990 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100991 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100992#if STATTIME > 0
993 "sl"
994#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100995 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
996 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100997 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100998 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100999 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001000#if STATTIME > 0
1001 " -s enables statistics output\n"
1002 " -l enables long statistics format\n"
1003#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001004 " -D goes daemon ; implies -q\n"
1005 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +01001006 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +01001007 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +01001008 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +01001009 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001010 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001011#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001012 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001013#endif
1014#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01001015 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +01001016#endif
willy tarreau53e99702006-03-25 18:53:50 +01001017 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +01001018 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01001019 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +01001020 exit(1);
1021}
1022
1023
1024/*
willy tarreaud0fb4652005-12-18 01:32:04 +01001025 * Displays the message on stderr with the date and pid. Overrides the quiet
1026 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +01001027 */
1028void Alert(char *fmt, ...) {
1029 va_list argp;
1030 struct timeval tv;
1031 struct tm *tm;
1032
willy tarreaud0fb4652005-12-18 01:32:04 +01001033 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001034 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001035
willy tarreau5cbea6f2005-12-17 12:48:26 +01001036 gettimeofday(&tv, NULL);
1037 tm=localtime(&tv.tv_sec);
1038 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001039 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001040 vfprintf(stderr, fmt, argp);
1041 fflush(stderr);
1042 va_end(argp);
1043 }
willy tarreau0f7af912005-12-17 12:21:26 +01001044}
1045
1046
1047/*
1048 * Displays the message on stderr with the date and pid.
1049 */
1050void Warning(char *fmt, ...) {
1051 va_list argp;
1052 struct timeval tv;
1053 struct tm *tm;
1054
willy tarreau982249e2005-12-18 00:57:06 +01001055 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001056 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001057
willy tarreau5cbea6f2005-12-17 12:48:26 +01001058 gettimeofday(&tv, NULL);
1059 tm=localtime(&tv.tv_sec);
1060 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001061 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001062 vfprintf(stderr, fmt, argp);
1063 fflush(stderr);
1064 va_end(argp);
1065 }
1066}
1067
1068/*
1069 * Displays the message on <out> only if quiet mode is not set.
1070 */
1071void qfprintf(FILE *out, char *fmt, ...) {
1072 va_list argp;
1073
willy tarreau982249e2005-12-18 00:57:06 +01001074 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001075 va_start(argp, fmt);
1076 vfprintf(out, fmt, argp);
1077 fflush(out);
1078 va_end(argp);
1079 }
willy tarreau0f7af912005-12-17 12:21:26 +01001080}
1081
1082
1083/*
1084 * converts <str> to a struct sockaddr_in* which is locally allocated.
1085 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1086 * INADDR_ANY.
1087 */
1088struct sockaddr_in *str2sa(char *str) {
1089 static struct sockaddr_in sa;
1090 char *c;
1091 int port;
1092
willy tarreaua1598082005-12-17 13:08:06 +01001093 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001094 str=strdup(str);
1095
1096 if ((c=strrchr(str,':')) != NULL) {
1097 *c++=0;
1098 port=atol(c);
1099 }
1100 else
1101 port=0;
1102
1103 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1104 sa.sin_addr.s_addr = INADDR_ANY;
1105 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001106 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001107 struct hostent *he;
1108
1109 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001110 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001111 }
1112 else
1113 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1114 }
1115 sa.sin_port=htons(port);
1116 sa.sin_family=AF_INET;
1117
1118 free(str);
1119 return &sa;
1120}
1121
willy tarreaub1285d52005-12-18 01:20:14 +01001122/*
1123 * converts <str> to a two struct in_addr* which are locally allocated.
1124 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1125 * is optionnal and either in the dotted or CIDR notation.
1126 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1127 */
1128int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1129 char *c;
1130 unsigned long len;
1131
1132 memset(mask, 0, sizeof(*mask));
1133 memset(addr, 0, sizeof(*addr));
1134 str=strdup(str);
1135
1136 if ((c = strrchr(str, '/')) != NULL) {
1137 *c++ = 0;
1138 /* c points to the mask */
1139 if (strchr(c, '.') != NULL) { /* dotted notation */
1140 if (!inet_pton(AF_INET, c, mask))
1141 return 0;
1142 }
1143 else { /* mask length */
1144 char *err;
1145 len = strtol(c, &err, 10);
1146 if (!*c || (err && *err) || (unsigned)len > 32)
1147 return 0;
1148 if (len)
1149 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1150 else
1151 mask->s_addr = 0;
1152 }
1153 }
1154 else {
1155 mask->s_addr = 0xFFFFFFFF;
1156 }
1157 if (!inet_pton(AF_INET, str, addr)) {
1158 struct hostent *he;
1159
1160 if ((he = gethostbyname(str)) == NULL) {
1161 return 0;
1162 }
1163 else
1164 *addr = *(struct in_addr *) *(he->h_addr_list);
1165 }
1166 free(str);
1167 return 1;
1168}
1169
willy tarreau9fe663a2005-12-17 13:02:59 +01001170
1171/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001172 * converts <str> to a list of listeners which are dynamically allocated.
1173 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1174 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1175 * - <port> is a numerical port from 1 to 65535 ;
1176 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1177 * This can be repeated as many times as necessary, separated by a coma.
1178 * The <tail> argument is a pointer to a current list which should be appended
1179 * to the tail of the new list. The pointer to the new list is returned.
1180 */
1181struct listener *str2listener(char *str, struct listener *tail) {
1182 struct listener *l;
1183 char *c, *next, *range, *dupstr;
1184 int port, end;
1185
1186 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001187
willy tarreaua41a8b42005-12-17 14:02:24 +01001188 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001189 struct sockaddr_storage ss;
1190
willy tarreaua41a8b42005-12-17 14:02:24 +01001191 str = next;
1192 /* 1) look for the end of the first address */
1193 if ((next = strrchr(str, ',')) != NULL) {
1194 *next++ = 0;
1195 }
1196
willy tarreau8a86dbf2005-12-18 00:45:59 +01001197 /* 2) look for the addr/port delimiter, it's the last colon. */
1198 if ((range = strrchr(str, ':')) == NULL) {
1199 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001200 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001201 }
1202
1203 *range++ = 0;
1204
1205 if (strrchr(str, ':') != NULL) {
1206 /* IPv6 address contains ':' */
1207 memset(&ss, 0, sizeof(ss));
1208 ss.ss_family = AF_INET6;
1209
1210 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1211 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001212 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001213 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001214 }
1215 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001216 memset(&ss, 0, sizeof(ss));
1217 ss.ss_family = AF_INET;
1218
1219 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1220 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1221 }
1222 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1223 struct hostent *he;
1224
1225 if ((he = gethostbyname(str)) == NULL) {
1226 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001227 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001228 }
1229 else
1230 ((struct sockaddr_in *)&ss)->sin_addr =
1231 *(struct in_addr *) *(he->h_addr_list);
1232 }
1233 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001234
1235 /* 3) look for the port-end delimiter */
1236 if ((c = strchr(range, '-')) != NULL) {
1237 *c++ = 0;
1238 end = atol(c);
1239 }
1240 else {
1241 end = atol(range);
1242 }
1243
willy tarreaud0fb4652005-12-18 01:32:04 +01001244 port = atol(range);
1245
1246 if (port < 1 || port > 65535) {
1247 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1248 goto fail;
1249 }
1250
1251 if (end < 1 || end > 65535) {
1252 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1253 goto fail;
1254 }
1255
1256 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001257 l = (struct listener *)calloc(1, sizeof(struct listener));
1258 l->next = tail;
1259 tail = l;
1260
willy tarreau41310e72006-03-25 18:17:56 +01001261 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001262 l->addr = ss;
1263 if (ss.ss_family == AF_INET6)
1264 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1265 else
1266 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1267
willy tarreaua41a8b42005-12-17 14:02:24 +01001268 } /* end for(port) */
1269 } /* end while(next) */
1270 free(dupstr);
1271 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001272 fail:
1273 free(dupstr);
1274 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001275}
1276
willy tarreau4302f492005-12-18 01:00:37 +01001277
1278#define FD_SETS_ARE_BITFIELDS
1279#ifdef FD_SETS_ARE_BITFIELDS
1280/*
1281 * This map is used with all the FD_* macros to check whether a particular bit
1282 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1283 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1284 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1285 * exclusively to the macros.
1286 */
1287fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1288fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1289
1290#else
1291#error "Check if your OS uses bitfields for fd_sets"
1292#endif
1293
1294/* will try to encode the string <string> replacing all characters tagged in
1295 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1296 * prefixed by <escape>, and will store the result between <start> (included
1297 *) and <stop> (excluded), and will always terminate the string with a '\0'
1298 * before <stop>. The position of the '\0' is returned if the conversion
1299 * completes. If bytes are missing between <start> and <stop>, then the
1300 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1301 * cannot even be stored so we return <start> without writing the 0.
1302 * The input string must also be zero-terminated.
1303 */
1304char hextab[16] = "0123456789ABCDEF";
1305char *encode_string(char *start, char *stop,
1306 const char escape, const fd_set *map,
1307 const char *string)
1308{
1309 if (start < stop) {
1310 stop--; /* reserve one byte for the final '\0' */
1311 while (start < stop && *string != 0) {
1312 if (!FD_ISSET((unsigned char)(*string), map))
1313 *start++ = *string;
1314 else {
1315 if (start + 3 >= stop)
1316 break;
1317 *start++ = escape;
1318 *start++ = hextab[(*string >> 4) & 15];
1319 *start++ = hextab[*string & 15];
1320 }
1321 string++;
1322 }
1323 *start = '\0';
1324 }
1325 return start;
1326}
willy tarreaua41a8b42005-12-17 14:02:24 +01001327
1328/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001329 * This function sends a syslog message to both log servers of a proxy,
1330 * or to global log servers if the proxy is NULL.
1331 * It also tries not to waste too much time computing the message header.
1332 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001333 */
1334void send_log(struct proxy *p, int level, char *message, ...) {
1335 static int logfd = -1; /* syslog UDP socket */
1336 static long tvsec = -1; /* to force the string to be initialized */
1337 struct timeval tv;
1338 va_list argp;
1339 static char logmsg[MAX_SYSLOG_LEN];
1340 static char *dataptr = NULL;
1341 int fac_level;
1342 int hdr_len, data_len;
1343 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001344 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001345 int nbloggers = 0;
1346 char *log_ptr;
1347
1348 if (logfd < 0) {
1349 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1350 return;
1351 }
1352
1353 if (level < 0 || progname == NULL || message == NULL)
1354 return;
1355
1356 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001357 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001358 /* this string is rebuild only once a second */
1359 struct tm *tm = localtime(&tv.tv_sec);
1360 tvsec = tv.tv_sec;
1361
willy tarreauc29948c2005-12-17 13:10:27 +01001362 hdr_len = snprintf(logmsg, sizeof(logmsg),
1363 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1364 monthname[tm->tm_mon],
1365 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1366 progname, pid);
1367 /* WARNING: depending upon implementations, snprintf may return
1368 * either -1 or the number of bytes that would be needed to store
1369 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001370 */
willy tarreauc29948c2005-12-17 13:10:27 +01001371 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1372 hdr_len = sizeof(logmsg);
1373
1374 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001375 }
1376
1377 va_start(argp, message);
1378 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001379 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1380 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001381 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001382 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001383
1384 if (p == NULL) {
1385 if (global.logfac1 >= 0) {
1386 sa[nbloggers] = &global.logsrv1;
1387 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001388 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001389 nbloggers++;
1390 }
1391 if (global.logfac2 >= 0) {
1392 sa[nbloggers] = &global.logsrv2;
1393 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001394 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001395 nbloggers++;
1396 }
1397 } else {
1398 if (p->logfac1 >= 0) {
1399 sa[nbloggers] = &p->logsrv1;
1400 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001401 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001402 nbloggers++;
1403 }
1404 if (p->logfac2 >= 0) {
1405 sa[nbloggers] = &p->logsrv2;
1406 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001407 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001408 nbloggers++;
1409 }
1410 }
1411
1412 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001413 /* we can filter the level of the messages that are sent to each logger */
1414 if (level > loglevel[nbloggers])
1415 continue;
1416
willy tarreauc29948c2005-12-17 13:10:27 +01001417 /* For each target, we may have a different facility.
1418 * We can also have a different log level for each message.
1419 * This induces variations in the message header length.
1420 * Since we don't want to recompute it each time, nor copy it every
1421 * time, we only change the facility in the pre-computed header,
1422 * and we change the pointer to the header accordingly.
1423 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001424 fac_level = (facilities[nbloggers] << 3) + level;
1425 log_ptr = logmsg + 3; /* last digit of the log level */
1426 do {
1427 *log_ptr = '0' + fac_level % 10;
1428 fac_level /= 10;
1429 log_ptr--;
1430 } while (fac_level && log_ptr > logmsg);
1431 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001432
willy tarreauc29948c2005-12-17 13:10:27 +01001433 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001434
1435#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001436 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001437 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1438#else
willy tarreauc29948c2005-12-17 13:10:27 +01001439 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001440 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1441#endif
1442 }
willy tarreau0f7af912005-12-17 12:21:26 +01001443}
1444
1445
1446/* sets <tv> to the current time */
1447static inline struct timeval *tv_now(struct timeval *tv) {
1448 if (tv)
1449 gettimeofday(tv, NULL);
1450 return tv;
1451}
1452
1453/*
1454 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1455 */
willy tarreaudab722b2006-05-04 19:23:38 +02001456static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001457 if (!tv || !from)
1458 return NULL;
1459 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1460 tv->tv_sec = from->tv_sec + (ms/1000);
1461 while (tv->tv_usec >= 1000000) {
1462 tv->tv_usec -= 1000000;
1463 tv->tv_sec++;
1464 }
1465 return tv;
1466}
1467
1468/*
1469 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001470 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001471 */
1472static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001473 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001474 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001475 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001476 return 1;
1477 else if (tv1->tv_usec < tv2->tv_usec)
1478 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001479 else if (tv1->tv_usec > tv2->tv_usec)
1480 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001481 else
1482 return 0;
1483}
1484
1485/*
1486 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001487 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001488 */
1489unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1490 int cmp;
1491 unsigned long ret;
1492
1493
willy tarreauef900ab2005-12-17 12:52:52 +01001494 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001495 if (!cmp)
1496 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001497 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001498 struct timeval *tmp = tv1;
1499 tv1 = tv2;
1500 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001501 }
willy tarreauef900ab2005-12-17 12:52:52 +01001502 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001503 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001504 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001505 else
willy tarreauef900ab2005-12-17 12:52:52 +01001506 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001507 return (unsigned long) ret;
1508}
1509
1510/*
willy tarreau750a4722005-12-17 13:21:24 +01001511 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001512 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001513 */
1514static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1515 unsigned long ret;
1516
willy tarreau6e682ce2005-12-17 13:26:49 +01001517 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1518 if (tv2->tv_usec > tv1->tv_usec)
1519 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001520 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001521 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001522 return (unsigned long) ret;
1523}
1524
1525/*
willy tarreau0f7af912005-12-17 12:21:26 +01001526 * 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 +01001527 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001528 */
willy tarreaudab722b2006-05-04 19:23:38 +02001529static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001530 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001531 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001532 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001533 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001534 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001535 else
1536 return 0;
1537 }
willy tarreau0f7af912005-12-17 12:21:26 +01001538 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001539 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001540 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001541 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001542 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001543 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001544 else
1545 return 0;
1546}
1547
1548/*
1549 * returns the remaining time between tv1=now and event=tv2
1550 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001551 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001552 */
1553static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1554 unsigned long ret;
1555
willy tarreau0f7af912005-12-17 12:21:26 +01001556 if (tv_cmp_ms(tv1, tv2) >= 0)
1557 return 0; /* event elapsed */
1558
willy tarreauef900ab2005-12-17 12:52:52 +01001559 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001560 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001561 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001562 else
willy tarreauef900ab2005-12-17 12:52:52 +01001563 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001564 return (unsigned long) ret;
1565}
1566
1567
1568/*
1569 * zeroes a struct timeval
1570 */
1571
1572static inline struct timeval *tv_eternity(struct timeval *tv) {
1573 tv->tv_sec = tv->tv_usec = 0;
1574 return tv;
1575}
1576
1577/*
1578 * returns 1 if tv is null, else 0
1579 */
1580static inline int tv_iseternity(struct timeval *tv) {
1581 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1582 return 1;
1583 else
1584 return 0;
1585}
1586
1587/*
1588 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1589 * considering that 0 is the eternity.
1590 */
willy tarreaudab722b2006-05-04 19:23:38 +02001591static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001592 if (tv_iseternity(tv1))
1593 if (tv_iseternity(tv2))
1594 return 0; /* same */
1595 else
1596 return 1; /* tv1 later than tv2 */
1597 else if (tv_iseternity(tv2))
1598 return -1; /* tv2 later than tv1 */
1599
1600 if (tv1->tv_sec > tv2->tv_sec)
1601 return 1;
1602 else if (tv1->tv_sec < tv2->tv_sec)
1603 return -1;
1604 else if (tv1->tv_usec > tv2->tv_usec)
1605 return 1;
1606 else if (tv1->tv_usec < tv2->tv_usec)
1607 return -1;
1608 else
1609 return 0;
1610}
1611
1612/*
1613 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1614 * considering that 0 is the eternity.
1615 */
willy tarreaudab722b2006-05-04 19:23:38 +02001616static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001617 if (tv_iseternity(tv1))
1618 if (tv_iseternity(tv2))
1619 return 0; /* same */
1620 else
1621 return 1; /* tv1 later than tv2 */
1622 else if (tv_iseternity(tv2))
1623 return -1; /* tv2 later than tv1 */
1624
willy tarreauefae1842005-12-17 12:51:03 +01001625 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001626 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001627 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001628 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001629 return -1;
1630 else
1631 return 0;
1632 }
1633 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001634 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001635 return 1;
1636 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001637 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001638 return -1;
1639 else
1640 return 0;
1641}
1642
1643/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001644 * returns the remaining time between tv1=now and event=tv2
1645 * if tv2 is passed, 0 is returned.
1646 * Returns TIME_ETERNITY if tv2 is eternity.
1647 */
willy tarreaudab722b2006-05-04 19:23:38 +02001648static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001649 unsigned long ret;
1650
1651 if (tv_iseternity(tv2))
1652 return TIME_ETERNITY;
1653
1654 if (tv_cmp_ms(tv1, tv2) >= 0)
1655 return 0; /* event elapsed */
1656
1657 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1658 if (tv2->tv_usec > tv1->tv_usec)
1659 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1660 else
1661 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1662 return (unsigned long) ret;
1663}
1664
1665/*
willy tarreau0f7af912005-12-17 12:21:26 +01001666 * returns the first event between tv1 and tv2 into tvmin.
1667 * a zero tv is ignored. tvmin is returned.
1668 */
1669static inline struct timeval *tv_min(struct timeval *tvmin,
1670 struct timeval *tv1, struct timeval *tv2) {
1671
1672 if (tv_cmp2(tv1, tv2) <= 0)
1673 *tvmin = *tv1;
1674 else
1675 *tvmin = *tv2;
1676
1677 return tvmin;
1678}
1679
1680
1681
1682/***********************************************************/
1683/* fd management ***************************************/
1684/***********************************************************/
1685
1686
1687
willy tarreau5cbea6f2005-12-17 12:48:26 +01001688/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1689 * The file descriptor is also closed.
1690 */
willy tarreaudab722b2006-05-04 19:23:38 +02001691static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001692 FD_CLR(fd, StaticReadEvent);
1693 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001694#if defined(ENABLE_EPOLL)
1695 if (PrevReadEvent) {
1696 FD_CLR(fd, PrevReadEvent);
1697 FD_CLR(fd, PrevWriteEvent);
1698 }
1699#endif
1700
willy tarreau5cbea6f2005-12-17 12:48:26 +01001701 close(fd);
1702 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001703
1704 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1705 maxfd--;
1706}
1707
1708/* recomputes the maxfd limit from the fd */
1709static inline void fd_insert(int fd) {
1710 if (fd+1 > maxfd)
1711 maxfd = fd+1;
1712}
1713
1714/*************************************************************/
1715/* task management ***************************************/
1716/*************************************************************/
1717
willy tarreau5cbea6f2005-12-17 12:48:26 +01001718/* puts the task <t> in run queue <q>, and returns <t> */
1719static inline struct task *task_wakeup(struct task **q, struct task *t) {
1720 if (t->state == TASK_RUNNING)
1721 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001722 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001723 t->rqnext = *q;
1724 t->state = TASK_RUNNING;
1725 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001726 }
1727}
1728
willy tarreau5cbea6f2005-12-17 12:48:26 +01001729/* removes the task <t> from the queue <q>
1730 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001731 * set the run queue to point to the next one, and return it
1732 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001733static inline struct task *task_sleep(struct task **q, struct task *t) {
1734 if (t->state == TASK_RUNNING) {
1735 *q = t->rqnext;
1736 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001737 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001738 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001739}
1740
1741/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001742 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001743 * from the run queue. A pointer to the task itself is returned.
1744 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001745static inline struct task *task_delete(struct task *t) {
1746 t->prev->next = t->next;
1747 t->next->prev = t->prev;
1748 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001749}
1750
1751/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001752 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001753 */
1754static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001755 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001756}
1757
willy tarreau5cbea6f2005-12-17 12:48:26 +01001758/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001759 * may be only moved or left where it was, depending on its timing requirements.
1760 * <task> is returned.
1761 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001762struct task *task_queue(struct task *task) {
1763 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001764 struct task *start_from;
1765
willy tarreau5e698ef2006-05-02 14:51:00 +02001766 /* This is a very dirty hack to queue non-expirable tasks in another queue
1767 * in order to avoid pulluting the tail of the standard queue. This will go
1768 * away with the new O(log(n)) scheduler anyway.
1769 */
1770 if (tv_iseternity(&task->expire)) {
1771 /* if the task was queued in the standard wait queue, we must dequeue it */
1772 if (task->prev) {
1773 if (task->wq == LIST_HEAD(wait_queue[1]))
1774 return task;
1775 else {
1776 task_delete(task);
1777 task->prev = NULL;
1778 }
1779 }
1780 list = task->wq = LIST_HEAD(wait_queue[1]);
1781 } else {
1782 /* if the task was queued in the eternity queue, we must dequeue it */
1783 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1784 task_delete(task);
1785 task->prev = NULL;
1786 list = task->wq = LIST_HEAD(wait_queue[0]);
1787 }
1788 }
1789
1790 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001791 if (task->prev == NULL) {
1792 // start_from = list;
1793 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001794#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001795 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001796#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001797 /* insert the unlinked <task> into the list, searching back from the last entry */
1798 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1799 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001800#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001801 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001803 }
1804
1805 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1806 // start_from = start_from->next;
1807 // stats_tsk_nsrch++;
1808 // }
1809 }
1810 else if (task->prev == list ||
1811 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1812 start_from = task->next;
1813 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001814#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001815 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001816#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001817 return task; /* it's already in the right place */
1818 }
1819
willy tarreau750a4722005-12-17 13:21:24 +01001820#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001821 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001822#endif
1823
1824 /* if the task is not at the right place, there's little chance that
1825 * it has only shifted a bit, and it will nearly always be queued
1826 * at the end of the list because of constant timeouts
1827 * (observed in real case).
1828 */
1829#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1830 start_from = list->prev; /* assume we'll queue to the end of the list */
1831 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1832 start_from = start_from->prev;
1833#if STATTIME > 0
1834 stats_tsk_lsrch++;
1835#endif
1836 }
1837#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001838 /* insert the unlinked <task> into the list, searching after position <start_from> */
1839 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1840 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001841#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001842 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001843#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001844 }
willy tarreau750a4722005-12-17 13:21:24 +01001845#endif /* WE_REALLY_... */
1846
willy tarreau0f7af912005-12-17 12:21:26 +01001847 /* we need to unlink it now */
1848 task_delete(task);
1849 }
1850 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001851#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001852 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001853#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001854#ifdef LEFT_TO_TOP /* not very good */
1855 start_from = list;
1856 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1857 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001858#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001859 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001860#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001861 }
1862#else
1863 start_from = task->prev->prev; /* valid because of the previous test above */
1864 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1865 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001866#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001867 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001868#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001869 }
1870#endif
1871 /* we need to unlink it now */
1872 task_delete(task);
1873 }
1874 task->prev = start_from;
1875 task->next = start_from->next;
1876 task->next->prev = task;
1877 start_from->next = task;
1878 return task;
1879}
1880
1881
1882/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001883/* pending connections queues **************************************/
1884/*********************************************************************/
1885
1886/*
willy tarreaudfece232006-05-02 00:19:57 +02001887 * Detaches pending connection <p>, decreases the pending count, and frees
1888 * the pending connection. The connection might have been queued to a specific
1889 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001890 */
willy tarreaudfece232006-05-02 00:19:57 +02001891static void pendconn_free(struct pendconn *p) {
1892 LIST_DEL(&p->list);
1893 p->sess->pend_pos = NULL;
1894 if (p->srv)
1895 p->srv->nbpend--;
1896 else
1897 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001898 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001899 pool_free(pendconn, p);
1900}
1901
1902/* Returns the first pending connection for server <s>, which may be NULL if
1903 * nothing is pending.
1904 */
1905static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001906 if (!s->nbpend)
1907 return NULL;
1908
1909 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1910}
1911
willy tarreaudfece232006-05-02 00:19:57 +02001912/* Returns the first pending connection for proxy <px>, which may be NULL if
1913 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001914 */
willy tarreaudfece232006-05-02 00:19:57 +02001915static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1916 if (!px->nbpend)
1917 return NULL;
1918
1919 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001920}
1921
willy tarreaubc2eda62006-05-04 15:16:23 +02001922/* Detaches the next pending connection from either a server or a proxy, and
1923 * returns its associated session. If no pending connection is found, NULL is
1924 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001925 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001926static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001927 struct pendconn *p;
1928 struct session *sess;
1929
willy tarreaubc2eda62006-05-04 15:16:23 +02001930 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001931 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001932 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001933 if (!p)
1934 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001935 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001936 }
willy tarreau18a957c2006-04-12 19:26:23 +02001937 sess = p->sess;
1938 pendconn_free(p);
1939 return sess;
1940}
1941
willy tarreaudfece232006-05-02 00:19:57 +02001942/* Adds the session <sess> to the pending connection list of server <sess>->srv
1943 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1944 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1945 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001946 */
willy tarreaudfece232006-05-02 00:19:57 +02001947static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001948 struct pendconn *p;
1949
1950 p = pool_alloc(pendconn);
1951 if (!p)
1952 return NULL;
1953
willy tarreau18a957c2006-04-12 19:26:23 +02001954 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001955 p->sess = sess;
1956 p->srv = sess->srv;
1957 if (sess->srv) {
1958 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001959 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001960 sess->srv->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001961 if (sess->srv->nbpend > sess->srv->nbpend_max)
1962 sess->srv->nbpend_max = sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001963 } else {
1964 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001965 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001966 sess->proxy->nbpend++;
willy tarreaucb406512006-05-18 00:52:35 +02001967 if (sess->proxy->nbpend > sess->proxy->nbpend_max)
1968 sess->proxy->nbpend_max = sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001969 }
willy tarreauf32f5242006-05-02 22:54:52 +02001970 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001971 return p;
1972}
1973
willy tarreau59a6cc22006-05-12 01:29:08 +02001974/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1975 * and non-zero otherwise. Suited for and if/else usage.
1976 */
1977static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1978 return (s && (s->nbpend || p->nbpend) &&
1979 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1980}
1981
1982
1983
willy tarreau18a957c2006-04-12 19:26:23 +02001984/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001985/* more specific functions ***************************************/
1986/*********************************************************************/
1987
1988/* some prototypes */
1989static int maintain_proxies(void);
1990
willy tarreaub952e1d2005-12-18 01:31:20 +01001991/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001992 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1993 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001994static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001995#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001996 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1997#else
willy tarreaua1598082005-12-17 13:08:06 +01001998#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001999 return getsockname(fd, (struct sockaddr *)sa, salen);
2000#else
2001 return -1;
2002#endif
2003#endif
2004}
2005
2006/*
2007 * frees the context associated to a session. It must have been removed first.
2008 */
willy tarreaudfece232006-05-02 00:19:57 +02002009static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02002010 if (s->pend_pos)
2011 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012 if (s->req)
2013 pool_free(buffer, s->req);
2014 if (s->rep)
2015 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01002016
2017 if (s->rsp_cap != NULL) {
2018 struct cap_hdr *h;
2019 for (h = s->proxy->rsp_cap; h; h = h->next) {
2020 if (s->rsp_cap[h->index] != NULL)
2021 pool_free_to(h->pool, s->rsp_cap[h->index]);
2022 }
2023 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
2024 }
2025 if (s->req_cap != NULL) {
2026 struct cap_hdr *h;
2027 for (h = s->proxy->req_cap; h; h = h->next) {
2028 if (s->req_cap[h->index] != NULL)
2029 pool_free_to(h->pool, s->req_cap[h->index]);
2030 }
2031 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
2032 }
2033
willy tarreaua1598082005-12-17 13:08:06 +01002034 if (s->logs.uri)
2035 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01002036 if (s->logs.cli_cookie)
2037 pool_free(capture, s->logs.cli_cookie);
2038 if (s->logs.srv_cookie)
2039 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01002040
willy tarreau5cbea6f2005-12-17 12:48:26 +01002041 pool_free(session, s);
2042}
2043
willy tarreau0f7af912005-12-17 12:21:26 +01002044
2045/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01002046 * This function recounts the number of usable active and backup servers for
2047 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002048 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01002049 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002050static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002051 struct server *srv;
2052
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002053 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002054 for (srv = px->srv; srv != NULL; srv = srv->next) {
2055 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002056 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002057 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002058 px->tot_wbck += srv->eweight + 1;
2059 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002060 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002061 px->tot_wact += srv->eweight + 1;
2062 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002063 }
2064 }
2065}
2066
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002067/* This function recomputes the server map for proxy px. It
2068 * relies on px->tot_wact and px->tot_wbck, so it must be
2069 * called after recount_servers(). It also expects px->srv_map
2070 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002071 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002072static void recalc_server_map(struct proxy *px) {
2073 int o, tot, flag;
2074 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002075
willy tarreau4c8c2b52006-03-24 19:36:41 +01002076 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002077 flag = SRV_RUNNING;
2078 tot = px->tot_wact;
2079 } else if (px->srv_bck) {
2080 flag = SRV_RUNNING | SRV_BACKUP;
2081 if (px->options & PR_O_USE_ALL_BK)
2082 tot = px->tot_wbck;
2083 else
2084 tot = 1; /* the first server is enough */
2085 } else {
2086 px->srv_map_sz = 0;
2087 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002088 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002089
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002090 /* this algorithm gives priority to the first server, which means that
2091 * it will respect the declaration order for equivalent weights, and
2092 * that whatever the weights, the first server called will always be
2093 * the first declard. This is an important asumption for the backup
2094 * case, where we want the first server only.
2095 */
2096 for (cur = px->srv; cur; cur = cur->next)
2097 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002098
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002099 for (o = 0; o < tot; o++) {
2100 int max = 0;
2101 best = NULL;
2102 for (cur = px->srv; cur; cur = cur->next) {
2103 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2104 int v;
2105
2106 /* If we are forced to return only one server, we don't want to
2107 * go further, because we would return the wrong one due to
2108 * divide overflow.
2109 */
2110 if (tot == 1) {
2111 best = cur;
2112 break;
2113 }
2114
2115 cur->wscore += cur->eweight + 1;
2116 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2117 if (best == NULL || v > max) {
2118 max = v;
2119 best = cur;
2120 }
2121 }
2122 }
2123 px->srv_map[o] = best;
2124 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002125 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002126 px->srv_map_sz = tot;
2127}
Willy TARREAU3481c462006-03-01 22:37:57 +01002128
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002129/*
willy tarreau898db9d2006-04-12 20:29:08 +02002130 * This function tries to find a running server with free connection slots for
2131 * the proxy <px> following the round-robin method.
2132 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2133 * to point to the next server. If no valid server is found, NULL is returned.
2134 */
2135static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2136 int newidx;
2137 struct server *srv;
2138
2139 if (px->srv_map_sz == 0)
2140 return NULL;
2141
2142 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2143 px->srv_rr_idx = 0;
2144 newidx = px->srv_rr_idx;
2145
2146 do {
2147 srv = px->srv_map[newidx++];
2148 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2149 px->srv_rr_idx = newidx;
2150 return srv;
2151 }
2152 if (newidx == px->srv_map_sz)
2153 newidx = 0;
2154 } while (newidx != px->srv_rr_idx);
2155
2156 return NULL;
2157}
2158
2159
2160/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002161 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002162 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002163 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2164 * to point to the next server. If no valid server is found, NULL is returned.
2165 */
2166static inline struct server *get_server_rr(struct proxy *px) {
2167 if (px->srv_map_sz == 0)
2168 return NULL;
2169
2170 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2171 px->srv_rr_idx = 0;
2172 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002173}
2174
willy tarreau62084d42006-03-24 18:57:41 +01002175
2176/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002177 * This function tries to find a running server for the proxy <px> following
2178 * the source hash method. Depending on the number of active/backup servers,
2179 * it will either look for active servers, or for backup servers.
2180 * If any server is found, it will be returned. If no valid server is found,
2181 * NULL is returned.
2182 */
2183static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002184 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002185
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002186 if (px->srv_map_sz == 0)
2187 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002188
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002189 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002190 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002191 while ((l + sizeof (int)) <= len) {
2192 h ^= ntohl(*(unsigned int *)(&addr[l]));
2193 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002194 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002195 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002196 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002197 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002198}
2199
2200
2201/*
willy tarreaudfece232006-05-02 00:19:57 +02002202 * This function marks the session as 'assigned' in direct or dispatch modes,
2203 * or tries to assign one in balance mode, according to the algorithm. It does
2204 * nothing if the session had already been assigned a server.
2205 *
2206 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002207 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2208 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2209 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002210 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2211 *
2212 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2213 * not need to be called anymore. This usually means that s->srv can be trusted
2214 * in balance and direct modes. This flag is not cleared, so it's to the caller
2215 * to clear it if required (eg: redispatch).
2216 *
willy tarreau0f7af912005-12-17 12:21:26 +01002217 */
willy tarreau0f7af912005-12-17 12:21:26 +01002218
willy tarreaudfece232006-05-02 00:19:57 +02002219int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002220#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002221 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002222#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002223
willy tarreaudfece232006-05-02 00:19:57 +02002224 if (s->pend_pos)
2225 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002226
willy tarreaudfece232006-05-02 00:19:57 +02002227 if (!(s->flags & SN_ASSIGNED)) {
2228 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2229 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2230 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002231
willy tarreaudfece232006-05-02 00:19:57 +02002232 if (s->proxy->options & PR_O_BALANCE_RR) {
2233 s->srv = get_server_rr_with_conns(s->proxy);
2234 if (!s->srv)
2235 return SRV_STATUS_FULL;
2236 }
2237 else if (s->proxy->options & PR_O_BALANCE_SH) {
2238 int len;
2239
2240 if (s->cli_addr.ss_family == AF_INET)
2241 len = 4;
2242 else if (s->cli_addr.ss_family == AF_INET6)
2243 len = 16;
2244 else /* unknown IP family */
2245 return SRV_STATUS_INTERNAL;
2246
2247 s->srv = get_server_sh(s->proxy,
2248 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2249 len);
2250 }
2251 else /* unknown balancing algorithm */
2252 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002253 }
willy tarreaudfece232006-05-02 00:19:57 +02002254 s->flags |= SN_ASSIGNED;
2255 }
2256 return SRV_STATUS_OK;
2257}
willy tarreau1a3442d2006-03-24 21:03:20 +01002258
willy tarreaudfece232006-05-02 00:19:57 +02002259/*
2260 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2261 * The address is taken from the currently assigned server, or from the
2262 * dispatch or transparent address.
2263 *
2264 * It may return :
2265 * SRV_STATUS_OK if everything is OK.
2266 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2267 *
2268 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2269 * not cleared, so it's to the caller to clear it if required.
2270 *
2271 */
2272int assign_server_address(struct session *s) {
2273#ifdef DEBUG_FULL
2274 fprintf(stderr,"assign_server_address : s=%p\n",s);
2275#endif
2276
2277 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2278 /* A server is necessarily known for this session */
2279 if (!(s->flags & SN_ASSIGNED))
2280 return SRV_STATUS_INTERNAL;
2281
2282 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002283
willy tarreaudfece232006-05-02 00:19:57 +02002284 /* if this server remaps proxied ports, we'll use
2285 * the port the client connected to with an offset. */
2286 if (s->srv->state & SRV_MAPPORTS) {
2287 struct sockaddr_in sockname;
2288 socklen_t namelen = sizeof(sockname);
2289
2290 if (!(s->proxy->options & PR_O_TRANSP) ||
2291 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2292 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2293 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002294 }
willy tarreau0f7af912005-12-17 12:21:26 +01002295 }
willy tarreaua1598082005-12-17 13:08:06 +01002296 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002297 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002298 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002299 }
2300 else if (s->proxy->options & PR_O_TRANSP) {
2301 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002302 socklen_t salen = sizeof(s->srv_addr);
2303
willy tarreau5cbea6f2005-12-17 12:48:26 +01002304 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2305 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002306 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002307 }
2308 }
willy tarreau0f7af912005-12-17 12:21:26 +01002309
willy tarreaudfece232006-05-02 00:19:57 +02002310 s->flags |= SN_ADDR_SET;
2311 return SRV_STATUS_OK;
2312}
willy tarreaua41a8b42005-12-17 14:02:24 +01002313
willy tarreaudfece232006-05-02 00:19:57 +02002314/* This function assigns a server to session <s> if required, and can add the
2315 * connection to either the assigned server's queue or to the proxy's queue.
2316 *
2317 * Returns :
2318 *
2319 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002320 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002321 * SRV_STATUS_QUEUED if the connection has been queued.
2322 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2323 * connection could not be queued.
2324 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2325 *
2326 */
2327int assign_server_and_queue(struct session *s) {
2328 struct pendconn *p;
2329 int err;
2330
2331 if (s->pend_pos)
2332 return SRV_STATUS_INTERNAL;
2333
2334 if (s->flags & SN_ASSIGNED) {
2335 /* a server does not need to be assigned, perhaps because we're in
2336 * direct mode, or in dispatch or transparent modes where the server
2337 * is not needed.
2338 */
2339 if (s->srv &&
2340 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2341 p = pendconn_add(s);
2342 if (p)
2343 return SRV_STATUS_QUEUED;
2344 else
2345 return SRV_STATUS_FULL;
2346 }
2347 return SRV_STATUS_OK;
2348 }
2349
2350 /* a server needs to be assigned */
2351 err = assign_server(s);
2352 switch (err) {
2353 case SRV_STATUS_OK:
2354 /* in balance mode, we might have servers with connection limits */
2355 if (s->srv != NULL &&
2356 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2357 p = pendconn_add(s);
2358 if (p)
2359 return SRV_STATUS_QUEUED;
2360 else
2361 return SRV_STATUS_FULL;
2362 }
2363 return SRV_STATUS_OK;
2364
2365 case SRV_STATUS_FULL:
2366 /* queue this session into the proxy's queue */
2367 p = pendconn_add(s);
2368 if (p)
2369 return SRV_STATUS_QUEUED;
2370 else
2371 return SRV_STATUS_FULL;
2372
2373 case SRV_STATUS_NOSRV:
2374 case SRV_STATUS_INTERNAL:
2375 return err;
2376 default:
2377 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002378 }
willy tarreaudfece232006-05-02 00:19:57 +02002379}
2380
2381
2382/*
2383 * This function initiates a connection to the server assigned to this session
2384 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2385 * It can return one of :
2386 * - SN_ERR_NONE if everything's OK
2387 * - SN_ERR_SRVTO if there are no more servers
2388 * - SN_ERR_SRVCL if the connection was refused by the server
2389 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2390 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2391 * - SN_ERR_INTERNAL for any other purely internal errors
2392 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2393 */
2394int connect_server(struct session *s) {
2395 int fd, err;
2396
2397 if (!(s->flags & SN_ADDR_SET)) {
2398 err = assign_server_address(s);
2399 if (err != SRV_STATUS_OK)
2400 return SN_ERR_INTERNAL;
2401 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002402
willy tarreau0f7af912005-12-17 12:21:26 +01002403 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002404 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002405
2406 if (errno == ENFILE)
2407 send_log(s->proxy, LOG_EMERG,
2408 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2409 s->proxy->id, maxfd);
2410 else if (errno == EMFILE)
2411 send_log(s->proxy, LOG_EMERG,
2412 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2413 s->proxy->id, maxfd);
2414 else if (errno == ENOBUFS || errno == ENOMEM)
2415 send_log(s->proxy, LOG_EMERG,
2416 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2417 s->proxy->id, maxfd);
2418 /* this is a resource error */
2419 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002420 }
2421
willy tarreau9fe663a2005-12-17 13:02:59 +01002422 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002423 /* do not log anything there, it's a normal condition when this option
2424 * is used to serialize connections to a server !
2425 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002426 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2427 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002428 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002429 }
2430
willy tarreau0f7af912005-12-17 12:21:26 +01002431 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2432 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002433 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002434 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002435 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002436 }
2437
willy tarreaub952e1d2005-12-18 01:31:20 +01002438 if (s->proxy->options & PR_O_TCP_SRV_KA)
2439 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2440
willy tarreau0174f312005-12-18 01:02:42 +01002441 /* allow specific binding :
2442 * - server-specific at first
2443 * - proxy-specific next
2444 */
2445 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2446 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2447 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2448 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2449 s->proxy->id, s->srv->id);
2450 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002451 send_log(s->proxy, LOG_EMERG,
2452 "Cannot bind to source address before connect() for server %s/%s.\n",
2453 s->proxy->id, s->srv->id);
2454 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002455 }
2456 }
2457 else if (s->proxy->options & PR_O_BIND_SRC) {
2458 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2459 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2460 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2461 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002462 send_log(s->proxy, LOG_EMERG,
2463 "Cannot bind to source address before connect() for server %s/%s.\n",
2464 s->proxy->id, s->srv->id);
2465 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002466 }
willy tarreaua1598082005-12-17 13:08:06 +01002467 }
2468
willy tarreaub1285d52005-12-18 01:20:14 +01002469 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2470 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2471
2472 if (errno == EAGAIN || errno == EADDRINUSE) {
2473 char *msg;
2474 if (errno == EAGAIN) /* no free ports left, try again later */
2475 msg = "no free ports";
2476 else
2477 msg = "local address already in use";
2478
2479 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002480 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002481 send_log(s->proxy, LOG_EMERG,
2482 "Connect() failed for server %s/%s: %s.\n",
2483 s->proxy->id, s->srv->id, msg);
2484 return SN_ERR_RESOURCE;
2485 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002486 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002487 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002488 return SN_ERR_SRVTO;
2489 } else {
2490 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002491 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002492 close(fd);
2493 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002494 }
2495 }
2496
willy tarreau5cbea6f2005-12-17 12:48:26 +01002497 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002498 fdtab[fd].read = &event_srv_read;
2499 fdtab[fd].write = &event_srv_write;
2500 fdtab[fd].state = FD_STCONN; /* connection in progress */
2501
2502 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002503#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2504 if (PrevReadEvent) {
2505 assert(!(FD_ISSET(fd, PrevReadEvent)));
2506 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2507 }
2508#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002509
2510 fd_insert(fd);
willy tarreaucb406512006-05-18 00:52:35 +02002511 if (s->srv) {
willy tarreau926a3572006-05-01 15:26:35 +02002512 s->srv->cur_sess++;
willy tarreaucb406512006-05-18 00:52:35 +02002513 if (s->srv->cur_sess > s->srv->cur_sess_max)
2514 s->srv->cur_sess_max = s->srv->cur_sess;
2515 }
willy tarreau0f7af912005-12-17 12:21:26 +01002516
2517 if (s->proxy->contimeout)
2518 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2519 else
2520 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002521 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002522}
2523
2524/*
2525 * this function is called on a read event from a client socket.
2526 * It returns 0.
2527 */
2528int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002529 struct task *t = fdtab[fd].owner;
2530 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002531 struct buffer *b = s->req;
2532 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002533
willy tarreau12350152005-12-18 01:03:27 +01002534#ifdef DEBUG_FULL
2535 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2536#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002537
willy tarreau0f7af912005-12-17 12:21:26 +01002538 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002539#ifdef FILL_BUFFERS
2540 while (1)
2541#else
2542 do
2543#endif
2544 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002545 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2546 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002547 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002548 }
2549 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002550 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 }
2552 else {
2553 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002554 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2555 * since it means that the rewrite protection has been removed. This
2556 * implies that the if statement can be removed.
2557 */
2558 if (max > b->rlim - b->data)
2559 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002560 }
2561
2562 if (max == 0) { /* not anymore room to store data */
2563 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002564 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002565 }
2566
willy tarreau3242e862005-12-17 12:27:53 +01002567#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002568 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002569 int skerr;
2570 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002571
willy tarreau5cbea6f2005-12-17 12:48:26 +01002572 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2573 if (skerr)
2574 ret = -1;
2575 else
2576 ret = recv(fd, b->r, max, 0);
2577 }
willy tarreau3242e862005-12-17 12:27:53 +01002578#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002579 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002580#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002581 if (ret > 0) {
2582 b->r += ret;
2583 b->l += ret;
2584 s->res_cr = RES_DATA;
2585
2586 if (b->r == b->data + BUFSIZE) {
2587 b->r = b->data; /* wrap around the buffer */
2588 }
willy tarreaua1598082005-12-17 13:08:06 +01002589
2590 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002591 /* we hope to read more data or to get a close on next round */
2592 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002593 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594 else if (ret == 0) {
2595 s->res_cr = RES_NULL;
2596 break;
2597 }
2598 else if (errno == EAGAIN) {/* ignore EAGAIN */
2599 break;
2600 }
2601 else {
2602 s->res_cr = RES_ERROR;
2603 fdtab[fd].state = FD_STERROR;
2604 break;
2605 }
2606 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002607#ifndef FILL_BUFFERS
2608 while (0);
2609#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002610 }
2611 else {
2612 s->res_cr = RES_ERROR;
2613 fdtab[fd].state = FD_STERROR;
2614 }
2615
willy tarreau5cbea6f2005-12-17 12:48:26 +01002616 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002617 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002618 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2619 else
2620 tv_eternity(&s->crexpire);
2621
2622 task_wakeup(&rq, t);
2623 }
willy tarreau0f7af912005-12-17 12:21:26 +01002624
willy tarreau0f7af912005-12-17 12:21:26 +01002625 return 0;
2626}
2627
2628
2629/*
2630 * this function is called on a read event from a server socket.
2631 * It returns 0.
2632 */
2633int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002634 struct task *t = fdtab[fd].owner;
2635 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002636 struct buffer *b = s->rep;
2637 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002638
willy tarreau12350152005-12-18 01:03:27 +01002639#ifdef DEBUG_FULL
2640 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2641#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002642
willy tarreau0f7af912005-12-17 12:21:26 +01002643 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002644#ifdef FILL_BUFFERS
2645 while (1)
2646#else
2647 do
2648#endif
2649 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002650 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2651 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002652 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002653 }
2654 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002655 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 }
2657 else {
2658 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002659 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2660 * since it means that the rewrite protection has been removed. This
2661 * implies that the if statement can be removed.
2662 */
2663 if (max > b->rlim - b->data)
2664 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002665 }
2666
2667 if (max == 0) { /* not anymore room to store data */
2668 FD_CLR(fd, StaticReadEvent);
2669 break;
2670 }
2671
willy tarreau3242e862005-12-17 12:27:53 +01002672#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002673 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002674 int skerr;
2675 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002676
willy tarreau5cbea6f2005-12-17 12:48:26 +01002677 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2678 if (skerr)
2679 ret = -1;
2680 else
2681 ret = recv(fd, b->r, max, 0);
2682 }
willy tarreau3242e862005-12-17 12:27:53 +01002683#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002684 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002685#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002686 if (ret > 0) {
2687 b->r += ret;
2688 b->l += ret;
2689 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002690
willy tarreau5cbea6f2005-12-17 12:48:26 +01002691 if (b->r == b->data + BUFSIZE) {
2692 b->r = b->data; /* wrap around the buffer */
2693 }
willy tarreaua1598082005-12-17 13:08:06 +01002694
2695 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002696 /* we hope to read more data or to get a close on next round */
2697 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002698 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002699 else if (ret == 0) {
2700 s->res_sr = RES_NULL;
2701 break;
2702 }
2703 else if (errno == EAGAIN) {/* ignore EAGAIN */
2704 break;
2705 }
2706 else {
2707 s->res_sr = RES_ERROR;
2708 fdtab[fd].state = FD_STERROR;
2709 break;
2710 }
2711 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002712#ifndef FILL_BUFFERS
2713 while (0);
2714#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002715 }
2716 else {
2717 s->res_sr = RES_ERROR;
2718 fdtab[fd].state = FD_STERROR;
2719 }
2720
willy tarreau5cbea6f2005-12-17 12:48:26 +01002721 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002722 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002723 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2724 else
2725 tv_eternity(&s->srexpire);
2726
2727 task_wakeup(&rq, t);
2728 }
willy tarreau0f7af912005-12-17 12:21:26 +01002729
willy tarreau0f7af912005-12-17 12:21:26 +01002730 return 0;
2731}
2732
2733/*
2734 * this function is called on a write event from a client socket.
2735 * It returns 0.
2736 */
2737int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002738 struct task *t = fdtab[fd].owner;
2739 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002740 struct buffer *b = s->rep;
2741 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002742
willy tarreau12350152005-12-18 01:03:27 +01002743#ifdef DEBUG_FULL
2744 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2745#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002746
2747 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002748 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002749 // max = BUFSIZE; BUG !!!!
2750 max = 0;
2751 }
2752 else if (b->r > b->w) {
2753 max = b->r - b->w;
2754 }
2755 else
2756 max = b->data + BUFSIZE - b->w;
2757
willy tarreau0f7af912005-12-17 12:21:26 +01002758 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002759 if (max == 0) {
2760 s->res_cw = RES_NULL;
2761 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002762 tv_eternity(&s->cwexpire);
2763 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002764 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002765 }
2766
willy tarreau3242e862005-12-17 12:27:53 +01002767#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002768 {
2769 int skerr;
2770 socklen_t lskerr = sizeof(skerr);
2771
2772 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2773 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002774 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002775 else
willy tarreau3242e862005-12-17 12:27:53 +01002776 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002777 }
willy tarreau3242e862005-12-17 12:27:53 +01002778#else
willy tarreau0f7af912005-12-17 12:21:26 +01002779 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002780#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002781
2782 if (ret > 0) {
2783 b->l -= ret;
2784 b->w += ret;
2785
2786 s->res_cw = RES_DATA;
2787
2788 if (b->w == b->data + BUFSIZE) {
2789 b->w = b->data; /* wrap around the buffer */
2790 }
2791 }
2792 else if (ret == 0) {
2793 /* nothing written, just make as if we were never called */
2794// s->res_cw = RES_NULL;
2795 return 0;
2796 }
2797 else if (errno == EAGAIN) /* ignore EAGAIN */
2798 return 0;
2799 else {
2800 s->res_cw = RES_ERROR;
2801 fdtab[fd].state = FD_STERROR;
2802 }
2803 }
2804 else {
2805 s->res_cw = RES_ERROR;
2806 fdtab[fd].state = FD_STERROR;
2807 }
2808
willy tarreaub1ff9db2005-12-17 13:51:03 +01002809 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002810 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002811 /* FIXME: to prevent the client from expiring read timeouts during writes,
2812 * we refresh it. A solution would be to merge read+write timeouts into a
2813 * unique one, although that needs some study particularly on full-duplex
2814 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002815 s->crexpire = s->cwexpire;
2816 }
willy tarreau0f7af912005-12-17 12:21:26 +01002817 else
2818 tv_eternity(&s->cwexpire);
2819
willy tarreau5cbea6f2005-12-17 12:48:26 +01002820 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002821 return 0;
2822}
2823
2824
2825/*
2826 * this function is called on a write event from a server socket.
2827 * It returns 0.
2828 */
2829int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002830 struct task *t = fdtab[fd].owner;
2831 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002832 struct buffer *b = s->req;
2833 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002834
willy tarreau12350152005-12-18 01:03:27 +01002835#ifdef DEBUG_FULL
2836 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2837#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002838
2839 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002840 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002841 // max = BUFSIZE; BUG !!!!
2842 max = 0;
2843 }
2844 else if (b->r > b->w) {
2845 max = b->r - b->w;
2846 }
2847 else
2848 max = b->data + BUFSIZE - b->w;
2849
willy tarreau0f7af912005-12-17 12:21:26 +01002850 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002851 if (max == 0) {
2852 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002853 if (s->srv_state == SV_STCONN) {
2854 int skerr;
2855 socklen_t lskerr = sizeof(skerr);
2856 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2857 if (skerr) {
2858 s->res_sw = RES_ERROR;
2859 fdtab[fd].state = FD_STERROR;
2860 task_wakeup(&rq, t);
2861 tv_eternity(&s->swexpire);
2862 FD_CLR(fd, StaticWriteEvent);
2863 return 0;
2864 }
2865 }
2866
willy tarreau0f7af912005-12-17 12:21:26 +01002867 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002868 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002869 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002870 tv_eternity(&s->swexpire);
2871 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002872 return 0;
2873 }
2874
willy tarreau3242e862005-12-17 12:27:53 +01002875#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002876 {
2877 int skerr;
2878 socklen_t lskerr = sizeof(skerr);
2879 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2880 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002881 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002882 else
willy tarreau3242e862005-12-17 12:27:53 +01002883 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002884 }
willy tarreau3242e862005-12-17 12:27:53 +01002885#else
willy tarreau0f7af912005-12-17 12:21:26 +01002886 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002887#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002888 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002889 if (ret > 0) {
2890 b->l -= ret;
2891 b->w += ret;
2892
2893 s->res_sw = RES_DATA;
2894
2895 if (b->w == b->data + BUFSIZE) {
2896 b->w = b->data; /* wrap around the buffer */
2897 }
2898 }
2899 else if (ret == 0) {
2900 /* nothing written, just make as if we were never called */
2901 // s->res_sw = RES_NULL;
2902 return 0;
2903 }
2904 else if (errno == EAGAIN) /* ignore EAGAIN */
2905 return 0;
2906 else {
2907 s->res_sw = RES_ERROR;
2908 fdtab[fd].state = FD_STERROR;
2909 }
2910 }
2911 else {
2912 s->res_sw = RES_ERROR;
2913 fdtab[fd].state = FD_STERROR;
2914 }
2915
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002916 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2917 * otherwise it could loop indefinitely !
2918 */
2919 if (s->srv_state != SV_STCONN) {
2920 if (s->proxy->srvtimeout) {
2921 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002922 /* FIXME: to prevent the server from expiring read timeouts during writes,
2923 * we refresh it. A solution would be to merge read+write+connect timeouts
2924 * into a unique one since we don't mind expiring on read or write, and none
2925 * of them is enabled while waiting for connect(), although that needs some
2926 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002927 s->srexpire = s->swexpire;
2928 }
2929 else
2930 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002931 }
willy tarreau0f7af912005-12-17 12:21:26 +01002932
willy tarreau5cbea6f2005-12-17 12:48:26 +01002933 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002934 return 0;
2935}
2936
2937
willy tarreaue0331262006-05-15 03:02:46 +02002938/* returns 1 if the buffer is empty, 0 otherwise */
2939static inline int buffer_isempty(struct buffer *buf) {
2940 return buf->l == 0;
2941}
2942
2943
2944/* returns 1 if the buffer is full, 0 otherwise */
2945static inline int buffer_isfull(struct buffer *buf) {
2946 return buf->l == BUFSIZE;
2947}
2948
2949
2950/* flushes any content from buffer <buf> */
2951void buffer_flush(struct buffer *buf) {
2952 buf->r = buf->h = buf->lr = buf->w = buf->data;
2953 buf->l = 0;
2954}
2955
2956
2957/* returns the maximum number of bytes writable at once in this buffer */
2958int buffer_max(struct buffer *buf) {
willy tarreaucb406512006-05-18 00:52:35 +02002959 if (buf->l == BUFSIZE)
2960 return 0;
2961 else if (buf->r >= buf->w)
willy tarreaue0331262006-05-15 03:02:46 +02002962 return buf->data + BUFSIZE - buf->r;
2963 else
2964 return buf->w - buf->r;
2965}
2966
2967
willy tarreau0f7af912005-12-17 12:21:26 +01002968/*
willy tarreaue0331262006-05-15 03:02:46 +02002969 * Tries to realign the given buffer, and returns how many bytes can be written
2970 * there at once without overwriting anything.
2971 */
2972int buffer_realign(struct buffer *buf) {
2973 if (buf->l == 0) {
2974 /* let's realign the buffer to optimize I/O */
willy tarreaucb406512006-05-18 00:52:35 +02002975 buf->r = buf->w = buf->h = buf->lr = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02002976 }
2977 return buffer_max(buf);
2978}
2979
2980
2981/* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of
2982 * success, or the number of bytes available otherwise.
2983 */
2984int buffer_write(struct buffer *buf, const char *msg, int len) {
2985 int max;
2986
willy tarreaucb406512006-05-18 00:52:35 +02002987 max = buffer_realign(buf);
willy tarreaue0331262006-05-15 03:02:46 +02002988
2989 if (len > max)
2990 return max;
2991
2992 memcpy(buf->r, msg, len);
2993 buf->l += len;
2994 buf->r += len;
2995 if (buf->r == buf->data + BUFSIZE)
willy tarreaucb406512006-05-18 00:52:35 +02002996 buf->r = buf->data;
willy tarreaue0331262006-05-15 03:02:46 +02002997 return 0;
2998}
2999
3000
3001/*
willy tarreaue39cd132005-12-17 13:00:18 +01003002 * returns a message to the client ; the connection is shut down for read,
3003 * and the request is cleared so that no server connection can be initiated.
3004 * The client must be in a valid state for this (HEADER, DATA ...).
3005 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01003006 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003007 */
3008void client_retnclose(struct session *s, int len, const char *msg) {
3009 FD_CLR(s->cli_fd, StaticReadEvent);
3010 FD_SET(s->cli_fd, StaticWriteEvent);
3011 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01003012 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01003013 shutdown(s->cli_fd, SHUT_RD);
3014 s->cli_state = CL_STSHUTR;
willy tarreaue0331262006-05-15 03:02:46 +02003015 buffer_flush(s->rep);
3016 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003017 s->req->l = 0;
3018}
3019
3020
3021/*
3022 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01003023 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01003024 */
3025void client_return(struct session *s, int len, const char *msg) {
willy tarreaue0331262006-05-15 03:02:46 +02003026 buffer_flush(s->rep);
3027 buffer_write(s->rep, msg, len);
willy tarreaue39cd132005-12-17 13:00:18 +01003028 s->req->l = 0;
3029}
3030
willy tarreaue0331262006-05-15 03:02:46 +02003031/*
3032 * Produces data for the session <s> depending on its source. Expects to be
3033 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3034 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3035 * session, which it uses to keep on being called when there is free space in
3036 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3037 * if it changes the session state from CL_STSHUTR, otherwise 0.
3038 */
3039int produce_content(struct session *s) {
3040 struct buffer *rep = s->rep;
3041 struct proxy *px;
3042 struct server *sv;
willy tarreaucb406512006-05-18 00:52:35 +02003043 int msglen;
willy tarreaue0331262006-05-15 03:02:46 +02003044 unsigned int up;
willy tarreaucb406512006-05-18 00:52:35 +02003045 int failed_checks, down_trans;
willy tarreaue0331262006-05-15 03:02:46 +02003046
3047 if (s->data_source == DATA_SRC_NONE) {
3048 s->flags &= ~SN_SELF_GEN;
3049 return 1;
3050 }
3051 else if (s->data_source == DATA_SRC_STATS) {
willy tarreaucb406512006-05-18 00:52:35 +02003052 if (s->data_ctx.stats.px == NULL) { /* initialized to NULL at session creation */
willy tarreaue0331262006-05-15 03:02:46 +02003053 /* the proxy was not known, the function had not been called yet */
3054
3055 s->flags |= SN_SELF_GEN; // more data will follow
3056 msglen = sprintf(trash,
3057 "HTTP/1.0 200 OK\r\n"
3058 "Cache-Control: no-cache\r\n"
3059 "Connection: close\r\n"
3060 "\r\n\r\n");
3061
3062 s->logs.status = 200;
3063 client_retnclose(s, msglen, trash); // send the start of the response.
3064 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3065 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3066 if (!(s->flags & SN_FINST_MASK))
3067 s->flags |= SN_FINST_R;
3068
3069 /* WARNING! This must fit in the first buffer !!! */
3070 msglen = snprintf(trash, sizeof(trash),
3071 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3072 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3073 "<style type=\"text/css\"><!--\n"
3074 "body {"
3075 " font-family: helvetica, arial;"
3076 " font-size: 12px;"
3077 " font-weight: normal;"
3078 " color: black;"
3079 " background: white;"
3080 "}\n"
3081 "td {"
3082 " font-size: 12px;"
willy tarreaucb406512006-05-18 00:52:35 +02003083 " align: center;"
willy tarreaue0331262006-05-15 03:02:46 +02003084 "}\n"
3085 "h1 {"
3086 " font-size: xx-large;"
3087 " margin-bottom: 0.5em;"
3088 "}\n"
3089 "h2 {"
3090 " font-family: helvetica, arial;"
3091 " font-size: x-large;"
3092 " font-weight: bold;"
3093 " font-style: italic;"
3094 " color: #6020a0;"
3095 " margin-top: 0em;"
3096 " margin-bottom: 0em;"
3097 "}\n"
3098 "h3 {"
3099 " font-family: helvetica, arial;"
3100 " font-size: 16px;"
3101 " font-weight: bold;"
3102 " color: #b00040;"
3103 " background: #e8e8d0;"
3104 " margin-top: 0em;"
3105 " margin-bottom: 0em;"
3106 "}\n"
3107 "li {"
3108 " margin-top: 0.25em;"
3109 " margin-right: 2em;"
3110 "}\n"
3111 ".hr {"
3112 " margin-top: 0.25em;"
3113 " border-color: black;"
3114 " border-bottom-style: solid;"
willy tarreaucb406512006-05-18 00:52:35 +02003115 "}\n"
3116 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
3117 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3118 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
3119 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3120 "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 +02003121 "-->"
3122 "</style></head>");
3123
willy tarreaucb406512006-05-18 00:52:35 +02003124 if (buffer_write(rep, trash, msglen) != 0)
3125 return 0;
willy tarreaue0331262006-05-15 03:02:46 +02003126
3127 up = (now.tv_sec - start_date.tv_sec);
3128
3129 /* WARNING! this has to fit the first packet too */
3130 msglen = snprintf(trash, sizeof(trash),
3131 "<body><h1>" PRODUCT_NAME "</h1>\n"
3132 "<h2>Statistics Report for pid %d</h2>\n"
3133 "<hr width=\"100%%\" class=\"hr\">\n"
3134 "<h3>&gt; General process informations</h3>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003135 "<table border=0><tr><td align=\"left\">\n"
willy tarreaue0331262006-05-15 03:02:46 +02003136 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3137 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
3138 "<b>system limits :</b> memmax = %d Megs ; ulimit-n = %d<br>\n"
3139 "<b>maxsock = </b> %d<br>\n"
3140 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
willy tarreaucb406512006-05-18 00:52:35 +02003141 "</td><td width=\"10%%\">\n"
3142 "</td><td align=\"right\">\n"
3143 "<table class=\"lgd\">"
3144 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
3145 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
3146 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
3147 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
3148 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
3149 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
3150 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
3151 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
3152 "</table>\n"
3153 "</tr></table>\n"
willy tarreaue0331262006-05-15 03:02:46 +02003154 "",
3155 pid, pid, global.nbproc,
3156 up / 86400, (up % 86400) / 3600,
3157 (up % 3600) / 60, (up % 60),
3158 global.rlimit_memmax,
3159 global.rlimit_nofile,
3160 global.maxsock,
3161 global.maxconn,
3162 actconn
3163 );
willy tarreaucb406512006-05-18 00:52:35 +02003164
3165 if (buffer_write(rep, trash, msglen) != 0)
3166 return 0;
willy tarreaue0331262006-05-15 03:02:46 +02003167 px = s->data_ctx.stats.px = proxy;
3168 }
3169
3170 while (s->data_ctx.stats.px) {
willy tarreaucb406512006-05-18 00:52:35 +02003171 int dispatch_sess, dispatch_cum;
3172
3173 /* if sv == NULL, this is because we are on a new proxy :
3174 * initialized to NULL at session creation
3175 */
willy tarreaue0331262006-05-15 03:02:46 +02003176 while (s->data_ctx.stats.sv == NULL) {
3177 px = s->data_ctx.stats.px;
3178 msglen = snprintf(trash, sizeof(trash),
3179 "<h3>&gt; Proxy instance %s : "
3180 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
3181 "",
3182 px->id,
3183 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
3184
3185 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaucb406512006-05-18 00:52:35 +02003186 "<table cols=\"13\" class=\"tbl\">\n"
3187 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3188 "<th colspan=5>Server</th>"
3189 "<th colspan=2>Queue</th>"
3190 "<th colspan=4>Sessions</th>"
3191 "<th colspan=2>Checks</th></tr>\n"
3192 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
3193 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
3194 "<th>Curr.</th><th>Max.</th>"
3195 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
3196 "<th>Failed</th><th>Fatal</th></tr>\n");
willy tarreaue0331262006-05-15 03:02:46 +02003197
3198 if (buffer_write(rep, trash, msglen) != 0)
3199 return 0;
3200 s->data_ctx.stats.sv = px->srv;
3201 }
3202
willy tarreaucb406512006-05-18 00:52:35 +02003203 px = s->data_ctx.stats.px;
3204
3205 dispatch_sess = px->nbconn;
3206 dispatch_cum = px->cum_conn;
3207 failed_checks = down_trans = 0;
willy tarreaue0331262006-05-15 03:02:46 +02003208 while (s->data_ctx.stats.sv != NULL) {
willy tarreaucb406512006-05-18 00:52:35 +02003209 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
3210 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
3211 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3212 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
3213
willy tarreaue0331262006-05-15 03:02:46 +02003214 px = s->data_ctx.stats.px;
3215 sv = s->data_ctx.stats.sv;
willy tarreaucb406512006-05-18 00:52:35 +02003216
3217 dispatch_sess -= sv->cur_sess;
3218 dispatch_cum -= sv->cum_sess;
3219
3220 failed_checks += sv->failed_checks;
3221 down_trans += sv->down_trans;
3222
3223 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3224 if (!(sv->state & SRV_CHECKED))
3225 sv_state = 4;
3226 else if (sv->state & SRV_RUNNING)
3227 if (sv->health == sv->rise + sv->fall - 1)
3228 sv_state = 3; /* UP */
3229 else
3230 sv_state = 2; /* going down */
3231 else
3232 if (sv->health)
3233 sv_state = 1; /* going up */
3234 else
3235 sv_state = 0; /* DOWN */
3236
3237 /* name, weight */
willy tarreaue0331262006-05-15 03:02:46 +02003238 msglen = snprintf(trash, sizeof(trash),
willy tarreaucb406512006-05-18 00:52:35 +02003239 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
3240 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
3241 sv->id, sv->uweight+1);
3242 /* status */
3243 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
3244 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3245 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3246
3247 /* act, bck */
3248 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3249 "</td><td>%s</td><td>%s</td>",
willy tarreaue0331262006-05-15 03:02:46 +02003250 (sv->state & SRV_BACKUP) ? "-" : "Y",
3251 (sv->state & SRV_BACKUP) ? "Y" : "-");
willy tarreaucb406512006-05-18 00:52:35 +02003252
3253 /* queue : current, max */
3254 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3255 "<td align=right>%d</td><td align=right>%d</td>",
3256 sv->nbpend, sv->nbpend_max);
3257
3258 /* sessions : current, max, limit, cumul */
3259 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3260 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
3261 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
3262
3263 /* failures : unique, fatal */
3264 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3265 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3266 sv->failed_checks, sv->down_trans);
3267
willy tarreaue0331262006-05-15 03:02:46 +02003268 sv = sv->next;
3269 if (!sv) {
willy tarreaucb406512006-05-18 00:52:35 +02003270 /* first, write informations about the dispatcher */
3271 /* name, weight, status, act, bck */
3272 msglen += snprintf(trash + msglen, sizeof(trash),
3273 "<tr align=center bgcolor=\"#e8e8d0\">"
3274 "<td>Dispatcher</td><td>-</td>"
3275 "<td>%s</td><td>-</td><td>-</td>",
3276 px->state == PR_STRUN ? "UP" : "DOWN");
3277
3278 /* queue : current, max */
willy tarreaue0331262006-05-15 03:02:46 +02003279 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
willy tarreaucb406512006-05-18 00:52:35 +02003280 "<td align=right>%d</td><td align=right>%d</td>",
3281 px->nbpend, px->nbpend_max);
3282
3283 /* sessions : current, max, limit, cumul */
3284 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3285 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
3286 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
3287
3288 /* failures : unique, fatal */
3289 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3290 "<td align=right>-</td><td align=right>-</td></tr>\n");
3291
3292
3293 /* now the summary for the proxy */
3294 /* name, weight, status, act, bck */
3295 msglen += snprintf(trash + msglen, sizeof(trash),
3296 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3297 "<td><b>Total</b></td><td>-</td>"
3298 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3299 (px->state == PR_STRUN && (px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3300 px->srv_act, px->srv_bck);
3301
3302 /* queue : current, max */
3303 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3304 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3305 px->totpend, px->nbpend_max);
3306
3307 /* sessions : current, max, limit, cumul */
3308 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3309 "<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>",
3310 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
3311
3312 /* failures : unique, fatal */
3313 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
3314 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3315 failed_checks, down_trans);
3316
3317 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
3318
willy tarreaue0331262006-05-15 03:02:46 +02003319 px = px->next;
willy tarreaucb406512006-05-18 00:52:35 +02003320 /* the server loop will automatically detect the NULL */
willy tarreaue0331262006-05-15 03:02:46 +02003321 }
3322
3323 if (buffer_write(rep, trash, msglen) != 0)
3324 return 0;
3325 s->data_ctx.stats.sv = sv;
3326 s->data_ctx.stats.px = px;
willy tarreaucb406512006-05-18 00:52:35 +02003327 } /* server loop */
3328 } /* proxy loop */
willy tarreaue0331262006-05-15 03:02:46 +02003329 /* here, we just have reached the sv == NULL and px == NULL */
3330 s->flags &= ~SN_SELF_GEN;
3331 return 1;
3332 }
3333 else {
3334 /* unknown data source */
3335 s->logs.status = 500;
3336 client_retnclose(s, s->proxy->errmsg.len500, s->proxy->errmsg.msg500);
3337 if (!(s->flags & SN_ERR_MASK))
3338 s->flags |= SN_ERR_PRXCOND;
3339 if (!(s->flags & SN_FINST_MASK))
3340 s->flags |= SN_FINST_R;
3341 s->flags &= SN_SELF_GEN;
3342 return 1;
3343 }
3344}
3345
3346
willy tarreau9fe663a2005-12-17 13:02:59 +01003347/*
3348 * send a log for the session when we have enough info about it
3349 */
3350void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003351 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01003352 struct proxy *p = s->proxy;
3353 int log;
3354 char *uri;
3355 char *pxid;
3356 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01003357 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01003358
3359 /* This is a first attempt at a better logging system.
3360 * For now, we rely on send_log() to provide the date, although it obviously
3361 * is the date of the log and not of the request, and most fields are not
3362 * computed.
3363 */
3364
willy tarreaua1598082005-12-17 13:08:06 +01003365 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01003366
willy tarreau8a86dbf2005-12-18 00:45:59 +01003367 if (s->cli_addr.ss_family == AF_INET)
3368 inet_ntop(AF_INET,
3369 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3370 pn, sizeof(pn));
3371 else
3372 inet_ntop(AF_INET6,
3373 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3374 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01003375
willy tarreauc1cae632005-12-17 14:12:23 +01003376 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01003377 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01003378 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01003379
willy tarreauc1cae632005-12-17 14:12:23 +01003380 tm = localtime(&s->logs.tv_accept.tv_sec);
3381 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01003382 char tmpline[MAX_SYSLOG_LEN], *h;
3383 int hdr;
3384
3385 h = tmpline;
3386 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
3387 *(h++) = ' ';
3388 *(h++) = '{';
3389 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
3390 if (hdr)
3391 *(h++) = '|';
3392 if (s->req_cap[hdr] != NULL)
3393 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
3394 }
3395 *(h++) = '}';
3396 }
3397
3398 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
3399 *(h++) = ' ';
3400 *(h++) = '{';
3401 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
3402 if (hdr)
3403 *(h++) = '|';
3404 if (s->rsp_cap[hdr] != NULL)
3405 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
3406 }
3407 *(h++) = '}';
3408 }
3409
3410 if (h < tmpline + sizeof(tmpline) - 4) {
3411 *(h++) = ' ';
3412 *(h++) = '"';
3413 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
3414 *(h++) = '"';
3415 }
3416 *h = '\0';
3417
willy tarreau5e69b162006-05-12 19:49:37 +02003418 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 +01003419 pn,
3420 (s->cli_addr.ss_family == AF_INET) ?
3421 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3422 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01003423 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3424 tm->tm_hour, tm->tm_min, tm->tm_sec,
3425 pxid, srv,
3426 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02003427 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
3428 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01003429 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003430 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3431 s->logs.status,
3432 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01003433 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
3434 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01003435 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
3436 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
3437 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
3438 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02003439 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3440 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003441 }
3442 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003443 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 +01003444 pn,
3445 (s->cli_addr.ss_family == AF_INET) ?
3446 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3447 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003448 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3449 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003450 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003451 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3452 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003453 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3454 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003455 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003456 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003457 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3458 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003459 }
3460
3461 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003462}
3463
willy tarreaue39cd132005-12-17 13:00:18 +01003464
3465/*
willy tarreau0f7af912005-12-17 12:21:26 +01003466 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003467 * to an accept. It tries to accept as many connections as possible.
3468 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003469 */
3470int event_accept(int fd) {
3471 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003472 struct session *s;
3473 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003474 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003475 int max_accept;
3476
3477 if (global.nbproc > 1)
3478 max_accept = 8; /* let other processes catch some connections too */
3479 else
3480 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003481
willy tarreauc2becdc2006-03-19 19:36:48 +01003482 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003483 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003484 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003485
willy tarreaub1285d52005-12-18 01:20:14 +01003486 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3487 switch (errno) {
3488 case EAGAIN:
3489 case EINTR:
3490 case ECONNABORTED:
3491 return 0; /* nothing more to accept */
3492 case ENFILE:
3493 send_log(p, LOG_EMERG,
3494 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3495 p->id, maxfd);
3496 return 0;
3497 case EMFILE:
3498 send_log(p, LOG_EMERG,
3499 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3500 p->id, maxfd);
3501 return 0;
3502 case ENOBUFS:
3503 case ENOMEM:
3504 send_log(p, LOG_EMERG,
3505 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3506 p->id, maxfd);
3507 return 0;
3508 default:
3509 return 0;
3510 }
3511 }
willy tarreau0f7af912005-12-17 12:21:26 +01003512
willy tarreau5cbea6f2005-12-17 12:48:26 +01003513 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3514 Alert("out of memory in event_accept().\n");
3515 FD_CLR(fd, StaticReadEvent);
3516 p->state = PR_STIDLE;
3517 close(cfd);
3518 return 0;
3519 }
willy tarreau0f7af912005-12-17 12:21:26 +01003520
willy tarreaub1285d52005-12-18 01:20:14 +01003521 /* if this session comes from a known monitoring system, we want to ignore
3522 * it as soon as possible, which means closing it immediately for TCP.
3523 */
3524 s->flags = 0;
3525 if (addr.ss_family == AF_INET &&
3526 p->mon_mask.s_addr &&
3527 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3528 if (p->mode == PR_MODE_TCP) {
3529 close(cfd);
3530 pool_free(session, s);
3531 continue;
3532 }
3533 s->flags |= SN_MONITOR;
3534 }
3535
willy tarreau5cbea6f2005-12-17 12:48:26 +01003536 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3537 Alert("out of memory in event_accept().\n");
3538 FD_CLR(fd, StaticReadEvent);
3539 p->state = PR_STIDLE;
3540 close(cfd);
3541 pool_free(session, s);
3542 return 0;
3543 }
willy tarreau0f7af912005-12-17 12:21:26 +01003544
willy tarreau5cbea6f2005-12-17 12:48:26 +01003545 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003546 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003547 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3548 close(cfd);
3549 pool_free(task, t);
3550 pool_free(session, s);
3551 return 0;
3552 }
willy tarreau0f7af912005-12-17 12:21:26 +01003553
willy tarreau5cbea6f2005-12-17 12:48:26 +01003554 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3555 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3556 (char *) &one, sizeof(one)) == -1)) {
3557 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3558 close(cfd);
3559 pool_free(task, t);
3560 pool_free(session, s);
3561 return 0;
3562 }
willy tarreau0f7af912005-12-17 12:21:26 +01003563
willy tarreaub952e1d2005-12-18 01:31:20 +01003564 if (p->options & PR_O_TCP_CLI_KA)
3565 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3566
willy tarreau9fe663a2005-12-17 13:02:59 +01003567 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003568 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003569 t->state = TASK_IDLE;
3570 t->process = process_session;
3571 t->context = s;
3572
3573 s->task = t;
3574 s->proxy = p;
3575 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3576 s->srv_state = SV_STIDLE;
3577 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003578
willy tarreau9fe663a2005-12-17 13:02:59 +01003579 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3580 s->cli_fd = cfd;
3581 s->srv_fd = -1;
willy tarreau9e138862006-05-14 23:06:28 +02003582 s->req_line.len = -1;
3583 s->auth_hdr.len = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003584 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003585 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003586 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003587
willy tarreaub1285d52005-12-18 01:20:14 +01003588 if (s->flags & SN_MONITOR)
3589 s->logs.logwait = 0;
3590 else
3591 s->logs.logwait = p->to_log;
3592
willy tarreaua1598082005-12-17 13:08:06 +01003593 s->logs.tv_accept = now;
3594 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003595 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003596 s->logs.t_connect = -1;
3597 s->logs.t_data = -1;
3598 s->logs.t_close = 0;
3599 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003600 s->logs.cli_cookie = NULL;
3601 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003602 s->logs.status = -1;
3603 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003604 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3605 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003606
willy tarreaue0331262006-05-15 03:02:46 +02003607 s->data_source = DATA_SRC_NONE;
3608 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
3609
willy tarreau2f6ba652005-12-17 13:57:42 +01003610 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003611 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003612
willy tarreau4302f492005-12-18 01:00:37 +01003613 if (p->nb_req_cap > 0) {
3614 if ((s->req_cap =
3615 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3616 == NULL) { /* no memory */
3617 close(cfd); /* nothing can be done for this fd without memory */
3618 pool_free(task, t);
3619 pool_free(session, s);
3620 return 0;
3621 }
3622 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3623 }
3624 else
3625 s->req_cap = NULL;
3626
3627 if (p->nb_rsp_cap > 0) {
3628 if ((s->rsp_cap =
3629 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3630 == NULL) { /* no memory */
3631 if (s->req_cap != NULL)
3632 pool_free_to(p->req_cap_pool, s->req_cap);
3633 close(cfd); /* nothing can be done for this fd without memory */
3634 pool_free(task, t);
3635 pool_free(session, s);
3636 return 0;
3637 }
3638 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3639 }
3640 else
3641 s->rsp_cap = NULL;
3642
willy tarreau5cbea6f2005-12-17 12:48:26 +01003643 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3644 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003645 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003646 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003647
willy tarreau8a86dbf2005-12-18 00:45:59 +01003648 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003649 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003650 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003651 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003652
willy tarreau9fe663a2005-12-17 13:02:59 +01003653 if (p->to_log) {
3654 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003655 if (s->logs.logwait & LW_CLIP)
3656 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003657 sess_log(s);
3658 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003659 else if (s->cli_addr.ss_family == AF_INET) {
3660 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3661 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3662 sn, sizeof(sn)) &&
3663 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3664 pn, sizeof(pn))) {
3665 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3666 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3667 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3668 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3669 }
3670 }
3671 else {
3672 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3673 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3674 sn, sizeof(sn)) &&
3675 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3676 pn, sizeof(pn))) {
3677 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3678 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3679 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3680 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3681 }
3682 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003683 }
willy tarreau0f7af912005-12-17 12:21:26 +01003684
willy tarreau982249e2005-12-18 00:57:06 +01003685 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003686 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003687 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003688 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003689 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003690 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003691 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003692 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003693
willy tarreau8a86dbf2005-12-18 00:45:59 +01003694 if (s->cli_addr.ss_family == AF_INET) {
3695 char pn[INET_ADDRSTRLEN];
3696 inet_ntop(AF_INET,
3697 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3698 pn, sizeof(pn));
3699
3700 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3701 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3702 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3703 }
3704 else {
3705 char pn[INET6_ADDRSTRLEN];
3706 inet_ntop(AF_INET6,
3707 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3708 pn, sizeof(pn));
3709
3710 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3711 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3712 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3713 }
3714
willy tarreauef900ab2005-12-17 12:52:52 +01003715 write(1, trash, len);
3716 }
willy tarreau0f7af912005-12-17 12:21:26 +01003717
willy tarreau5cbea6f2005-12-17 12:48:26 +01003718 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003719 if (s->rsp_cap != NULL)
3720 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3721 if (s->req_cap != NULL)
3722 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003723 close(cfd); /* nothing can be done for this fd without memory */
3724 pool_free(task, t);
3725 pool_free(session, s);
3726 return 0;
3727 }
willy tarreau4302f492005-12-18 01:00:37 +01003728
willy tarreau5cbea6f2005-12-17 12:48:26 +01003729 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003730 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003731 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3732 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003733 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003734 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003735
willy tarreau5cbea6f2005-12-17 12:48:26 +01003736 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3737 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003738 if (s->rsp_cap != NULL)
3739 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3740 if (s->req_cap != NULL)
3741 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003742 close(cfd); /* nothing can be done for this fd without memory */
3743 pool_free(task, t);
3744 pool_free(session, s);
3745 return 0;
3746 }
3747 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003748 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003749 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 +01003750
willy tarreau5cbea6f2005-12-17 12:48:26 +01003751 fdtab[cfd].read = &event_cli_read;
3752 fdtab[cfd].write = &event_cli_write;
3753 fdtab[cfd].owner = t;
3754 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003755
willy tarreaub1285d52005-12-18 01:20:14 +01003756 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3757 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3758 /* Either we got a request from a monitoring system on an HTTP instance,
3759 * or we're in health check mode with the 'httpchk' option enabled. In
3760 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3761 */
3762 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3763 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3764 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003765 }
3766 else {
3767 FD_SET(cfd, StaticReadEvent);
3768 }
3769
willy tarreaub952e1d2005-12-18 01:31:20 +01003770#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3771 if (PrevReadEvent) {
3772 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3773 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3774 }
3775#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003776 fd_insert(cfd);
3777
3778 tv_eternity(&s->cnexpire);
3779 tv_eternity(&s->srexpire);
3780 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003781 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003782 tv_eternity(&s->cwexpire);
3783
willy tarreaub1285d52005-12-18 01:20:14 +01003784 if (s->proxy->clitimeout) {
3785 if (FD_ISSET(cfd, StaticReadEvent))
3786 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3787 if (FD_ISSET(cfd, StaticWriteEvent))
3788 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3789 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003790
willy tarreaub1285d52005-12-18 01:20:14 +01003791 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003792
3793 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003794
3795 if (p->mode != PR_MODE_HEALTH)
3796 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003797
3798 p->nbconn++;
willy tarreaucb406512006-05-18 00:52:35 +02003799 if (p->nbconn > p->nbconn_max)
3800 p->nbconn_max = p->nbconn;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003801 actconn++;
3802 totalconn++;
3803
willy tarreaub952e1d2005-12-18 01:31:20 +01003804 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003805 } /* end of while (p->nbconn < p->maxconn) */
3806 return 0;
3807}
willy tarreau0f7af912005-12-17 12:21:26 +01003808
willy tarreau0f7af912005-12-17 12:21:26 +01003809
willy tarreau5cbea6f2005-12-17 12:48:26 +01003810/*
3811 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003812 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3813 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003814 * or -1 if an error occured.
3815 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003816int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003817 struct task *t = fdtab[fd].owner;
3818 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003819 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003820 socklen_t lskerr = sizeof(skerr);
3821
willy tarreau05be12b2006-03-19 19:35:00 +01003822 skerr = 1;
3823 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3824 || (skerr != 0)) {
3825 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003826 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003827 fdtab[fd].state = FD_STERROR;
3828 FD_CLR(fd, StaticWriteEvent);
3829 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003830 else if (s->result != -1) {
3831 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003832 if (s->proxy->options & PR_O_HTTP_CHK) {
3833 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003834 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003835 * so we'll send the request, and won't wake the checker up now.
3836 */
3837#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003838 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003839#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003840 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003841#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003842 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003843 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3844 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3845 return 0;
3846 }
willy tarreau05be12b2006-03-19 19:35:00 +01003847 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003848 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003849 FD_CLR(fd, StaticWriteEvent);
3850 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003851 }
3852 else {
3853 /* good TCP connection is enough */
3854 s->result = 1;
3855 }
3856 }
3857
3858 task_wakeup(&rq, t);
3859 return 0;
3860}
3861
willy tarreau0f7af912005-12-17 12:21:26 +01003862
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003863/*
3864 * This function is used only for server health-checks. It handles
3865 * the server's reply to an HTTP request. It returns 1 if the server replies
3866 * 2xx or 3xx (valid responses), or -1 in other cases.
3867 */
3868int event_srv_chk_r(int fd) {
3869 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003870 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003871 struct task *t = fdtab[fd].owner;
3872 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003873 int skerr;
3874 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003875
willy tarreaua4a583a2005-12-18 01:39:19 +01003876 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003877
willy tarreau05be12b2006-03-19 19:35:00 +01003878 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3879 if (!skerr) {
3880#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003881 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003882#else
willy tarreau05be12b2006-03-19 19:35:00 +01003883 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3884 * but the connection was closed on the remote end. Fortunately, recv still
3885 * works correctly and we don't need to do the getsockopt() on linux.
3886 */
3887 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003888#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003889
3890 if ((len >= sizeof("HTTP/1.0 000")) &&
3891 !memcmp(reply, "HTTP/1.", 7) &&
3892 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3893 result = 1;
3894 }
3895
3896 if (result == -1)
3897 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003898
3899 if (s->result != -1)
3900 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003901
3902 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003903 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003904 return 0;
3905}
3906
3907
3908/*
3909 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3910 * and moves <end> just after the end of <str>.
3911 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3912 * the shift value (positive or negative) is returned.
3913 * If there's no space left, the move is not done.
3914 *
3915 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003916int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003917 int delta;
3918 int len;
3919
3920 len = strlen(str);
3921 delta = len - (end - pos);
3922
3923 if (delta + b->r >= b->data + BUFSIZE)
3924 return 0; /* no space left */
3925
3926 /* first, protect the end of the buffer */
3927 memmove(end + delta, end, b->data + b->l - end);
3928
3929 /* now, copy str over pos */
3930 memcpy(pos, str,len);
3931
willy tarreau5cbea6f2005-12-17 12:48:26 +01003932 /* we only move data after the displaced zone */
3933 if (b->r > pos) b->r += delta;
3934 if (b->w > pos) b->w += delta;
3935 if (b->h > pos) b->h += delta;
3936 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003937 b->l += delta;
3938
3939 return delta;
3940}
3941
willy tarreau8337c6b2005-12-17 13:41:01 +01003942/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003943 * len is 0.
3944 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003945int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003946 int delta;
3947
3948 delta = len - (end - pos);
3949
3950 if (delta + b->r >= b->data + BUFSIZE)
3951 return 0; /* no space left */
3952
Willy TARREAUe78ae262006-01-08 01:24:12 +01003953 if (b->data + b->l < end)
3954 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3955 return 0;
3956
willy tarreau0f7af912005-12-17 12:21:26 +01003957 /* first, protect the end of the buffer */
3958 memmove(end + delta, end, b->data + b->l - end);
3959
3960 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003961 if (len)
3962 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003963
willy tarreau5cbea6f2005-12-17 12:48:26 +01003964 /* we only move data after the displaced zone */
3965 if (b->r > pos) b->r += delta;
3966 if (b->w > pos) b->w += delta;
3967 if (b->h > pos) b->h += delta;
3968 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003969 b->l += delta;
3970
3971 return delta;
3972}
3973
3974
3975int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3976 char *old_dst = dst;
3977
3978 while (*str) {
3979 if (*str == '\\') {
3980 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003981 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003982 int len, num;
3983
3984 num = *str - '0';
3985 str++;
3986
willy tarreau8a86dbf2005-12-18 00:45:59 +01003987 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003988 len = matches[num].rm_eo - matches[num].rm_so;
3989 memcpy(dst, src + matches[num].rm_so, len);
3990 dst += len;
3991 }
3992
3993 }
3994 else if (*str == 'x') {
3995 unsigned char hex1, hex2;
3996 str++;
3997
willy tarreauc1f47532005-12-18 01:08:26 +01003998 hex1 = toupper(*str++) - '0';
3999 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01004000
4001 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4002 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4003 *dst++ = (hex1<<4) + hex2;
4004 }
4005 else
4006 *dst++ = *str++;
4007 }
4008 else
4009 *dst++ = *str++;
4010 }
4011 *dst = 0;
4012 return dst - old_dst;
4013}
4014
willy tarreauc1f47532005-12-18 01:08:26 +01004015static int ishex(char s)
4016{
4017 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
4018}
4019
4020/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
4021char *check_replace_string(char *str)
4022{
4023 char *err = NULL;
4024 while (*str) {
4025 if (*str == '\\') {
4026 err = str; /* in case of a backslash, we return the pointer to it */
4027 str++;
4028 if (!*str)
4029 return err;
4030 else if (isdigit((int)*str))
4031 err = NULL;
4032 else if (*str == 'x') {
4033 str++;
4034 if (!ishex(*str))
4035 return err;
4036 str++;
4037 if (!ishex(*str))
4038 return err;
4039 err = NULL;
4040 }
4041 else {
4042 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
4043 err = NULL;
4044 }
4045 }
4046 str++;
4047 }
4048 return err;
4049}
4050
willy tarreau0f7af912005-12-17 12:21:26 +01004051/*
4052 * manages the client FSM and its socket. BTW, it also tries to handle the
4053 * cookie. It returns 1 if a state has changed (and a resync may be needed),
4054 * 0 else.
4055 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004056int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004057 int s = t->srv_state;
4058 int c = t->cli_state;
4059 struct buffer *req = t->req;
4060 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004061 int method_checked = 0;
4062 appsess *asession_temp = NULL;
4063 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01004064
willy tarreau750a4722005-12-17 13:21:24 +01004065#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01004066 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
4067 cli_stnames[c], srv_stnames[s],
4068 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4069 t->crexpire.tv_sec, t->crexpire.tv_usec,
4070 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01004071#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004072 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4073 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4074 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4075 //);
4076 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004077 /* now parse the partial (or complete) headers */
4078 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
4079 char *ptr;
4080 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01004081 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01004082
willy tarreau5cbea6f2005-12-17 12:48:26 +01004083 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01004084
willy tarreau0f7af912005-12-17 12:21:26 +01004085 /* look for the end of the current header */
4086 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
4087 ptr++;
4088
willy tarreau5cbea6f2005-12-17 12:48:26 +01004089 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004090 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02004091
4092 /*
4093 * first, let's check that it's not a leading empty line, in
4094 * which case we'll ignore and remove it (according to RFC2616).
4095 */
4096 if (req->h == req->data) {
4097 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4098 if (ptr > req->r - 2) {
4099 /* this is a partial header, let's wait for more to come */
4100 req->lr = ptr;
4101 break;
4102 }
4103
4104 /* now we know that *ptr is either \r or \n,
4105 * and that there are at least 1 char after it.
4106 */
4107 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4108 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4109 else
4110 req->lr = ptr + 2; /* \r\n or \n\r */
4111 /* ignore empty leading lines */
4112 buffer_replace2(req, req->h, req->lr, NULL, 0);
4113 req->h = req->lr;
4114 continue;
4115 }
4116
willy tarreau5cbea6f2005-12-17 12:48:26 +01004117 /* we can only get here after an end of headers */
4118 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004119
willy tarreaue39cd132005-12-17 13:00:18 +01004120 if (t->flags & SN_CLDENY) {
4121 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01004122 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01004123 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01004124 if (!(t->flags & SN_ERR_MASK))
4125 t->flags |= SN_ERR_PRXCOND;
4126 if (!(t->flags & SN_FINST_MASK))
4127 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004128 return 1;
4129 }
4130
willy tarreau9e138862006-05-14 23:06:28 +02004131 /* Right now, we know that we have processed the entire headers
4132 * and that unwanted requests have been filtered out. We can do
4133 * whatever we want.
4134 */
4135
willy tarreau9e138862006-05-14 23:06:28 +02004136 if (t->proxy->uri_auth != NULL
4137 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
4138 if (!memcmp(t->req_line.str + 4,
4139 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
4140 && !memcmp(t->req_line.str, "GET ", 4)) {
4141 struct user_auth *user;
4142 int authenticated;
4143
4144 /* we are in front of a interceptable URI. Let's check
4145 * if there's an authentication and if it's valid.
4146 */
4147 user = t->proxy->uri_auth->users;
4148 if (!user) {
4149 /* no user auth required, it's OK */
4150 authenticated = 1;
4151 } else {
4152 authenticated = 0;
4153
4154 /* a user list is defined, we have to check.
4155 * skip 21 chars for "Authorization: Basic ".
4156 */
4157 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
4158 user = NULL;
4159
4160 while (user) {
4161 if ((t->auth_hdr.len == user->user_len + 21)
4162 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
4163 authenticated = 1;
4164 break;
4165 }
4166 user = user->next;
willy tarreau9e138862006-05-14 23:06:28 +02004167 }
4168 }
4169
4170 if (!authenticated) {
4171 int msglen;
4172
4173 /* no need to go further */
4174
4175 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
4176 t->logs.status = 401;
4177 client_retnclose(t, msglen, trash);
4178 if (!(t->flags & SN_ERR_MASK))
4179 t->flags |= SN_ERR_PRXCOND;
4180 if (!(t->flags & SN_FINST_MASK))
4181 t->flags |= SN_FINST_R;
4182 return 1;
4183 }
4184
willy tarreaue0331262006-05-15 03:02:46 +02004185 t->cli_state = CL_STSHUTR;
4186 t->data_source = DATA_SRC_STATS;
4187 produce_content(t);
4188 return 1;
willy tarreau9e138862006-05-14 23:06:28 +02004189 }
4190 }
4191
4192
willy tarreau5cbea6f2005-12-17 12:48:26 +01004193 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004194 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
4195 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004196 }
willy tarreau0f7af912005-12-17 12:21:26 +01004197
willy tarreau9fe663a2005-12-17 13:02:59 +01004198 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01004199 if (t->cli_addr.ss_family == AF_INET) {
4200 unsigned char *pn;
4201 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
4202 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
4203 pn[0], pn[1], pn[2], pn[3]);
4204 buffer_replace2(req, req->h, req->h, trash, len);
4205 }
4206 else if (t->cli_addr.ss_family == AF_INET6) {
4207 char pn[INET6_ADDRSTRLEN];
4208 inet_ntop(AF_INET6,
4209 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
4210 pn, sizeof(pn));
4211 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
4212 buffer_replace2(req, req->h, req->h, trash, len);
4213 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004214 }
4215
willy tarreau25c4ea52005-12-18 00:49:49 +01004216 /* add a "connection: close" line if needed */
4217 if (t->proxy->options & PR_O_HTTP_CLOSE)
4218 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
4219
willy tarreau982249e2005-12-18 00:57:06 +01004220 if (!memcmp(req->data, "POST ", 5)) {
4221 /* this is a POST request, which is not cacheable by default */
4222 t->flags |= SN_POST;
4223 }
willy tarreaucd878942005-12-17 13:27:43 +01004224
willy tarreau5cbea6f2005-12-17 12:48:26 +01004225 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004226 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01004227
willy tarreau750a4722005-12-17 13:21:24 +01004228 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004229 /* FIXME: we'll set the client in a wait state while we try to
4230 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02004231 * better to release the maximum of system buffers instead ?
4232 * The solution is to enable the FD but set its time-out to
4233 * eternity as long as the server-side does not enable data xfer.
4234 * CL_STDATA also has to take care of this, which is done below.
4235 */
willy tarreauef900ab2005-12-17 12:52:52 +01004236 //FD_CLR(t->cli_fd, StaticReadEvent);
4237 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01004238
4239 /* FIXME: if we break here (as up to 1.1.23), having the client
4240 * shutdown its connection can lead to an abort further.
4241 * it's better to either return 1 or even jump directly to the
4242 * data state which will save one schedule.
4243 */
4244 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01004245
4246 if (!t->proxy->clitimeout ||
4247 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4248 /* If the client has no timeout, or if the server is not ready yet,
4249 * and we know for sure that it can expire, then it's cleaner to
4250 * disable the timeout on the client side so that too low values
4251 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01004252 *
4253 * FIXME-20050705: the server needs a way to re-enable this time-out
4254 * when it switches its state, otherwise a client can stay connected
4255 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01004256 */
4257 tv_eternity(&t->crexpire);
4258
willy tarreau197e8ec2005-12-17 14:10:59 +01004259 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004260 }
willy tarreau0f7af912005-12-17 12:21:26 +01004261
Willy TARREAU13032e72006-03-12 17:31:45 +01004262 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4263 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004264 /* this is a partial header, let's wait for more to come */
4265 req->lr = ptr;
4266 break;
4267 }
willy tarreau0f7af912005-12-17 12:21:26 +01004268
willy tarreau5cbea6f2005-12-17 12:48:26 +01004269 /* now we know that *ptr is either \r or \n,
4270 * and that there are at least 1 char after it.
4271 */
4272 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4273 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4274 else
4275 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01004276
willy tarreau5cbea6f2005-12-17 12:48:26 +01004277 /*
4278 * now we know that we have a full header ; we can do whatever
4279 * we want with these pointers :
4280 * req->h = beginning of header
4281 * ptr = end of header (first \r or \n)
4282 * req->lr = beginning of next line (next rep->h)
4283 * req->r = end of data (not used at this stage)
4284 */
willy tarreau0f7af912005-12-17 12:21:26 +01004285
willy tarreau12350152005-12-18 01:03:27 +01004286 if (!method_checked && (t->proxy->appsession_name != NULL) &&
4287 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
4288 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
4289
4290 /* skip ; */
4291 request_line++;
4292
4293 /* look if we have a jsessionid */
4294
4295 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
4296
4297 /* skip jsessionid= */
4298 request_line += t->proxy->appsession_name_len + 1;
4299
4300 /* First try if we allready have an appsession */
4301 asession_temp = &local_asession;
4302
4303 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4304 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4305 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4306 return 0;
4307 }
4308
4309 /* Copy the sessionid */
4310 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
4311 asession_temp->sessid[t->proxy->appsession_len] = 0;
4312 asession_temp->serverid = NULL;
4313
4314 /* only do insert, if lookup fails */
4315 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
4316 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4317 Alert("Not enough memory process_cli():asession:calloc().\n");
4318 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4319 return 0;
4320 }
4321 asession_temp->sessid = local_asession.sessid;
4322 asession_temp->serverid = local_asession.serverid;
4323 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004324 } /* end if (chtbl_lookup()) */
4325 else {
willy tarreau12350152005-12-18 01:03:27 +01004326 /*free wasted memory;*/
4327 pool_free_to(apools.sessid, local_asession.sessid);
4328 }
4329
4330 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4331 asession_temp->request_count++;
4332
4333#if defined(DEBUG_HASH)
4334 print_table(&(t->proxy->htbl_proxy));
4335#endif
4336
4337 if (asession_temp->serverid == NULL) {
4338 Alert("Found Application Session without matching server.\n");
4339 } else {
4340 struct server *srv = t->proxy->srv;
4341 while (srv) {
4342 if (strcmp(srv->id, asession_temp->serverid) == 0) {
4343 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4344 /* we found the server and it's usable */
4345 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004346 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004347 t->srv = srv;
4348 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01004349 } else {
willy tarreau12350152005-12-18 01:03:27 +01004350 t->flags &= ~SN_CK_MASK;
4351 t->flags |= SN_CK_DOWN;
4352 }
willy tarreaub952e1d2005-12-18 01:31:20 +01004353 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01004354 srv = srv->next;
4355 }/* end while(srv) */
4356 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01004357 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01004358 else {
4359 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
4360 }
willy tarreau598da412005-12-18 01:07:29 +01004361 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01004362 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01004363 else{
4364 //printf("No Methode-Header with Session-String\n");
4365 }
4366
willy tarreau8337c6b2005-12-17 13:41:01 +01004367 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004368 /* we have a complete HTTP request that we must log */
4369 int urilen;
4370
willy tarreaua1598082005-12-17 13:08:06 +01004371 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004372 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01004373 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01004374 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01004375 if (!(t->flags & SN_ERR_MASK))
4376 t->flags |= SN_ERR_PRXCOND;
4377 if (!(t->flags & SN_FINST_MASK))
4378 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01004379 return 1;
4380 }
4381
4382 urilen = ptr - req->h;
4383 if (urilen >= REQURI_LEN)
4384 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01004385 memcpy(t->logs.uri, req->h, urilen);
4386 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004387
willy tarreaua1598082005-12-17 13:08:06 +01004388 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01004389 sess_log(t);
4390 }
willy tarreau4302f492005-12-18 01:00:37 +01004391 else if (t->logs.logwait & LW_REQHDR) {
4392 struct cap_hdr *h;
4393 int len;
4394 for (h = t->proxy->req_cap; h; h = h->next) {
4395 if ((h->namelen + 2 <= ptr - req->h) &&
4396 (req->h[h->namelen] == ':') &&
4397 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
4398
4399 if (t->req_cap[h->index] == NULL)
4400 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4401
4402 len = ptr - (req->h + h->namelen + 2);
4403 if (len > h->len)
4404 len = h->len;
4405
4406 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
4407 t->req_cap[h->index][len]=0;
4408 }
4409 }
4410
4411 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004412
willy tarreau5cbea6f2005-12-17 12:48:26 +01004413 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004414
willy tarreau982249e2005-12-18 00:57:06 +01004415 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004416 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004417 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 +01004418 max = ptr - req->h;
4419 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004420 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004421 trash[len++] = '\n';
4422 write(1, trash, len);
4423 }
willy tarreau0f7af912005-12-17 12:21:26 +01004424
willy tarreau25c4ea52005-12-18 00:49:49 +01004425
4426 /* remove "connection: " if needed */
4427 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4428 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
4429 delete_header = 1;
4430 }
4431
willy tarreau5cbea6f2005-12-17 12:48:26 +01004432 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004433 if (!delete_header && t->proxy->req_exp != NULL
4434 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004435 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004436 char term;
4437
4438 term = *ptr;
4439 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004440 exp = t->proxy->req_exp;
4441 do {
4442 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
4443 switch (exp->action) {
4444 case ACT_ALLOW:
4445 if (!(t->flags & SN_CLDENY))
4446 t->flags |= SN_CLALLOW;
4447 break;
4448 case ACT_REPLACE:
4449 if (!(t->flags & SN_CLDENY)) {
4450 int len = exp_replace(trash, req->h, exp->replace, pmatch);
4451 ptr += buffer_replace2(req, req->h, ptr, trash, len);
4452 }
4453 break;
4454 case ACT_REMOVE:
4455 if (!(t->flags & SN_CLDENY))
4456 delete_header = 1;
4457 break;
4458 case ACT_DENY:
4459 if (!(t->flags & SN_CLALLOW))
4460 t->flags |= SN_CLDENY;
4461 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004462 case ACT_PASS: /* we simply don't deny this one */
4463 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004464 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004465 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004466 }
willy tarreaue39cd132005-12-17 13:00:18 +01004467 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004468 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01004469 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004470
willy tarreau240afa62005-12-17 13:14:35 +01004471 /* Now look for cookies. Conforming to RFC2109, we have to support
4472 * attributes whose name begin with a '$', and associate them with
4473 * the right cookie, if we want to delete this cookie.
4474 * So there are 3 cases for each cookie read :
4475 * 1) it's a special attribute, beginning with a '$' : ignore it.
4476 * 2) it's a server id cookie that we *MAY* want to delete : save
4477 * some pointers on it (last semi-colon, beginning of cookie...)
4478 * 3) it's an application cookie : we *MAY* have to delete a previous
4479 * "special" cookie.
4480 * At the end of loop, if a "special" cookie remains, we may have to
4481 * remove it. If no application cookie persists in the header, we
4482 * *MUST* delete it
4483 */
willy tarreau12350152005-12-18 01:03:27 +01004484 if (!delete_header &&
4485 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01004486 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01004487 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004488 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01004489 char *del_colon, *del_cookie, *colon;
4490 int app_cookies;
4491
willy tarreau5cbea6f2005-12-17 12:48:26 +01004492 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01004493 colon = p1;
4494 /* del_cookie == NULL => nothing to be deleted */
4495 del_colon = del_cookie = NULL;
4496 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004497
4498 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01004499 /* skip spaces and colons, but keep an eye on these ones */
4500 while (p1 < ptr) {
4501 if (*p1 == ';' || *p1 == ',')
4502 colon = p1;
4503 else if (!isspace((int)*p1))
4504 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004505 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01004506 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004507
4508 if (p1 == ptr)
4509 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004510
4511 /* p1 is at the beginning of the cookie name */
4512 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004513 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004514 p2++;
4515
4516 if (p2 == ptr)
4517 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004518
4519 p3 = p2 + 1; /* skips the '=' sign */
4520 if (p3 == ptr)
4521 break;
4522
willy tarreau240afa62005-12-17 13:14:35 +01004523 p4 = p3;
4524 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004525 p4++;
4526
4527 /* here, we have the cookie name between p1 and p2,
4528 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004529 * we can process it :
4530 *
4531 * Cookie: NAME=VALUE;
4532 * | || || |
4533 * | || || +--> p4
4534 * | || |+-------> p3
4535 * | || +--------> p2
4536 * | |+------------> p1
4537 * | +-------------> colon
4538 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004539 */
4540
willy tarreau240afa62005-12-17 13:14:35 +01004541 if (*p1 == '$') {
4542 /* skip this one */
4543 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004544 else {
4545 /* first, let's see if we want to capture it */
4546 if (t->proxy->capture_name != NULL &&
4547 t->logs.cli_cookie == NULL &&
4548 (p4 - p1 >= t->proxy->capture_namelen) &&
4549 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4550 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004551
willy tarreau8337c6b2005-12-17 13:41:01 +01004552 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4553 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004554 } else {
4555 if (log_len > t->proxy->capture_len)
4556 log_len = t->proxy->capture_len;
4557 memcpy(t->logs.cli_cookie, p1, log_len);
4558 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004559 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004560 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004561
4562 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4563 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4564 /* Cool... it's the right one */
4565 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004566 char *delim;
4567
4568 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4569 * have the server ID betweek p3 and delim, and the original cookie between
4570 * delim+1 and p4. Otherwise, delim==p4 :
4571 *
4572 * Cookie: NAME=SRV~VALUE;
4573 * | || || | |
4574 * | || || | +--> p4
4575 * | || || +--------> delim
4576 * | || |+-----------> p3
4577 * | || +------------> p2
4578 * | |+----------------> p1
4579 * | +-----------------> colon
4580 * +------------------------> req->h
4581 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004582
willy tarreau0174f312005-12-18 01:02:42 +01004583 if (t->proxy->options & PR_O_COOK_PFX) {
4584 for (delim = p3; delim < p4; delim++)
4585 if (*delim == COOKIE_DELIM)
4586 break;
4587 }
4588 else
4589 delim = p4;
4590
4591
4592 /* Here, we'll look for the first running server which supports the cookie.
4593 * This allows to share a same cookie between several servers, for example
4594 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004595 * However, to prevent clients from sticking to cookie-less backup server
4596 * when they have incidentely learned an empty cookie, we simply ignore
4597 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004598 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004599 if (delim == p3)
4600 srv = NULL;
4601
willy tarreau0174f312005-12-18 01:02:42 +01004602 while (srv) {
4603 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4604 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4605 /* we found the server and it's usable */
4606 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004607 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004608 t->srv = srv;
4609 break;
willy tarreau12350152005-12-18 01:03:27 +01004610 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004611 /* we found a server, but it's down */
4612 t->flags &= ~SN_CK_MASK;
4613 t->flags |= SN_CK_DOWN;
4614 }
4615 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004616 srv = srv->next;
4617 }
4618
willy tarreau0174f312005-12-18 01:02:42 +01004619 if (!srv && !(t->flags & SN_CK_DOWN)) {
4620 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004621 t->flags &= ~SN_CK_MASK;
4622 t->flags |= SN_CK_INVALID;
4623 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004624
willy tarreau0174f312005-12-18 01:02:42 +01004625 /* depending on the cookie mode, we may have to either :
4626 * - delete the complete cookie if we're in insert+indirect mode, so that
4627 * the server never sees it ;
4628 * - remove the server id from the cookie value, and tag the cookie as an
4629 * application cookie so that it does not get accidentely removed later,
4630 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004631 */
willy tarreau0174f312005-12-18 01:02:42 +01004632 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4633 buffer_replace2(req, p3, delim + 1, NULL, 0);
4634 p4 -= (delim + 1 - p3);
4635 ptr -= (delim + 1 - p3);
4636 del_cookie = del_colon = NULL;
4637 app_cookies++; /* protect the header from deletion */
4638 }
4639 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004640 (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 +01004641 del_cookie = p1;
4642 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004643 }
willy tarreau12350152005-12-18 01:03:27 +01004644 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004645 /* now we know that we must keep this cookie since it's
4646 * not ours. But if we wanted to delete our cookie
4647 * earlier, we cannot remove the complete header, but we
4648 * can remove the previous block itself.
4649 */
4650 app_cookies++;
4651
4652 if (del_cookie != NULL) {
4653 buffer_replace2(req, del_cookie, p1, NULL, 0);
4654 p4 -= (p1 - del_cookie);
4655 ptr -= (p1 - del_cookie);
4656 del_cookie = del_colon = NULL;
4657 }
willy tarreau240afa62005-12-17 13:14:35 +01004658 }
willy tarreau12350152005-12-18 01:03:27 +01004659
4660 if ((t->proxy->appsession_name != NULL) &&
4661 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4662 /* first, let's see if the cookie is our appcookie*/
4663
4664 /* Cool... it's the right one */
4665
4666 asession_temp = &local_asession;
4667
4668 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4669 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4670 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4671 return 0;
4672 }
4673
4674 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4675 asession_temp->sessid[t->proxy->appsession_len] = 0;
4676 asession_temp->serverid = NULL;
4677
4678 /* only do insert, if lookup fails */
4679 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4680 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4681 Alert("Not enough memory process_cli():asession:calloc().\n");
4682 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4683 return 0;
4684 }
4685
4686 asession_temp->sessid = local_asession.sessid;
4687 asession_temp->serverid = local_asession.serverid;
4688 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4689 }
4690 else{
4691 /* free wasted memory */
4692 pool_free_to(apools.sessid, local_asession.sessid);
4693 }
4694
4695 if (asession_temp->serverid == NULL) {
4696 Alert("Found Application Session without matching server.\n");
4697 } else {
4698 struct server *srv = t->proxy->srv;
4699 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004700 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004701 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4702 /* we found the server and it's usable */
4703 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004704 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004705 t->srv = srv;
4706 break;
4707 } else {
4708 t->flags &= ~SN_CK_MASK;
4709 t->flags |= SN_CK_DOWN;
4710 }
4711 }
4712 srv = srv->next;
4713 }/* end while(srv) */
4714 }/* end else if server == NULL */
4715
4716 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004717 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004718 }
willy tarreau240afa62005-12-17 13:14:35 +01004719
willy tarreau5cbea6f2005-12-17 12:48:26 +01004720 /* we'll have to look for another cookie ... */
4721 p1 = p4;
4722 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004723
4724 /* There's no more cookie on this line.
4725 * We may have marked the last one(s) for deletion.
4726 * We must do this now in two ways :
4727 * - if there is no app cookie, we simply delete the header ;
4728 * - if there are app cookies, we must delete the end of the
4729 * string properly, including the colon/semi-colon before
4730 * the cookie name.
4731 */
4732 if (del_cookie != NULL) {
4733 if (app_cookies) {
4734 buffer_replace2(req, del_colon, ptr, NULL, 0);
4735 /* WARNING! <ptr> becomes invalid for now. If some code
4736 * below needs to rely on it before the end of the global
4737 * header loop, we need to correct it with this code :
willy tarreau240afa62005-12-17 13:14:35 +01004738 */
willy tarreau9e138862006-05-14 23:06:28 +02004739 ptr = del_colon;
willy tarreau240afa62005-12-17 13:14:35 +01004740 }
4741 else
4742 delete_header = 1;
4743 }
4744 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004745
4746 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004747 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004748 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau9e138862006-05-14 23:06:28 +02004749 /* WARNING: ptr is not valid anymore, since the header may have
4750 * been deleted or truncated ! */
4751 } else {
4752 /* try to catch the first line as the request */
4753 if (t->req_line.len < 0) {
4754 t->req_line.str = req->h;
4755 t->req_line.len = ptr - req->h;
4756 }
4757
4758 /* We might also need the 'Authorization: ' header */
4759 if (t->auth_hdr.len < 0 &&
4760 t->proxy->uri_auth != NULL &&
4761 ptr > req->h + 15 &&
4762 !strncasecmp("Authorization: ", req->h, 15)) {
4763 t->auth_hdr.str = req->h;
4764 t->auth_hdr.len = ptr - req->h;
4765 }
willy tarreau0f7af912005-12-17 12:21:26 +01004766 }
willy tarreau240afa62005-12-17 13:14:35 +01004767
willy tarreau5cbea6f2005-12-17 12:48:26 +01004768 req->h = req->lr;
4769 } /* while (req->lr < req->r) */
4770
4771 /* end of header processing (even if incomplete) */
4772
willy tarreauef900ab2005-12-17 12:52:52 +01004773 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4774 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4775 * full. We cannot loop here since event_cli_read will disable it only if
4776 * req->l == rlim-data
4777 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004778 FD_SET(t->cli_fd, StaticReadEvent);
4779 if (t->proxy->clitimeout)
4780 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4781 else
4782 tv_eternity(&t->crexpire);
4783 }
4784
willy tarreaue39cd132005-12-17 13:00:18 +01004785 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004786 * won't be able to free more later, so the session will never terminate.
4787 */
willy tarreaue39cd132005-12-17 13:00:18 +01004788 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004789 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004790 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004791 if (!(t->flags & SN_ERR_MASK))
4792 t->flags |= SN_ERR_PRXCOND;
4793 if (!(t->flags & SN_FINST_MASK))
4794 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004795 return 1;
4796 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004797 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004798 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004799 tv_eternity(&t->crexpire);
4800 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004801 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004802 if (!(t->flags & SN_ERR_MASK))
4803 t->flags |= SN_ERR_CLICL;
4804 if (!(t->flags & SN_FINST_MASK))
4805 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004806 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004807 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004808 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4809
4810 /* read timeout : give up with an error message.
4811 */
4812 t->logs.status = 408;
4813 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004814 if (!(t->flags & SN_ERR_MASK))
4815 t->flags |= SN_ERR_CLITO;
4816 if (!(t->flags & SN_FINST_MASK))
4817 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004818 return 1;
4819 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004820
4821 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004822 }
4823 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004824 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004825 /* FIXME: this error handling is partly buggy because we always report
4826 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4827 * or HEADER phase. BTW, it's not logical to expire the client while
4828 * we're waiting for the server to connect.
4829 */
willy tarreau0f7af912005-12-17 12:21:26 +01004830 /* read or write error */
4831 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004832 tv_eternity(&t->crexpire);
4833 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004834 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004835 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004836 if (!(t->flags & SN_ERR_MASK))
4837 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004838 if (!(t->flags & SN_FINST_MASK)) {
4839 if (t->pend_pos)
4840 t->flags |= SN_FINST_Q;
4841 else if (s == SV_STCONN)
4842 t->flags |= SN_FINST_C;
4843 else
4844 t->flags |= SN_FINST_D;
4845 }
willy tarreau0f7af912005-12-17 12:21:26 +01004846 return 1;
4847 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004848 /* last read, or end of server write */
4849 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004850 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004851 tv_eternity(&t->crexpire);
4852 shutdown(t->cli_fd, SHUT_RD);
4853 t->cli_state = CL_STSHUTR;
4854 return 1;
4855 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004856 /* last server read and buffer empty */
4857 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004858 FD_CLR(t->cli_fd, StaticWriteEvent);
4859 tv_eternity(&t->cwexpire);
4860 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004861 /* We must ensure that the read part is still alive when switching
4862 * to shutw */
4863 FD_SET(t->cli_fd, StaticReadEvent);
4864 if (t->proxy->clitimeout)
4865 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004866 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004867 //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 +01004868 return 1;
4869 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004870 /* read timeout */
4871 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4872 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004873 tv_eternity(&t->crexpire);
4874 shutdown(t->cli_fd, SHUT_RD);
4875 t->cli_state = CL_STSHUTR;
4876 if (!(t->flags & SN_ERR_MASK))
4877 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004878 if (!(t->flags & SN_FINST_MASK)) {
4879 if (t->pend_pos)
4880 t->flags |= SN_FINST_Q;
4881 else if (s == SV_STCONN)
4882 t->flags |= SN_FINST_C;
4883 else
4884 t->flags |= SN_FINST_D;
4885 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004886 return 1;
4887 }
4888 /* write timeout */
4889 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4890 FD_CLR(t->cli_fd, StaticWriteEvent);
4891 tv_eternity(&t->cwexpire);
4892 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004893 /* We must ensure that the read part is still alive when switching
4894 * to shutw */
4895 FD_SET(t->cli_fd, StaticReadEvent);
4896 if (t->proxy->clitimeout)
4897 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4898
willy tarreau036e1ce2005-12-17 13:46:33 +01004899 t->cli_state = CL_STSHUTW;
4900 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004901 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004902 if (!(t->flags & SN_FINST_MASK)) {
4903 if (t->pend_pos)
4904 t->flags |= SN_FINST_Q;
4905 else if (s == SV_STCONN)
4906 t->flags |= SN_FINST_C;
4907 else
4908 t->flags |= SN_FINST_D;
4909 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004910 return 1;
4911 }
willy tarreau0f7af912005-12-17 12:21:26 +01004912
willy tarreauc58fc692005-12-17 14:13:08 +01004913 if (req->l >= req->rlim - req->data) {
4914 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004915 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004916 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004917 FD_CLR(t->cli_fd, StaticReadEvent);
4918 tv_eternity(&t->crexpire);
4919 }
4920 }
4921 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004922 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004923 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4924 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004925 if (!t->proxy->clitimeout ||
4926 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4927 /* If the client has no timeout, or if the server not ready yet, and we
4928 * know for sure that it can expire, then it's cleaner to disable the
4929 * timeout on the client side so that too low values cannot make the
4930 * sessions abort too early.
4931 */
willy tarreau0f7af912005-12-17 12:21:26 +01004932 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004933 else
4934 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004935 }
4936 }
4937
4938 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004939 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004940 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4941 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4942 tv_eternity(&t->cwexpire);
4943 }
4944 }
4945 else { /* buffer not empty */
4946 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4947 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004948 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004949 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004950 /* FIXME: to prevent the client from expiring read timeouts during writes,
4951 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004952 t->crexpire = t->cwexpire;
4953 }
willy tarreau0f7af912005-12-17 12:21:26 +01004954 else
4955 tv_eternity(&t->cwexpire);
4956 }
4957 }
4958 return 0; /* other cases change nothing */
4959 }
4960 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004961 if (t->res_cw == RES_ERROR) {
4962 tv_eternity(&t->cwexpire);
4963 fd_delete(t->cli_fd);
4964 t->cli_state = CL_STCLOSE;
4965 if (!(t->flags & SN_ERR_MASK))
4966 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004967 if (!(t->flags & SN_FINST_MASK)) {
4968 if (t->pend_pos)
4969 t->flags |= SN_FINST_Q;
4970 else if (s == SV_STCONN)
4971 t->flags |= SN_FINST_C;
4972 else
4973 t->flags |= SN_FINST_D;
4974 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004975 return 1;
4976 }
willy tarreaue0331262006-05-15 03:02:46 +02004977 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
4978 && !(t->flags & SN_SELF_GEN)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004979 tv_eternity(&t->cwexpire);
4980 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004981 t->cli_state = CL_STCLOSE;
4982 return 1;
4983 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004984 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4985 tv_eternity(&t->cwexpire);
4986 fd_delete(t->cli_fd);
4987 t->cli_state = CL_STCLOSE;
4988 if (!(t->flags & SN_ERR_MASK))
4989 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004990 if (!(t->flags & SN_FINST_MASK)) {
4991 if (t->pend_pos)
4992 t->flags |= SN_FINST_Q;
4993 else if (s == SV_STCONN)
4994 t->flags |= SN_FINST_C;
4995 else
4996 t->flags |= SN_FINST_D;
4997 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004998 return 1;
4999 }
willy tarreaue0331262006-05-15 03:02:46 +02005000
5001 if (t->flags & SN_SELF_GEN) {
5002 produce_content(t);
5003 if (rep->l == 0) {
5004 tv_eternity(&t->cwexpire);
5005 fd_delete(t->cli_fd);
5006 t->cli_state = CL_STCLOSE;
5007 return 1;
5008 }
5009 }
5010
5011 if ((rep->l == 0)
5012 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005013 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5014 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
5015 tv_eternity(&t->cwexpire);
5016 }
5017 }
5018 else { /* buffer not empty */
5019 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
5020 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005021 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005022 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005023 /* FIXME: to prevent the client from expiring read timeouts during writes,
5024 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005025 t->crexpire = t->cwexpire;
5026 }
willy tarreau0f7af912005-12-17 12:21:26 +01005027 else
5028 tv_eternity(&t->cwexpire);
5029 }
5030 }
5031 return 0;
5032 }
5033 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005034 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005035 tv_eternity(&t->crexpire);
5036 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005037 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005038 if (!(t->flags & SN_ERR_MASK))
5039 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02005040 if (!(t->flags & SN_FINST_MASK)) {
5041 if (t->pend_pos)
5042 t->flags |= SN_FINST_Q;
5043 else if (s == SV_STCONN)
5044 t->flags |= SN_FINST_C;
5045 else
5046 t->flags |= SN_FINST_D;
5047 }
willy tarreau0f7af912005-12-17 12:21:26 +01005048 return 1;
5049 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005050 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
5051 tv_eternity(&t->crexpire);
5052 fd_delete(t->cli_fd);
5053 t->cli_state = CL_STCLOSE;
5054 return 1;
5055 }
5056 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
5057 tv_eternity(&t->crexpire);
5058 fd_delete(t->cli_fd);
5059 t->cli_state = CL_STCLOSE;
5060 if (!(t->flags & SN_ERR_MASK))
5061 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02005062 if (!(t->flags & SN_FINST_MASK)) {
5063 if (t->pend_pos)
5064 t->flags |= SN_FINST_Q;
5065 else if (s == SV_STCONN)
5066 t->flags |= SN_FINST_C;
5067 else
5068 t->flags |= SN_FINST_D;
5069 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005070 return 1;
5071 }
willy tarreauef900ab2005-12-17 12:52:52 +01005072 else if (req->l >= req->rlim - req->data) {
5073 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01005074
5075 /* FIXME-20050705: is it possible for a client to maintain a session
5076 * after the timeout by sending more data after it receives a close ?
5077 */
5078
willy tarreau0f7af912005-12-17 12:21:26 +01005079 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01005080 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01005081 FD_CLR(t->cli_fd, StaticReadEvent);
5082 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005083 //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 +01005084 }
5085 }
5086 else {
willy tarreauef900ab2005-12-17 12:52:52 +01005087 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01005088 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
5089 FD_SET(t->cli_fd, StaticReadEvent);
5090 if (t->proxy->clitimeout)
5091 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
5092 else
5093 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01005094 //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 +01005095 }
5096 }
5097 return 0;
5098 }
5099 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005100 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005101 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005102 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 +01005103 write(1, trash, len);
5104 }
5105 return 0;
5106 }
5107 return 0;
5108}
5109
willy tarreaudfece232006-05-02 00:19:57 +02005110/* This function turns the server state into the SV_STCLOSE, and sets
5111 * indicators accordingly. Note that if <status> is 0, no message is
5112 * returned.
5113 */
5114void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
5115 t->srv_state = SV_STCLOSE;
5116 if (status > 0) {
5117 t->logs.status = status;
5118 if (t->proxy->mode == PR_MODE_HTTP)
5119 client_return(t, msglen, msg);
5120 }
5121 if (!(t->flags & SN_ERR_MASK))
5122 t->flags |= err;
5123 if (!(t->flags & SN_FINST_MASK))
5124 t->flags |= finst;
5125}
5126
5127/*
5128 * This function checks the retry count during the connect() job.
5129 * It updates the session's srv_state and retries, so that the caller knows
5130 * what it has to do. It uses the last connection error to set the log when
5131 * it expires. It returns 1 when it has expired, and 0 otherwise.
5132 */
5133int srv_count_retry_down(struct session *t, int conn_err) {
5134 /* we are in front of a retryable error */
5135 t->conn_retries--;
5136 if (t->conn_retries < 0) {
5137 /* if not retryable anymore, let's abort */
5138 tv_eternity(&t->cnexpire);
5139 srv_close_with_err(t, conn_err, SN_FINST_C,
5140 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
5141
5142 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005143 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005144 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005145 if (may_dequeue_tasks(t->srv, t->proxy))
5146 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005147 return 1;
5148 }
5149 return 0;
5150}
willy tarreau0f7af912005-12-17 12:21:26 +01005151
5152/*
willy tarreaudfece232006-05-02 00:19:57 +02005153 * This function performs the retryable part of the connect() job.
5154 * It updates the session's srv_state and retries, so that the caller knows
5155 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
5156 * it needs to redispatch.
5157 */
5158int srv_retryable_connect(struct session *t) {
5159 int conn_err;
5160
5161 /* This loop ensures that we stop before the last retry in case of a
5162 * redispatchable server.
5163 */
5164 do {
5165 /* initiate a connection to the server */
5166 conn_err = connect_server(t);
5167 switch (conn_err) {
5168
5169 case SN_ERR_NONE:
5170 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
5171 t->srv_state = SV_STCONN;
5172 return 1;
5173
5174 case SN_ERR_INTERNAL:
5175 tv_eternity(&t->cnexpire);
5176 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5177 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
5178 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005179 if (may_dequeue_tasks(t->srv, t->proxy))
5180 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005181 return 1;
5182 }
5183 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02005184 if (srv_count_retry_down(t, conn_err)) {
5185 /* let's try to offer this slot to anybody */
5186 if (may_dequeue_tasks(t->srv, t->proxy))
5187 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005188 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02005189 }
willy tarreaudfece232006-05-02 00:19:57 +02005190 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
5191
5192 /* We're on our last chance, and the REDISP option was specified.
5193 * We will ignore cookie and force to balance or use the dispatcher.
5194 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005195 /* let's try to offer this slot to anybody */
5196 if (may_dequeue_tasks(t->srv, t->proxy))
5197 task_wakeup(&rq, t->srv->queue_mgt);
5198
willy tarreaudfece232006-05-02 00:19:57 +02005199 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5200 t->srv = NULL; /* it's left to the dispatcher to choose a server */
5201 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
5202 t->flags &= ~SN_CK_MASK;
5203 t->flags |= SN_CK_DOWN;
5204 }
5205 return 0;
5206}
5207
5208/* This function performs the "redispatch" part of a connection attempt. It
5209 * will assign a server if required, queue the connection if required, and
5210 * handle errors that might arise at this level. It can change the server
5211 * state. It will return 1 if it encounters an error, switches the server
5212 * state, or has to queue a connection. Otherwise, it will return 0 indicating
5213 * that the connection is ready to use.
5214 */
5215
5216int srv_redispatch_connect(struct session *t) {
5217 int conn_err;
5218
5219 /* We know that we don't have any connection pending, so we will
5220 * try to get a new one, and wait in this state if it's queued
5221 */
5222 conn_err = assign_server_and_queue(t);
5223 switch (conn_err) {
5224 case SRV_STATUS_OK:
5225 break;
5226
5227 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02005228 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02005229 tv_eternity(&t->cnexpire);
5230 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
5231 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaudfece232006-05-02 00:19:57 +02005232 return 1;
5233
5234 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02005235 /* FIXME-20060503 : we should use the queue timeout instead */
5236 if (t->proxy->contimeout)
5237 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
5238 else
5239 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02005240 t->srv_state = SV_STIDLE;
5241 /* do nothing else and do not wake any other session up */
5242 return 1;
5243
5244 case SRV_STATUS_FULL:
5245 case SRV_STATUS_INTERNAL:
5246 default:
5247 tv_eternity(&t->cnexpire);
5248 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
5249 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
5250 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02005251 if (may_dequeue_tasks(t->srv, t->proxy))
5252 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005253 return 1;
5254 }
5255 /* if we get here, it's because we got SRV_STATUS_OK, which also
5256 * means that the connection has not been queued.
5257 */
5258 return 0;
5259}
5260
5261
5262/*
willy tarreau0f7af912005-12-17 12:21:26 +01005263 * manages the server FSM and its socket. It returns 1 if a state has changed
5264 * (and a resync may be needed), 0 else.
5265 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005266int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01005267 int s = t->srv_state;
5268 int c = t->cli_state;
5269 struct buffer *req = t->req;
5270 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01005271 appsess *asession_temp = NULL;
5272 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01005273 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01005274
willy tarreau750a4722005-12-17 13:21:24 +01005275#ifdef DEBUG_FULL
5276 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
5277#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01005278 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
5279 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
5280 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
5281 //);
willy tarreau0f7af912005-12-17 12:21:26 +01005282 if (s == SV_STIDLE) {
5283 if (c == CL_STHEADERS)
5284 return 0; /* stay in idle, waiting for data to reach the client side */
5285 else if (c == CL_STCLOSE ||
5286 c == CL_STSHUTW ||
5287 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
5288 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02005289 if (t->pend_pos)
5290 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau51e91292006-05-14 23:29:47 +02005291 /* note that this must not return any error because it would be able to
5292 * overwrite the client_retnclose() output.
5293 */
willy tarreau078c79a2006-05-13 12:23:58 +02005294 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 +02005295
willy tarreau0f7af912005-12-17 12:21:26 +01005296 return 1;
5297 }
willy tarreaudfece232006-05-02 00:19:57 +02005298 else {
5299 /* Right now, we will need to create a connection to the server.
5300 * We might already have tried, and got a connection pending, in
5301 * which case we will not do anything till it's pending. It's up
5302 * to any other session to release it and wake us up again.
5303 */
willy tarreau45526ed2006-05-03 20:11:50 +02005304 if (t->pend_pos) {
5305 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
5306 return 0;
5307 else {
5308 /* we've been waiting too long here */
5309 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02005310 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
5311 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02005312 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
5313 return 1;
5314 }
5315 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005316
willy tarreaudfece232006-05-02 00:19:57 +02005317 do {
5318 /* first, get a connection */
5319 if (srv_redispatch_connect(t))
5320 return t->srv_state != SV_STIDLE;
5321
5322 /* try to (re-)connect to the server, and fail if we expire the
5323 * number of retries.
5324 */
willy tarreauf32f5242006-05-02 22:54:52 +02005325 if (srv_retryable_connect(t)) {
5326 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005327 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02005328 }
willy tarreaudfece232006-05-02 00:19:57 +02005329
5330 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005331 }
5332 }
5333 else if (s == SV_STCONN) { /* connection in progress */
5334 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01005335 //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 +01005336 return 0; /* nothing changed */
5337 }
5338 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02005339 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005340 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02005341
willy tarreau0f7af912005-12-17 12:21:26 +01005342 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005343 if (t->srv)
5344 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02005345
5346 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01005347 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
5348 else
willy tarreaudfece232006-05-02 00:19:57 +02005349 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01005350
willy tarreaudfece232006-05-02 00:19:57 +02005351 /* ensure that we have enough retries left */
5352 if (srv_count_retry_down(t, conn_err))
5353 return 1;
5354
5355 do {
5356 /* Now we will try to either reconnect to the same server or
5357 * connect to another server. If the connection gets queued
5358 * because all servers are saturated, then we will go back to
5359 * the SV_STIDLE state.
5360 */
willy tarreauf32f5242006-05-02 22:54:52 +02005361 if (srv_retryable_connect(t)) {
5362 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02005363 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02005364 }
willy tarreaudfece232006-05-02 00:19:57 +02005365
5366 /* we need to redispatch the connection to another server */
5367 if (srv_redispatch_connect(t))
5368 return t->srv_state != SV_STCONN;
5369 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01005370 }
5371 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01005372 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005373
willy tarreau0f7af912005-12-17 12:21:26 +01005374 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005375 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005376 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005377 tv_eternity(&t->swexpire);
5378 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01005379 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005380 if (t->proxy->srvtimeout) {
5381 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005382 /* FIXME: to prevent the server from expiring read timeouts during writes,
5383 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005384 t->srexpire = t->swexpire;
5385 }
5386 else
5387 tv_eternity(&t->swexpire);
5388 }
willy tarreau0f7af912005-12-17 12:21:26 +01005389
5390 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
5391 FD_SET(t->srv_fd, StaticReadEvent);
5392 if (t->proxy->srvtimeout)
5393 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5394 else
5395 tv_eternity(&t->srexpire);
5396
5397 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02005398 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005399 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01005400
5401 /* if the user wants to log as soon as possible, without counting
5402 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005403 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005404 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
5405 sess_log(t);
5406 }
willy tarreau0f7af912005-12-17 12:21:26 +01005407 }
willy tarreauef900ab2005-12-17 12:52:52 +01005408 else {
willy tarreau0f7af912005-12-17 12:21:26 +01005409 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02005410 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01005411 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
5412 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005413 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005414 return 1;
5415 }
5416 }
5417 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005418 /* now parse the partial (or complete) headers */
5419 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
5420 char *ptr;
5421 int delete_header;
5422
5423 ptr = rep->lr;
5424
5425 /* look for the end of the current header */
5426 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
5427 ptr++;
5428
5429 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005430 int line, len;
5431
5432 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01005433
5434 /* first, we'll block if security checks have caught nasty things */
5435 if (t->flags & SN_CACHEABLE) {
5436 if ((t->flags & SN_CACHE_COOK) &&
5437 (t->flags & SN_SCK_ANY) &&
5438 (t->proxy->options & PR_O_CHK_CACHE)) {
5439
5440 /* we're in presence of a cacheable response containing
5441 * a set-cookie header. We'll block it as requested by
5442 * the 'checkcache' option, and send an alert.
5443 */
5444 tv_eternity(&t->srexpire);
5445 tv_eternity(&t->swexpire);
5446 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005447 if (t->srv)
5448 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01005449 t->srv_state = SV_STCLOSE;
5450 t->logs.status = 502;
5451 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5452 if (!(t->flags & SN_ERR_MASK))
5453 t->flags |= SN_ERR_PRXCOND;
5454 if (!(t->flags & SN_FINST_MASK))
5455 t->flags |= SN_FINST_H;
5456
5457 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5458 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5459
willy tarreaudfece232006-05-02 00:19:57 +02005460 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005461 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005462 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005463 if (may_dequeue_tasks(t->srv, t->proxy))
5464 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005465
willy tarreau97f58572005-12-18 00:53:44 +01005466 return 1;
5467 }
5468 }
5469
willy tarreau982249e2005-12-18 00:57:06 +01005470 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
5471 if (t->flags & SN_SVDENY) {
5472 tv_eternity(&t->srexpire);
5473 tv_eternity(&t->swexpire);
5474 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005475 if (t->srv)
5476 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01005477 t->srv_state = SV_STCLOSE;
5478 t->logs.status = 502;
5479 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5480 if (!(t->flags & SN_ERR_MASK))
5481 t->flags |= SN_ERR_PRXCOND;
5482 if (!(t->flags & SN_FINST_MASK))
5483 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005484 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005485 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005486 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005487 if (may_dequeue_tasks(t->srv, t->proxy))
5488 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005489
willy tarreau982249e2005-12-18 00:57:06 +01005490 return 1;
5491 }
5492
willy tarreau5cbea6f2005-12-17 12:48:26 +01005493 /* we'll have something else to do here : add new headers ... */
5494
willy tarreaucd878942005-12-17 13:27:43 +01005495 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
5496 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005497 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01005498 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02005499 * requests and this one isn't. Note that servers which don't have cookies
5500 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005501 */
willy tarreau750a4722005-12-17 13:21:24 +01005502 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01005503 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02005504 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01005505
willy tarreau036e1ce2005-12-17 13:46:33 +01005506 t->flags |= SN_SCK_INSERTED;
5507
willy tarreau750a4722005-12-17 13:21:24 +01005508 /* Here, we will tell an eventual cache on the client side that we don't
5509 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
5510 * Some caches understand the correct form: 'no-cache="set-cookie"', but
5511 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
5512 */
willy tarreau240afa62005-12-17 13:14:35 +01005513 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01005514 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
5515 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01005516
5517 if (rep->data + rep->l < rep->h)
5518 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
5519 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01005520 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005521 }
5522
5523 /* headers to be added */
5524 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01005525 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
5526 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005527 }
5528
willy tarreau25c4ea52005-12-18 00:49:49 +01005529 /* add a "connection: close" line if needed */
5530 if (t->proxy->options & PR_O_HTTP_CLOSE)
5531 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
5532
willy tarreau5cbea6f2005-12-17 12:48:26 +01005533 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01005534 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01005535 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01005536
Willy TARREAU767ba712006-03-01 22:40:50 +01005537 /* client connection already closed or option 'httpclose' required :
5538 * we close the server's outgoing connection right now.
5539 */
5540 if ((req->l == 0) &&
5541 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5542 FD_CLR(t->srv_fd, StaticWriteEvent);
5543 tv_eternity(&t->swexpire);
5544
5545 /* We must ensure that the read part is still alive when switching
5546 * to shutw */
5547 FD_SET(t->srv_fd, StaticReadEvent);
5548 if (t->proxy->srvtimeout)
5549 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5550
5551 shutdown(t->srv_fd, SHUT_WR);
5552 t->srv_state = SV_STSHUTW;
5553 }
5554
willy tarreau25c4ea52005-12-18 00:49:49 +01005555 /* if the user wants to log as soon as possible, without counting
5556 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005557 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005558 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5559 t->logs.bytes = rep->h - rep->data;
5560 sess_log(t);
5561 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005562 break;
5563 }
5564
5565 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5566 if (ptr > rep->r - 2) {
5567 /* this is a partial header, let's wait for more to come */
5568 rep->lr = ptr;
5569 break;
5570 }
5571
5572 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5573 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5574
5575 /* now we know that *ptr is either \r or \n,
5576 * and that there are at least 1 char after it.
5577 */
5578 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5579 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5580 else
5581 rep->lr = ptr + 2; /* \r\n or \n\r */
5582
5583 /*
5584 * now we know that we have a full header ; we can do whatever
5585 * we want with these pointers :
5586 * rep->h = beginning of header
5587 * ptr = end of header (first \r or \n)
5588 * rep->lr = beginning of next line (next rep->h)
5589 * rep->r = end of data (not used at this stage)
5590 */
5591
willy tarreaua1598082005-12-17 13:08:06 +01005592
willy tarreau982249e2005-12-18 00:57:06 +01005593 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005594 t->logs.logwait &= ~LW_RESP;
5595 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005596 switch (t->logs.status) {
5597 case 200:
5598 case 203:
5599 case 206:
5600 case 300:
5601 case 301:
5602 case 410:
5603 /* RFC2616 @13.4:
5604 * "A response received with a status code of
5605 * 200, 203, 206, 300, 301 or 410 MAY be stored
5606 * by a cache (...) unless a cache-control
5607 * directive prohibits caching."
5608 *
5609 * RFC2616 @9.5: POST method :
5610 * "Responses to this method are not cacheable,
5611 * unless the response includes appropriate
5612 * Cache-Control or Expires header fields."
5613 */
5614 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5615 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5616 break;
5617 default:
5618 break;
5619 }
willy tarreau4302f492005-12-18 01:00:37 +01005620 }
5621 else if (t->logs.logwait & LW_RSPHDR) {
5622 struct cap_hdr *h;
5623 int len;
5624 for (h = t->proxy->rsp_cap; h; h = h->next) {
5625 if ((h->namelen + 2 <= ptr - rep->h) &&
5626 (rep->h[h->namelen] == ':') &&
5627 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5628
5629 if (t->rsp_cap[h->index] == NULL)
5630 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5631
5632 len = ptr - (rep->h + h->namelen + 2);
5633 if (len > h->len)
5634 len = h->len;
5635
5636 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5637 t->rsp_cap[h->index][len]=0;
5638 }
5639 }
5640
willy tarreaua1598082005-12-17 13:08:06 +01005641 }
5642
willy tarreau5cbea6f2005-12-17 12:48:26 +01005643 delete_header = 0;
5644
willy tarreau982249e2005-12-18 00:57:06 +01005645 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005646 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005647 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 +01005648 max = ptr - rep->h;
5649 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005650 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005651 trash[len++] = '\n';
5652 write(1, trash, len);
5653 }
5654
willy tarreau25c4ea52005-12-18 00:49:49 +01005655 /* remove "connection: " if needed */
5656 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5657 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5658 delete_header = 1;
5659 }
5660
willy tarreau5cbea6f2005-12-17 12:48:26 +01005661 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005662 if (!delete_header && t->proxy->rsp_exp != NULL
5663 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005664 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005665 char term;
5666
5667 term = *ptr;
5668 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005669 exp = t->proxy->rsp_exp;
5670 do {
5671 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5672 switch (exp->action) {
5673 case ACT_ALLOW:
5674 if (!(t->flags & SN_SVDENY))
5675 t->flags |= SN_SVALLOW;
5676 break;
5677 case ACT_REPLACE:
5678 if (!(t->flags & SN_SVDENY)) {
5679 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5680 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5681 }
5682 break;
5683 case ACT_REMOVE:
5684 if (!(t->flags & SN_SVDENY))
5685 delete_header = 1;
5686 break;
5687 case ACT_DENY:
5688 if (!(t->flags & SN_SVALLOW))
5689 t->flags |= SN_SVDENY;
5690 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005691 case ACT_PASS: /* we simply don't deny this one */
5692 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005693 }
5694 break;
5695 }
willy tarreaue39cd132005-12-17 13:00:18 +01005696 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005697 *ptr = term; /* restore the string terminator */
5698 }
5699
willy tarreau97f58572005-12-18 00:53:44 +01005700 /* check for cache-control: or pragma: headers */
5701 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5702 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5703 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5704 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5705 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005706 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005707 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5708 else {
5709 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005710 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005711 t->flags &= ~SN_CACHE_COOK;
5712 }
5713 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005714 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005715 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005716 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005717 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5718 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005719 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005720 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005721 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5722 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5723 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5724 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5725 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5726 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005727 }
5728 }
5729 }
5730
willy tarreau5cbea6f2005-12-17 12:48:26 +01005731 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005732 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005733 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005734 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005735 char *p1, *p2, *p3, *p4;
5736
willy tarreau97f58572005-12-18 00:53:44 +01005737 t->flags |= SN_SCK_ANY;
5738
willy tarreau5cbea6f2005-12-17 12:48:26 +01005739 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5740
5741 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005742 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005743 p1++;
5744
5745 if (p1 == ptr || *p1 == ';') /* end of cookie */
5746 break;
5747
5748 /* p1 is at the beginning of the cookie name */
5749 p2 = p1;
5750
5751 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5752 p2++;
5753
5754 if (p2 == ptr || *p2 == ';') /* next cookie */
5755 break;
5756
5757 p3 = p2 + 1; /* skips the '=' sign */
5758 if (p3 == ptr)
5759 break;
5760
5761 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005762 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005763 p4++;
5764
5765 /* here, we have the cookie name between p1 and p2,
5766 * and its value between p3 and p4.
5767 * we can process it.
5768 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005769
5770 /* first, let's see if we want to capture it */
5771 if (t->proxy->capture_name != NULL &&
5772 t->logs.srv_cookie == NULL &&
5773 (p4 - p1 >= t->proxy->capture_namelen) &&
5774 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5775 int log_len = p4 - p1;
5776
5777 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5778 Alert("HTTP logging : out of memory.\n");
5779 }
5780
5781 if (log_len > t->proxy->capture_len)
5782 log_len = t->proxy->capture_len;
5783 memcpy(t->logs.srv_cookie, p1, log_len);
5784 t->logs.srv_cookie[log_len] = 0;
5785 }
5786
5787 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5788 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005789 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005790 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005791
5792 /* If the cookie is in insert mode on a known server, we'll delete
5793 * this occurrence because we'll insert another one later.
5794 * We'll delete it too if the "indirect" option is set and we're in
5795 * a direct access. */
5796 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005797 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005798 /* this header must be deleted */
5799 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005800 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005801 }
5802 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5803 /* replace bytes p3->p4 with the cookie name associated
5804 * with this server since we know it.
5805 */
5806 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005807 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005808 }
willy tarreau0174f312005-12-18 01:02:42 +01005809 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5810 /* insert the cookie name associated with this server
5811 * before existing cookie, and insert a delimitor between them..
5812 */
5813 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5814 p3[t->srv->cklen] = COOKIE_DELIM;
5815 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5816 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005817 break;
5818 }
willy tarreau12350152005-12-18 01:03:27 +01005819
5820 /* first, let's see if the cookie is our appcookie*/
5821 if ((t->proxy->appsession_name != NULL) &&
5822 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5823
5824 /* Cool... it's the right one */
5825
willy tarreaub952e1d2005-12-18 01:31:20 +01005826 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005827 asession_temp = &local_asession;
5828
willy tarreaub952e1d2005-12-18 01:31:20 +01005829 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005830 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5831 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5832 }
5833 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5834 asession_temp->sessid[t->proxy->appsession_len] = 0;
5835 asession_temp->serverid = NULL;
5836
5837 /* only do insert, if lookup fails */
5838 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5839 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5840 Alert("Not enought Memory process_srv():asession:calloc().\n");
5841 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5842 return 0;
5843 }
5844 asession_temp->sessid = local_asession.sessid;
5845 asession_temp->serverid = local_asession.serverid;
5846 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005847 }/* end if (chtbl_lookup()) */
5848 else {
willy tarreau12350152005-12-18 01:03:27 +01005849 /* free wasted memory */
5850 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005851 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005852
willy tarreaub952e1d2005-12-18 01:31:20 +01005853 if (asession_temp->serverid == NULL) {
5854 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005855 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5856 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5857 }
5858 asession_temp->serverid[0] = '\0';
5859 }
5860
willy tarreaub952e1d2005-12-18 01:31:20 +01005861 if (asession_temp->serverid[0] == '\0')
5862 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005863
5864 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5865
5866#if defined(DEBUG_HASH)
5867 print_table(&(t->proxy->htbl_proxy));
5868#endif
5869 break;
5870 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005871 else {
5872 // fprintf(stderr,"Ignoring unknown cookie : ");
5873 // write(2, p1, p2-p1);
5874 // fprintf(stderr," = ");
5875 // write(2, p3, p4-p3);
5876 // fprintf(stderr,"\n");
5877 }
5878 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5879 } /* we're now at the end of the cookie value */
5880 } /* end of cookie processing */
5881
willy tarreau97f58572005-12-18 00:53:44 +01005882 /* check for any set-cookie in case we check for cacheability */
5883 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5884 (t->proxy->options & PR_O_CHK_CACHE) &&
5885 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5886 t->flags |= SN_SCK_ANY;
5887 }
5888
willy tarreau5cbea6f2005-12-17 12:48:26 +01005889 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005890 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005891 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005892
willy tarreau5cbea6f2005-12-17 12:48:26 +01005893 rep->h = rep->lr;
5894 } /* while (rep->lr < rep->r) */
5895
5896 /* end of header processing (even if incomplete) */
5897
willy tarreauef900ab2005-12-17 12:52:52 +01005898 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5899 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5900 * full. We cannot loop here since event_srv_read will disable it only if
5901 * rep->l == rlim-data
5902 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005903 FD_SET(t->srv_fd, StaticReadEvent);
5904 if (t->proxy->srvtimeout)
5905 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5906 else
5907 tv_eternity(&t->srexpire);
5908 }
willy tarreau0f7af912005-12-17 12:21:26 +01005909
willy tarreau8337c6b2005-12-17 13:41:01 +01005910 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005911 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005912 tv_eternity(&t->srexpire);
5913 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005914 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005915 if (t->srv)
5916 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005917 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005918 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005919 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005920 if (!(t->flags & SN_ERR_MASK))
5921 t->flags |= SN_ERR_SRVCL;
5922 if (!(t->flags & SN_FINST_MASK))
5923 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005924 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005925 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005926 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005927 if (may_dequeue_tasks(t->srv, t->proxy))
5928 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005929
willy tarreau0f7af912005-12-17 12:21:26 +01005930 return 1;
5931 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005932 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005933 * since we are in header mode, if there's no space left for headers, we
5934 * won't be able to free more later, so the session will never terminate.
5935 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005936 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 +01005937 FD_CLR(t->srv_fd, StaticReadEvent);
5938 tv_eternity(&t->srexpire);
5939 shutdown(t->srv_fd, SHUT_RD);
5940 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005941 //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 +01005942 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005943 }
5944 /* read timeout : return a 504 to the client.
5945 */
5946 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5947 tv_eternity(&t->srexpire);
5948 tv_eternity(&t->swexpire);
5949 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005950 if (t->srv)
5951 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005952 t->srv_state = SV_STCLOSE;
5953 t->logs.status = 504;
5954 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005955 if (!(t->flags & SN_ERR_MASK))
5956 t->flags |= SN_ERR_SRVTO;
5957 if (!(t->flags & SN_FINST_MASK))
5958 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005959 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005960 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005961 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005962 if (may_dequeue_tasks(t->srv, t->proxy))
5963 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005964
willy tarreau8337c6b2005-12-17 13:41:01 +01005965 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005966 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005967 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005968 /* FIXME!!! here, we don't want to switch to SHUTW if the
5969 * client shuts read too early, because we may still have
5970 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005971 * The side-effect is that if the client completely closes its
5972 * connection during SV_STHEADER, the connection to the server
5973 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005974 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005975 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005976 FD_CLR(t->srv_fd, StaticWriteEvent);
5977 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005978
5979 /* We must ensure that the read part is still alive when switching
5980 * to shutw */
5981 FD_SET(t->srv_fd, StaticReadEvent);
5982 if (t->proxy->srvtimeout)
5983 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5984
willy tarreau0f7af912005-12-17 12:21:26 +01005985 shutdown(t->srv_fd, SHUT_WR);
5986 t->srv_state = SV_STSHUTW;
5987 return 1;
5988 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005989 /* write timeout */
5990 /* FIXME!!! here, we don't want to switch to SHUTW if the
5991 * client shuts read too early, because we may still have
5992 * some work to do on the headers.
5993 */
5994 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5995 FD_CLR(t->srv_fd, StaticWriteEvent);
5996 tv_eternity(&t->swexpire);
5997 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005998 /* We must ensure that the read part is still alive when switching
5999 * to shutw */
6000 FD_SET(t->srv_fd, StaticReadEvent);
6001 if (t->proxy->srvtimeout)
6002 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6003
6004 /* We must ensure that the read part is still alive when switching
6005 * to shutw */
6006 FD_SET(t->srv_fd, StaticReadEvent);
6007 if (t->proxy->srvtimeout)
6008 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6009
willy tarreau036e1ce2005-12-17 13:46:33 +01006010 t->srv_state = SV_STSHUTW;
6011 if (!(t->flags & SN_ERR_MASK))
6012 t->flags |= SN_ERR_SRVTO;
6013 if (!(t->flags & SN_FINST_MASK))
6014 t->flags |= SN_FINST_H;
6015 return 1;
6016 }
willy tarreau0f7af912005-12-17 12:21:26 +01006017
6018 if (req->l == 0) {
6019 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6020 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6021 tv_eternity(&t->swexpire);
6022 }
6023 }
6024 else { /* client buffer not empty */
6025 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6026 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006027 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006028 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006029 /* FIXME: to prevent the server from expiring read timeouts during writes,
6030 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006031 t->srexpire = t->swexpire;
6032 }
willy tarreau0f7af912005-12-17 12:21:26 +01006033 else
6034 tv_eternity(&t->swexpire);
6035 }
6036 }
6037
willy tarreau5cbea6f2005-12-17 12:48:26 +01006038 /* be nice with the client side which would like to send a complete header
6039 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
6040 * would read all remaining data at once ! The client should not write past rep->lr
6041 * when the server is in header state.
6042 */
6043 //return header_processed;
6044 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01006045 }
6046 else if (s == SV_STDATA) {
6047 /* read or write error */
6048 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01006049 tv_eternity(&t->srexpire);
6050 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006051 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006052 if (t->srv)
6053 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01006054 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006055 if (!(t->flags & SN_ERR_MASK))
6056 t->flags |= SN_ERR_SRVCL;
6057 if (!(t->flags & SN_FINST_MASK))
6058 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006059 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006060 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006061 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006062 if (may_dequeue_tasks(t->srv, t->proxy))
6063 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006064
willy tarreau0f7af912005-12-17 12:21:26 +01006065 return 1;
6066 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006067 /* last read, or end of client write */
6068 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006069 FD_CLR(t->srv_fd, StaticReadEvent);
6070 tv_eternity(&t->srexpire);
6071 shutdown(t->srv_fd, SHUT_RD);
6072 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01006073 //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 +01006074 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006075 }
6076 /* end of client read and no more data to send */
6077 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
6078 FD_CLR(t->srv_fd, StaticWriteEvent);
6079 tv_eternity(&t->swexpire);
6080 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006081 /* We must ensure that the read part is still alive when switching
6082 * to shutw */
6083 FD_SET(t->srv_fd, StaticReadEvent);
6084 if (t->proxy->srvtimeout)
6085 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6086
willy tarreaua41a8b42005-12-17 14:02:24 +01006087 t->srv_state = SV_STSHUTW;
6088 return 1;
6089 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006090 /* read timeout */
6091 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6092 FD_CLR(t->srv_fd, StaticReadEvent);
6093 tv_eternity(&t->srexpire);
6094 shutdown(t->srv_fd, SHUT_RD);
6095 t->srv_state = SV_STSHUTR;
6096 if (!(t->flags & SN_ERR_MASK))
6097 t->flags |= SN_ERR_SRVTO;
6098 if (!(t->flags & SN_FINST_MASK))
6099 t->flags |= SN_FINST_D;
6100 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006101 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006102 /* write timeout */
6103 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006104 FD_CLR(t->srv_fd, StaticWriteEvent);
6105 tv_eternity(&t->swexpire);
6106 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01006107 /* We must ensure that the read part is still alive when switching
6108 * to shutw */
6109 FD_SET(t->srv_fd, StaticReadEvent);
6110 if (t->proxy->srvtimeout)
6111 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01006112 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01006113 if (!(t->flags & SN_ERR_MASK))
6114 t->flags |= SN_ERR_SRVTO;
6115 if (!(t->flags & SN_FINST_MASK))
6116 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01006117 return 1;
6118 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006119
6120 /* recompute request time-outs */
6121 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01006122 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6123 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6124 tv_eternity(&t->swexpire);
6125 }
6126 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01006127 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01006128 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6129 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006130 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006131 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006132 /* FIXME: to prevent the server from expiring read timeouts during writes,
6133 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006134 t->srexpire = t->swexpire;
6135 }
willy tarreau0f7af912005-12-17 12:21:26 +01006136 else
6137 tv_eternity(&t->swexpire);
6138 }
6139 }
6140
willy tarreaub1ff9db2005-12-17 13:51:03 +01006141 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01006142 if (rep->l == BUFSIZE) { /* no room to read more data */
6143 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6144 FD_CLR(t->srv_fd, StaticReadEvent);
6145 tv_eternity(&t->srexpire);
6146 }
6147 }
6148 else {
6149 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6150 FD_SET(t->srv_fd, StaticReadEvent);
6151 if (t->proxy->srvtimeout)
6152 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6153 else
6154 tv_eternity(&t->srexpire);
6155 }
6156 }
6157
6158 return 0; /* other cases change nothing */
6159 }
6160 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006161 if (t->res_sw == RES_ERROR) {
6162 //FD_CLR(t->srv_fd, StaticWriteEvent);
6163 tv_eternity(&t->swexpire);
6164 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006165 if (t->srv)
6166 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006167 //close(t->srv_fd);
6168 t->srv_state = SV_STCLOSE;
6169 if (!(t->flags & SN_ERR_MASK))
6170 t->flags |= SN_ERR_SRVCL;
6171 if (!(t->flags & SN_FINST_MASK))
6172 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006173 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006174 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006175 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006176 if (may_dequeue_tasks(t->srv, t->proxy))
6177 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006178
willy tarreau036e1ce2005-12-17 13:46:33 +01006179 return 1;
6180 }
6181 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006182 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006183 tv_eternity(&t->swexpire);
6184 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006185 if (t->srv)
6186 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006187 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006188 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006189 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006190 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006191 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006192 if (may_dequeue_tasks(t->srv, t->proxy))
6193 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006194
willy tarreau0f7af912005-12-17 12:21:26 +01006195 return 1;
6196 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006197 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
6198 //FD_CLR(t->srv_fd, StaticWriteEvent);
6199 tv_eternity(&t->swexpire);
6200 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006201 if (t->srv)
6202 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006203 //close(t->srv_fd);
6204 t->srv_state = SV_STCLOSE;
6205 if (!(t->flags & SN_ERR_MASK))
6206 t->flags |= SN_ERR_SRVTO;
6207 if (!(t->flags & SN_FINST_MASK))
6208 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006209 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006210 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006211 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006212 if (may_dequeue_tasks(t->srv, t->proxy))
6213 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006214
willy tarreau036e1ce2005-12-17 13:46:33 +01006215 return 1;
6216 }
willy tarreau0f7af912005-12-17 12:21:26 +01006217 else if (req->l == 0) {
6218 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6219 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
6220 tv_eternity(&t->swexpire);
6221 }
6222 }
6223 else { /* buffer not empty */
6224 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
6225 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006226 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01006227 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02006228 /* FIXME: to prevent the server from expiring read timeouts during writes,
6229 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01006230 t->srexpire = t->swexpire;
6231 }
willy tarreau0f7af912005-12-17 12:21:26 +01006232 else
6233 tv_eternity(&t->swexpire);
6234 }
6235 }
6236 return 0;
6237 }
6238 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006239 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006240 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01006241 tv_eternity(&t->srexpire);
6242 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006243 if (t->srv)
6244 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006245 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01006246 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01006247 if (!(t->flags & SN_ERR_MASK))
6248 t->flags |= SN_ERR_SRVCL;
6249 if (!(t->flags & SN_FINST_MASK))
6250 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006251 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006252 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006253 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006254 if (may_dequeue_tasks(t->srv, t->proxy))
6255 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006256
willy tarreau0f7af912005-12-17 12:21:26 +01006257 return 1;
6258 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006259 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
6260 //FD_CLR(t->srv_fd, StaticReadEvent);
6261 tv_eternity(&t->srexpire);
6262 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006263 if (t->srv)
6264 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006265 //close(t->srv_fd);
6266 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02006267 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006268 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006269 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006270 if (may_dequeue_tasks(t->srv, t->proxy))
6271 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006272
willy tarreau036e1ce2005-12-17 13:46:33 +01006273 return 1;
6274 }
6275 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
6276 //FD_CLR(t->srv_fd, StaticReadEvent);
6277 tv_eternity(&t->srexpire);
6278 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02006279 if (t->srv)
6280 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01006281 //close(t->srv_fd);
6282 t->srv_state = SV_STCLOSE;
6283 if (!(t->flags & SN_ERR_MASK))
6284 t->flags |= SN_ERR_SRVTO;
6285 if (!(t->flags & SN_FINST_MASK))
6286 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02006287 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02006288 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02006289 */
willy tarreau59a6cc22006-05-12 01:29:08 +02006290 if (may_dequeue_tasks(t->srv, t->proxy))
6291 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02006292
willy tarreau036e1ce2005-12-17 13:46:33 +01006293 return 1;
6294 }
willy tarreau0f7af912005-12-17 12:21:26 +01006295 else if (rep->l == BUFSIZE) { /* no room to read more data */
6296 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
6297 FD_CLR(t->srv_fd, StaticReadEvent);
6298 tv_eternity(&t->srexpire);
6299 }
6300 }
6301 else {
6302 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
6303 FD_SET(t->srv_fd, StaticReadEvent);
6304 if (t->proxy->srvtimeout)
6305 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
6306 else
6307 tv_eternity(&t->srexpire);
6308 }
6309 }
6310 return 0;
6311 }
6312 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01006313 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006314 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006315 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 +01006316 write(1, trash, len);
6317 }
6318 return 0;
6319 }
6320 return 0;
6321}
6322
6323
willy tarreau5cbea6f2005-12-17 12:48:26 +01006324/* Processes the client and server jobs of a session task, then
6325 * puts it back to the wait queue in a clean state, or
6326 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006327 * the time the task accepts to wait, or TIME_ETERNITY for
6328 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01006329 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006330int process_session(struct task *t) {
6331 struct session *s = t->context;
6332 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006333
willy tarreau5cbea6f2005-12-17 12:48:26 +01006334 do {
6335 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01006336 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006337 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006338 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006339 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01006340 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006341 } while (fsm_resync);
6342
6343 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01006344 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006345 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01006346
willy tarreau5cbea6f2005-12-17 12:48:26 +01006347 tv_min(&min1, &s->crexpire, &s->cwexpire);
6348 tv_min(&min2, &s->srexpire, &s->swexpire);
6349 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01006350 tv_min(&t->expire, &min1, &min2);
6351
6352 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006353 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01006354
Willy TARREAU1cec83c2006-03-01 22:33:49 +01006355#ifdef DEBUG_FULL
6356 /* DEBUG code : this should never ever happen, otherwise it indicates
6357 * that a task still has something to do and will provoke a quick loop.
6358 */
6359 if (tv_remain2(&now, &t->expire) <= 0)
6360 exit(100);
6361#endif
6362
willy tarreaub952e1d2005-12-18 01:31:20 +01006363 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01006364 }
6365
willy tarreau5cbea6f2005-12-17 12:48:26 +01006366 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01006367 actconn--;
6368
willy tarreau982249e2005-12-18 00:57:06 +01006369 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01006370 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01006371 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 +01006372 write(1, trash, len);
6373 }
6374
willy tarreau750a4722005-12-17 13:21:24 +01006375 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01006376 if (s->rep != NULL)
6377 s->logs.bytes = s->rep->total;
6378
willy tarreau9fe663a2005-12-17 13:02:59 +01006379 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01006380 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01006381 sess_log(s);
6382
willy tarreau0f7af912005-12-17 12:21:26 +01006383 /* the task MUST not be in the run queue anymore */
6384 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006385 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01006386 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01006387 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006388}
6389
6390
willy tarreau2812edc2006-05-04 12:09:37 +02006391/* Sets server <s> down, notifies by all available means, recounts the
6392 * remaining servers on the proxy and transfers queued sessions whenever
6393 * possible to other servers.
6394 */
6395void set_server_down(struct server *s) {
6396 struct pendconn *pc, *pc_bck, *pc_end;
6397 struct session *sess;
6398 int xferred;
6399
6400 s->state &= ~SRV_RUNNING;
6401
6402 if (s->health == s->rise) {
6403 recount_servers(s->proxy);
6404 recalc_server_map(s->proxy);
6405
6406 /* we might have sessions queued on this server and waiting for
6407 * a connection. Those which are redispatchable will be queued
6408 * to another server or to the proxy itself.
6409 */
6410 xferred = 0;
6411 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
6412 sess = pc->sess;
6413 if ((sess->proxy->options & PR_O_REDISP)) {
6414 /* The REDISP option was specified. We will ignore
6415 * cookie and force to balance or use the dispatcher.
6416 */
6417 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
6418 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
6419 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
6420 sess->flags &= ~SN_CK_MASK;
6421 sess->flags |= SN_CK_DOWN;
6422 }
6423 pendconn_free(pc);
6424 task_wakeup(&rq, sess->task);
6425 xferred++;
6426 }
6427 }
6428
6429 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
6430 " %d sessions active, %d requeued, %d remaining in queue.\n",
6431 s->state & SRV_BACKUP ? "Backup " : "",
6432 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6433 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6434 s->cur_sess, xferred, s->nbpend);
6435
willy tarreaubc2eda62006-05-04 15:16:23 +02006436 Warning("%s", trash);
6437 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02006438
6439 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
6440 Alert("Proxy %s has no server available !\n", s->proxy->id);
6441 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
6442 }
willy tarreaucb406512006-05-18 00:52:35 +02006443 s->down_trans++;
willy tarreau2812edc2006-05-04 12:09:37 +02006444 }
6445 s->health = 0; /* failure */
6446}
6447
6448
willy tarreau5cbea6f2005-12-17 12:48:26 +01006449
6450/*
6451 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006452 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01006453 */
6454int process_chk(struct task *t) {
6455 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01006456 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01006457 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006458
willy tarreauef900ab2005-12-17 12:52:52 +01006459 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006460
willy tarreau25424f82006-03-19 19:37:48 +01006461 new_chk:
6462 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006463 if (fd < 0) { /* no check currently running */
6464 //fprintf(stderr, "process_chk: 2\n");
6465 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
6466 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006467 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006468 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006469
6470 /* we don't send any health-checks when the proxy is stopped or when
6471 * the server should not be checked.
6472 */
6473 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01006474 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6475 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01006476 task_queue(t); /* restore t to its place in the task list */
6477 return tv_remain2(&now, &t->expire);
6478 }
6479
willy tarreau5cbea6f2005-12-17 12:48:26 +01006480 /* we'll initiate a new check */
6481 s->result = 0; /* no result yet */
6482 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006483 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01006484 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
6485 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
6486 //fprintf(stderr, "process_chk: 3\n");
6487
willy tarreaua41a8b42005-12-17 14:02:24 +01006488 /* we'll connect to the check port on the server */
6489 sa = s->addr;
6490 sa.sin_port = htons(s->check_port);
6491
willy tarreau0174f312005-12-18 01:02:42 +01006492 /* allow specific binding :
6493 * - server-specific at first
6494 * - proxy-specific next
6495 */
6496 if (s->state & SRV_BIND_SRC) {
6497 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6498 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
6499 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
6500 s->proxy->id, s->id);
6501 s->result = -1;
6502 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006503 }
willy tarreau0174f312005-12-18 01:02:42 +01006504 else if (s->proxy->options & PR_O_BIND_SRC) {
6505 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6506 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
6507 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
6508 s->proxy->id);
6509 s->result = -1;
6510 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006511 }
willy tarreau0174f312005-12-18 01:02:42 +01006512
6513 if (!s->result) {
6514 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
6515 /* OK, connection in progress or established */
6516
6517 //fprintf(stderr, "process_chk: 4\n");
6518
6519 s->curfd = fd; /* that's how we know a test is in progress ;-) */
6520 fdtab[fd].owner = t;
6521 fdtab[fd].read = &event_srv_chk_r;
6522 fdtab[fd].write = &event_srv_chk_w;
6523 fdtab[fd].state = FD_STCONN; /* connection in progress */
6524 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01006525#ifdef DEBUG_FULL
6526 assert (!FD_ISSET(fd, StaticReadEvent));
6527#endif
willy tarreau0174f312005-12-18 01:02:42 +01006528 fd_insert(fd);
6529 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
6530 tv_delayfrom(&t->expire, &now, s->inter);
6531 task_queue(t); /* restore t to its place in the task list */
6532 return tv_remain(&now, &t->expire);
6533 }
6534 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
6535 s->result = -1; /* a real error */
6536 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006537 }
6538 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006539 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006540 }
6541
6542 if (!s->result) { /* nothing done */
6543 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006544 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6545 tv_delayfrom(&t->expire, &t->expire, s->inter);
6546 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006547 }
6548
6549 /* here, we have seen a failure */
willy tarreaucb406512006-05-18 00:52:35 +02006550 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006551 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006552 s->failed_checks++;
6553 }
willy tarreau2812edc2006-05-04 12:09:37 +02006554 else
6555 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006556
6557 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006558 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006559 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6560 tv_delayfrom(&t->expire, &t->expire, s->inter);
6561 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006562 }
6563 else {
6564 //fprintf(stderr, "process_chk: 8\n");
6565 /* there was a test running */
6566 if (s->result > 0) { /* good server detected */
6567 //fprintf(stderr, "process_chk: 9\n");
6568 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006569 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006570 s->state |= SRV_RUNNING;
6571
willy tarreau535ae7a2005-12-17 12:58:00 +01006572 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006573 int xferred;
6574
willy tarreau62084d42006-03-24 18:57:41 +01006575 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006576 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006577
6578 /* check if we can handle some connections queued at the proxy. We
6579 * will take as many as we can handle.
6580 */
6581 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
6582 struct session *sess;
6583 struct pendconn *p;
6584
6585 p = pendconn_from_px(s->proxy);
6586 if (!p)
6587 break;
6588 p->sess->srv = s;
6589 sess = p->sess;
6590 pendconn_free(p);
6591 task_wakeup(&rq, sess->task);
6592 }
6593
6594 sprintf(trash,
6595 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6596 " %d sessions requeued, %d total in queue.\n",
6597 s->state & SRV_BACKUP ? "Backup " : "",
6598 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6599 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6600 xferred, s->nbpend);
6601
6602 Warning("%s", trash);
6603 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006604 }
willy tarreauef900ab2005-12-17 12:52:52 +01006605
willy tarreaue47c8d72005-12-17 12:55:52 +01006606 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006607 }
willy tarreauef900ab2005-12-17 12:52:52 +01006608 s->curfd = -1; /* no check running anymore */
6609 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006610 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006611 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6612 tv_delayfrom(&t->expire, &t->expire, s->inter);
6613 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006614 }
6615 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6616 //fprintf(stderr, "process_chk: 10\n");
6617 /* failure or timeout detected */
willy tarreaucb406512006-05-18 00:52:35 +02006618 if (s->health > s->rise) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006619 s->health--; /* still good */
willy tarreaucb406512006-05-18 00:52:35 +02006620 s->failed_checks++;
6621 }
willy tarreau2812edc2006-05-04 12:09:37 +02006622 else
6623 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006624 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006625 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006626 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006627 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6628 tv_delayfrom(&t->expire, &t->expire, s->inter);
6629 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006630 }
6631 /* if result is 0 and there's no timeout, we have to wait again */
6632 }
6633 //fprintf(stderr, "process_chk: 11\n");
6634 s->result = 0;
6635 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006636 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006637}
6638
6639
willy tarreau5cbea6f2005-12-17 12:48:26 +01006640
willy tarreau59a6cc22006-05-12 01:29:08 +02006641/*
6642 * Manages a server's connection queue. If woken up, will try to dequeue as
6643 * many pending sessions as possible, and wake them up. The task has nothing
6644 * else to do, so it always returns TIME_ETERNITY.
6645 */
6646int process_srv_queue(struct task *t) {
6647 struct server *s = (struct server*)t->context;
6648 struct proxy *p = s->proxy;
6649 int xferred;
6650
6651 /* First, check if we can handle some connections queued at the proxy. We
6652 * will take as many as we can handle.
6653 */
6654 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6655 struct session *sess;
6656
6657 sess = pendconn_get_next_sess(s, p);
6658 if (sess == NULL)
6659 break;
6660 task_wakeup(&rq, sess->task);
6661 }
6662
6663 return TIME_ETERNITY;
6664}
6665
willy tarreau0f7af912005-12-17 12:21:26 +01006666#if STATTIME > 0
6667int stats(void);
6668#endif
6669
6670/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006671 * This does 4 things :
6672 * - wake up all expired tasks
6673 * - call all runnable tasks
6674 * - call maintain_proxies() to enable/disable the listeners
6675 * - return the delay till next event in ms, -1 = wait indefinitely
6676 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6677 *
willy tarreau0f7af912005-12-17 12:21:26 +01006678 */
6679
willy tarreau1c2ad212005-12-18 01:11:29 +01006680int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006681 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006682 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006683 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006684
willy tarreaub952e1d2005-12-18 01:31:20 +01006685 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006686
willy tarreau1c2ad212005-12-18 01:11:29 +01006687 /* look for expired tasks and add them to the run queue.
6688 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006689 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6690 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006691 tnext = t->next;
6692 if (t->state & TASK_RUNNING)
6693 continue;
6694
willy tarreaub952e1d2005-12-18 01:31:20 +01006695 if (tv_iseternity(&t->expire))
6696 continue;
6697
willy tarreau1c2ad212005-12-18 01:11:29 +01006698 /* wakeup expired entries. It doesn't matter if they are
6699 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006700 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006701 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006702 task_wakeup(&rq, t);
6703 }
6704 else {
6705 /* first non-runnable task. Use its expiration date as an upper bound */
6706 int temp_time = tv_remain(&now, &t->expire);
6707 if (temp_time)
6708 next_time = temp_time;
6709 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006710 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006711 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006712
willy tarreau1c2ad212005-12-18 01:11:29 +01006713 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006714 * since we only use the run queue's head. Note that any task can be
6715 * woken up by any other task and it will be processed immediately
6716 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006717 */
willy tarreau7feab592006-04-22 15:13:16 +02006718 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006719 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006720
willy tarreau1c2ad212005-12-18 01:11:29 +01006721 task_sleep(&rq, t);
6722 temp_time = t->process(t);
6723 next_time = MINTIME(temp_time, next_time);
6724 }
6725
6726 /* maintain all proxies in a consistent state. This should quickly become a task */
6727 time2 = maintain_proxies();
6728 return MINTIME(time2, next_time);
6729}
6730
6731
6732#if defined(ENABLE_EPOLL)
6733
6734/*
6735 * Main epoll() loop.
6736 */
6737
6738/* does 3 actions :
6739 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6740 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6741 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6742 *
6743 * returns 0 if initialization failed, !0 otherwise.
6744 */
6745
6746int epoll_loop(int action) {
6747 int next_time;
6748 int status;
6749 int fd;
6750
6751 int fds, count;
6752 int pr, pw, sr, sw;
6753 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6754 struct epoll_event ev;
6755
6756 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006757 static struct epoll_event *epoll_events = NULL;
6758 static int epoll_fd;
6759
6760 if (action == POLL_LOOP_ACTION_INIT) {
6761 epoll_fd = epoll_create(global.maxsock + 1);
6762 if (epoll_fd < 0)
6763 return 0;
6764 else {
6765 epoll_events = (struct epoll_event*)
6766 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6767 PrevReadEvent = (fd_set *)
6768 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6769 PrevWriteEvent = (fd_set *)
6770 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006771 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006772 return 1;
6773 }
6774 else if (action == POLL_LOOP_ACTION_CLEAN) {
6775 if (PrevWriteEvent) free(PrevWriteEvent);
6776 if (PrevReadEvent) free(PrevReadEvent);
6777 if (epoll_events) free(epoll_events);
6778 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006779 epoll_fd = 0;
6780 return 1;
6781 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006782
willy tarreau1c2ad212005-12-18 01:11:29 +01006783 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006784
willy tarreau1c2ad212005-12-18 01:11:29 +01006785 tv_now(&now);
6786
6787 while (1) {
6788 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006789
6790 /* stop when there's no connection left and we don't allow them anymore */
6791 if (!actconn && listeners == 0)
6792 break;
6793
willy tarreau0f7af912005-12-17 12:21:26 +01006794#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006795 {
6796 int time2;
6797 time2 = stats();
6798 next_time = MINTIME(time2, next_time);
6799 }
willy tarreau0f7af912005-12-17 12:21:26 +01006800#endif
6801
willy tarreau1c2ad212005-12-18 01:11:29 +01006802 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6803
6804 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6805 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6806
6807 if ((ro^rn) | (wo^wn)) {
6808 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6809#define FDSETS_ARE_INT_ALIGNED
6810#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006811
willy tarreauad90a0c2005-12-18 01:09:15 +01006812#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6813#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006814 pr = (ro >> count) & 1;
6815 pw = (wo >> count) & 1;
6816 sr = (rn >> count) & 1;
6817 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006818#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006819 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6820 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6821 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6822 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006823#endif
6824#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006825 pr = FD_ISSET(fd, PrevReadEvent);
6826 pw = FD_ISSET(fd, PrevWriteEvent);
6827 sr = FD_ISSET(fd, StaticReadEvent);
6828 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006829#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006830 if (!((sr^pr) | (sw^pw)))
6831 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006832
willy tarreau1c2ad212005-12-18 01:11:29 +01006833 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6834 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006835
willy tarreaub952e1d2005-12-18 01:31:20 +01006836#ifdef EPOLL_CTL_MOD_WORKAROUND
6837 /* I encountered a rarely reproducible problem with
6838 * EPOLL_CTL_MOD where a modified FD (systematically
6839 * the one in epoll_events[0], fd#7) would sometimes
6840 * be set EPOLL_OUT while asked for a read ! This is
6841 * with the 2.4 epoll patch. The workaround is to
6842 * delete then recreate in case of modification.
6843 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6844 * nor RHEL kernels.
6845 */
6846
6847 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6848 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6849
6850 if ((sr | sw))
6851 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6852#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006853 if ((pr | pw)) {
6854 /* the file-descriptor already exists... */
6855 if ((sr | sw)) {
6856 /* ...and it will still exist */
6857 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6858 // perror("epoll_ctl(MOD)");
6859 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006860 }
6861 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006862 /* ...and it will be removed */
6863 if (fdtab[fd].state != FD_STCLOSE &&
6864 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6865 // perror("epoll_ctl(DEL)");
6866 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006867 }
6868 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006869 } else {
6870 /* the file-descriptor did not exist, let's add it */
6871 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6872 // perror("epoll_ctl(ADD)");
6873 // exit(1);
6874 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006875 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006876#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006877 }
6878 ((int*)PrevReadEvent)[fds] = rn;
6879 ((int*)PrevWriteEvent)[fds] = wn;
6880 }
6881 }
6882
6883 /* now let's wait for events */
6884 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6885 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006886
willy tarreau1c2ad212005-12-18 01:11:29 +01006887 for (count = 0; count < status; count++) {
6888 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006889
6890 if (FD_ISSET(fd, StaticReadEvent)) {
6891 if (fdtab[fd].state == FD_STCLOSE)
6892 continue;
6893 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6894 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006895 }
willy tarreau05be12b2006-03-19 19:35:00 +01006896
6897 if (FD_ISSET(fd, StaticWriteEvent)) {
6898 if (fdtab[fd].state == FD_STCLOSE)
6899 continue;
6900 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6901 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006902 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006903 }
6904 }
6905 return 1;
6906}
6907#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006908
willy tarreauad90a0c2005-12-18 01:09:15 +01006909
willy tarreau5cbea6f2005-12-17 12:48:26 +01006910
willy tarreau1c2ad212005-12-18 01:11:29 +01006911#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006912
willy tarreau1c2ad212005-12-18 01:11:29 +01006913/*
6914 * Main poll() loop.
6915 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006916
willy tarreau1c2ad212005-12-18 01:11:29 +01006917/* does 3 actions :
6918 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6919 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6920 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6921 *
6922 * returns 0 if initialization failed, !0 otherwise.
6923 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006924
willy tarreau1c2ad212005-12-18 01:11:29 +01006925int poll_loop(int action) {
6926 int next_time;
6927 int status;
6928 int fd, nbfd;
6929
6930 int fds, count;
6931 int sr, sw;
6932 unsigned rn, wn; /* read new, write new */
6933
6934 /* private data */
6935 static struct pollfd *poll_events = NULL;
6936
6937 if (action == POLL_LOOP_ACTION_INIT) {
6938 poll_events = (struct pollfd*)
6939 calloc(1, sizeof(struct pollfd) * global.maxsock);
6940 return 1;
6941 }
6942 else if (action == POLL_LOOP_ACTION_CLEAN) {
6943 if (poll_events)
6944 free(poll_events);
6945 return 1;
6946 }
6947
6948 /* OK, it's POLL_LOOP_ACTION_RUN */
6949
6950 tv_now(&now);
6951
6952 while (1) {
6953 next_time = process_runnable_tasks();
6954
6955 /* stop when there's no connection left and we don't allow them anymore */
6956 if (!actconn && listeners == 0)
6957 break;
6958
6959#if STATTIME > 0
6960 {
6961 int time2;
6962 time2 = stats();
6963 next_time = MINTIME(time2, next_time);
6964 }
6965#endif
6966
6967
6968 nbfd = 0;
6969 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6970
6971 rn = ((int*)StaticReadEvent)[fds];
6972 wn = ((int*)StaticWriteEvent)[fds];
6973
6974 if ((rn|wn)) {
6975 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6976#define FDSETS_ARE_INT_ALIGNED
6977#ifdef FDSETS_ARE_INT_ALIGNED
6978
6979#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6980#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6981 sr = (rn >> count) & 1;
6982 sw = (wn >> count) & 1;
6983#else
6984 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6985 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6986#endif
6987#else
6988 sr = FD_ISSET(fd, StaticReadEvent);
6989 sw = FD_ISSET(fd, StaticWriteEvent);
6990#endif
6991 if ((sr|sw)) {
6992 poll_events[nbfd].fd = fd;
6993 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6994 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006995 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006996 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006997 }
6998 }
6999
7000 /* now let's wait for events */
7001 status = poll(poll_events, nbfd, next_time);
7002 tv_now(&now);
7003
7004 for (count = 0; status > 0 && count < nbfd; count++) {
7005 fd = poll_events[count].fd;
7006
7007 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
7008 continue;
7009
7010 /* ok, we found one active fd */
7011 status--;
7012
willy tarreau05be12b2006-03-19 19:35:00 +01007013 if (FD_ISSET(fd, StaticReadEvent)) {
7014 if (fdtab[fd].state == FD_STCLOSE)
7015 continue;
7016 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
7017 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007018 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007019
willy tarreau05be12b2006-03-19 19:35:00 +01007020 if (FD_ISSET(fd, StaticWriteEvent)) {
7021 if (fdtab[fd].state == FD_STCLOSE)
7022 continue;
7023 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
7024 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01007025 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007026 }
7027 }
7028 return 1;
7029}
willy tarreauad90a0c2005-12-18 01:09:15 +01007030#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01007031
willy tarreauad90a0c2005-12-18 01:09:15 +01007032
willy tarreauad90a0c2005-12-18 01:09:15 +01007033
willy tarreau1c2ad212005-12-18 01:11:29 +01007034/*
7035 * Main select() loop.
7036 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007037
willy tarreau1c2ad212005-12-18 01:11:29 +01007038/* does 3 actions :
7039 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
7040 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
7041 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
7042 *
7043 * returns 0 if initialization failed, !0 otherwise.
7044 */
willy tarreauad90a0c2005-12-18 01:09:15 +01007045
willy tarreauad90a0c2005-12-18 01:09:15 +01007046
willy tarreau1c2ad212005-12-18 01:11:29 +01007047int select_loop(int action) {
7048 int next_time;
7049 int status;
7050 int fd,i;
7051 struct timeval delta;
7052 int readnotnull, writenotnull;
7053 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01007054
willy tarreau1c2ad212005-12-18 01:11:29 +01007055 if (action == POLL_LOOP_ACTION_INIT) {
7056 ReadEvent = (fd_set *)
7057 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7058 WriteEvent = (fd_set *)
7059 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
7060 return 1;
7061 }
7062 else if (action == POLL_LOOP_ACTION_CLEAN) {
7063 if (WriteEvent) free(WriteEvent);
7064 if (ReadEvent) free(ReadEvent);
7065 return 1;
7066 }
willy tarreauad90a0c2005-12-18 01:09:15 +01007067
willy tarreau1c2ad212005-12-18 01:11:29 +01007068 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01007069
willy tarreau1c2ad212005-12-18 01:11:29 +01007070 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01007071
willy tarreau1c2ad212005-12-18 01:11:29 +01007072 while (1) {
7073 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01007074
willy tarreau1c2ad212005-12-18 01:11:29 +01007075 /* stop when there's no connection left and we don't allow them anymore */
7076 if (!actconn && listeners == 0)
7077 break;
7078
7079#if STATTIME > 0
7080 {
7081 int time2;
7082 time2 = stats();
7083 next_time = MINTIME(time2, next_time);
7084 }
7085#endif
7086
willy tarreau1c2ad212005-12-18 01:11:29 +01007087 if (next_time > 0) { /* FIXME */
7088 /* Convert to timeval */
7089 /* to avoid eventual select loops due to timer precision */
7090 next_time += SCHEDULER_RESOLUTION;
7091 delta.tv_sec = next_time / 1000;
7092 delta.tv_usec = (next_time % 1000) * 1000;
7093 }
7094 else if (next_time == 0) { /* allow select to return immediately when needed */
7095 delta.tv_sec = delta.tv_usec = 0;
7096 }
7097
7098
7099 /* let's restore fdset state */
7100
7101 readnotnull = 0; writenotnull = 0;
7102 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
7103 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
7104 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
7105 }
7106
7107 // /* just a verification code, needs to be removed for performance */
7108 // for (i=0; i<maxfd; i++) {
7109 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
7110 // abort();
7111 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
7112 // abort();
7113 //
7114 // }
7115
7116 status = select(maxfd,
7117 readnotnull ? ReadEvent : NULL,
7118 writenotnull ? WriteEvent : NULL,
7119 NULL,
7120 (next_time >= 0) ? &delta : NULL);
7121
7122 /* this is an experiment on the separation of the select work */
7123 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7124 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
7125
7126 tv_now(&now);
7127
7128 if (status > 0) { /* must proceed with events */
7129
7130 int fds;
7131 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01007132
willy tarreau1c2ad212005-12-18 01:11:29 +01007133 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
7134 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
7135 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
7136
7137 /* if we specify read first, the accepts and zero reads will be
7138 * seen first. Moreover, system buffers will be flushed faster.
7139 */
willy tarreau05be12b2006-03-19 19:35:00 +01007140 if (FD_ISSET(fd, ReadEvent)) {
7141 if (fdtab[fd].state == FD_STCLOSE)
7142 continue;
7143 fdtab[fd].read(fd);
7144 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007145
willy tarreau05be12b2006-03-19 19:35:00 +01007146 if (FD_ISSET(fd, WriteEvent)) {
7147 if (fdtab[fd].state == FD_STCLOSE)
7148 continue;
7149 fdtab[fd].write(fd);
7150 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007151 }
7152 }
7153 else {
7154 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01007155 }
willy tarreau0f7af912005-12-17 12:21:26 +01007156 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007157 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01007158}
7159
7160
7161#if STATTIME > 0
7162/*
7163 * Display proxy statistics regularly. It is designed to be called from the
7164 * select_loop().
7165 */
7166int stats(void) {
7167 static int lines;
7168 static struct timeval nextevt;
7169 static struct timeval lastevt;
7170 static struct timeval starttime = {0,0};
7171 unsigned long totaltime, deltatime;
7172 int ret;
7173
willy tarreau750a4722005-12-17 13:21:24 +01007174 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01007175 deltatime = (tv_diff(&lastevt, &now)?:1);
7176 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01007177
willy tarreau9fe663a2005-12-17 13:02:59 +01007178 if (global.mode & MODE_STATS) {
7179 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007180 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007181 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
7182 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007183 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01007184 actconn, totalconn,
7185 stats_tsk_new, stats_tsk_good,
7186 stats_tsk_left, stats_tsk_right,
7187 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
7188 }
7189 }
7190
7191 tv_delayfrom(&nextevt, &now, STATTIME);
7192
7193 lastevt=now;
7194 }
7195 ret = tv_remain(&now, &nextevt);
7196 return ret;
7197}
7198#endif
7199
7200
7201/*
7202 * this function enables proxies when there are enough free sessions,
7203 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01007204 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01007205 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01007206 */
7207static int maintain_proxies(void) {
7208 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01007209 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007210 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01007211
7212 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01007213 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01007214
7215 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01007216 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01007217 while (p) {
7218 if (p->nbconn < p->maxconn) {
7219 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007220 for (l = p->listen; l != NULL; l = l->next) {
7221 FD_SET(l->fd, StaticReadEvent);
7222 }
willy tarreau0f7af912005-12-17 12:21:26 +01007223 p->state = PR_STRUN;
7224 }
7225 }
7226 else {
7227 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007228 for (l = p->listen; l != NULL; l = l->next) {
7229 FD_CLR(l->fd, StaticReadEvent);
7230 }
willy tarreau0f7af912005-12-17 12:21:26 +01007231 p->state = PR_STIDLE;
7232 }
7233 }
7234 p = p->next;
7235 }
7236 }
7237 else { /* block all proxies */
7238 while (p) {
7239 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007240 for (l = p->listen; l != NULL; l = l->next) {
7241 FD_CLR(l->fd, StaticReadEvent);
7242 }
willy tarreau0f7af912005-12-17 12:21:26 +01007243 p->state = PR_STIDLE;
7244 }
7245 p = p->next;
7246 }
7247 }
7248
willy tarreau5cbea6f2005-12-17 12:48:26 +01007249 if (stopping) {
7250 p = proxy;
7251 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007252 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007253 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01007254 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007255 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007256 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01007257 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01007258
willy tarreaua41a8b42005-12-17 14:02:24 +01007259 for (l = p->listen; l != NULL; l = l->next) {
7260 fd_delete(l->fd);
7261 listeners--;
7262 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007263 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007264 }
7265 else {
7266 tleft = MINTIME(t, tleft);
7267 }
7268 }
7269 p = p->next;
7270 }
7271 }
7272 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01007273}
7274
7275/*
7276 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01007277 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
7278 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01007279 */
7280static void soft_stop(void) {
7281 struct proxy *p;
7282
7283 stopping = 1;
7284 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007285 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01007286 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01007287 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01007288 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01007289 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01007290 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01007291 }
willy tarreau0f7af912005-12-17 12:21:26 +01007292 p = p->next;
7293 }
7294}
7295
willy tarreaudbd3bef2006-01-20 19:35:18 +01007296static void pause_proxy(struct proxy *p) {
7297 struct listener *l;
7298 for (l = p->listen; l != NULL; l = l->next) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007299 if (shutdown(l->fd, SHUT_RD) == 0) {
7300 FD_CLR(l->fd, StaticReadEvent);
7301 p->state = PR_STPAUSED;
7302 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007303 }
7304}
7305
7306/*
7307 * This function temporarily disables listening so that another new instance
7308 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01007309 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01007310 * the proxy, or a SIGTTIN can be sent to listen again.
7311 */
7312static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02007313 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007314 struct proxy *p;
7315
Willy TARREAU007aa462006-05-14 09:55:23 +02007316 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007317 p = proxy;
7318 tv_now(&now); /* else, the old time before select will be used */
7319 while (p) {
7320 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
7321 Warning("Pausing proxy %s.\n", p->id);
7322 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
7323 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02007324 if (p->state != PR_STPAUSED) {
7325 err |= 1;
7326 Warning("Proxy %s failed to enter pause mode.\n", p->id);
7327 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
7328 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007329 }
7330 p = p->next;
7331 }
Willy TARREAU007aa462006-05-14 09:55:23 +02007332 if (err) {
7333 Warning("Some proxies refused to pause, performing soft stop now.\n");
7334 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
7335 soft_stop();
7336 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01007337}
7338
7339
7340/*
7341 * This function reactivates listening. This can be used after a call to
7342 * sig_pause(), for example when a new instance has failed starting up.
7343 * It is designed to be called upon reception of a SIGTTIN.
7344 */
7345static void listen_proxies(void) {
7346 struct proxy *p;
7347 struct listener *l;
7348
7349 p = proxy;
7350 tv_now(&now); /* else, the old time before select will be used */
7351 while (p) {
7352 if (p->state == PR_STPAUSED) {
7353 Warning("Enabling proxy %s.\n", p->id);
7354 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
7355
7356 for (l = p->listen; l != NULL; l = l->next) {
7357 if (listen(l->fd, p->maxconn) == 0) {
7358 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
7359 FD_SET(l->fd, StaticReadEvent);
7360 p->state = PR_STRUN;
7361 }
7362 else
7363 p->state = PR_STIDLE;
7364 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01007365 int port;
7366
7367 if (l->addr.ss_family == AF_INET6)
7368 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
7369 else
7370 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
7371
willy tarreaudbd3bef2006-01-20 19:35:18 +01007372 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007373 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007374 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01007375 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01007376 /* Another port might have been enabled. Let's stop everything. */
7377 pause_proxy(p);
7378 break;
7379 }
7380 }
7381 }
7382 p = p->next;
7383 }
7384}
7385
7386
willy tarreau0f7af912005-12-17 12:21:26 +01007387/*
7388 * upon SIGUSR1, let's have a soft stop.
7389 */
7390void sig_soft_stop(int sig) {
7391 soft_stop();
7392 signal(sig, SIG_IGN);
7393}
7394
willy tarreaudbd3bef2006-01-20 19:35:18 +01007395/*
7396 * upon SIGTTOU, we pause everything
7397 */
7398void sig_pause(int sig) {
7399 pause_proxies();
7400 signal(sig, sig_pause);
7401}
willy tarreau0f7af912005-12-17 12:21:26 +01007402
willy tarreau8337c6b2005-12-17 13:41:01 +01007403/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01007404 * upon SIGTTIN, let's have a soft stop.
7405 */
7406void sig_listen(int sig) {
7407 listen_proxies();
7408 signal(sig, sig_listen);
7409}
7410
7411/*
willy tarreau8337c6b2005-12-17 13:41:01 +01007412 * this function dumps every server's state when the process receives SIGHUP.
7413 */
7414void sig_dump_state(int sig) {
7415 struct proxy *p = proxy;
7416
7417 Warning("SIGHUP received, dumping servers states.\n");
7418 while (p) {
7419 struct server *s = p->srv;
7420
willy tarreau4632c212006-05-02 23:32:51 +02007421 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01007422 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02007423 snprintf(trash, sizeof(trash),
7424 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
7425 p->id, s->id,
7426 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
7427 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02007428 Warning("%s\n", trash);
7429 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01007430 s = s->next;
7431 }
willy tarreaudd07e972005-12-18 00:48:48 +01007432
willy tarreau62084d42006-03-24 18:57:41 +01007433 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02007434 snprintf(trash, sizeof(trash),
7435 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
7436 p->id,
7437 (p->srv_bck) ? "is running on backup servers" : "has no server available",
7438 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007439 } else {
7440 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02007441 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
7442 " Conn: %d act, %d pend (%d unass), %d tot.",
7443 p->id, p->srv_act, p->srv_bck,
7444 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007445 }
7446 Warning("%s\n", trash);
7447 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01007448
willy tarreau8337c6b2005-12-17 13:41:01 +01007449 p = p->next;
7450 }
7451 signal(sig, sig_dump_state);
7452}
7453
willy tarreau0f7af912005-12-17 12:21:26 +01007454void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007455 struct task *t, *tnext;
7456 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01007457
willy tarreau5e698ef2006-05-02 14:51:00 +02007458 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
7459 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007460 tnext = t->next;
7461 s = t->context;
7462 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
7463 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
7464 "req=%d, rep=%d, clifd=%d\n",
7465 s, tv_remain(&now, &t->expire),
7466 s->cli_state,
7467 s->srv_state,
7468 FD_ISSET(s->cli_fd, StaticReadEvent),
7469 FD_ISSET(s->cli_fd, StaticWriteEvent),
7470 FD_ISSET(s->srv_fd, StaticReadEvent),
7471 FD_ISSET(s->srv_fd, StaticWriteEvent),
7472 s->req->l, s->rep?s->rep->l:0, s->cli_fd
7473 );
willy tarreau0f7af912005-12-17 12:21:26 +01007474 }
willy tarreau12350152005-12-18 01:03:27 +01007475}
7476
willy tarreau64a3cc32005-12-18 01:13:11 +01007477#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007478static void fast_stop(void)
7479{
7480 struct proxy *p;
7481 p = proxy;
7482 while (p) {
7483 p->grace = 0;
7484 p = p->next;
7485 }
7486 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01007487}
7488
willy tarreau12350152005-12-18 01:03:27 +01007489void sig_int(int sig) {
7490 /* This would normally be a hard stop,
7491 but we want to be sure about deallocation,
7492 and so on, so we do a soft stop with
7493 0 GRACE time
7494 */
7495 fast_stop();
7496 /* If we are killed twice, we decide to die*/
7497 signal(sig, SIG_DFL);
7498}
7499
7500void sig_term(int sig) {
7501 /* This would normally be a hard stop,
7502 but we want to be sure about deallocation,
7503 and so on, so we do a soft stop with
7504 0 GRACE time
7505 */
7506 fast_stop();
7507 /* If we are killed twice, we decide to die*/
7508 signal(sig, SIG_DFL);
7509}
willy tarreau64a3cc32005-12-18 01:13:11 +01007510#endif
willy tarreau12350152005-12-18 01:03:27 +01007511
willy tarreauc1f47532005-12-18 01:08:26 +01007512/* returns the pointer to an error in the replacement string, or NULL if OK */
7513char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01007514 struct hdr_exp *exp;
7515
willy tarreauc1f47532005-12-18 01:08:26 +01007516 if (replace != NULL) {
7517 char *err;
7518 err = check_replace_string(replace);
7519 if (err)
7520 return err;
7521 }
7522
willy tarreaue39cd132005-12-17 13:00:18 +01007523 while (*head != NULL)
7524 head = &(*head)->next;
7525
7526 exp = calloc(1, sizeof(struct hdr_exp));
7527
7528 exp->preg = preg;
7529 exp->replace = replace;
7530 exp->action = action;
7531 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01007532
7533 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007534}
7535
willy tarreau9fe663a2005-12-17 13:02:59 +01007536
willy tarreau0f7af912005-12-17 12:21:26 +01007537/*
willy tarreau9fe663a2005-12-17 13:02:59 +01007538 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01007539 */
willy tarreau9fe663a2005-12-17 13:02:59 +01007540int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01007541
willy tarreau9fe663a2005-12-17 13:02:59 +01007542 if (!strcmp(args[0], "global")) { /* new section */
7543 /* no option, nothing special to do */
7544 return 0;
7545 }
7546 else if (!strcmp(args[0], "daemon")) {
7547 global.mode |= MODE_DAEMON;
7548 }
7549 else if (!strcmp(args[0], "debug")) {
7550 global.mode |= MODE_DEBUG;
7551 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007552 else if (!strcmp(args[0], "noepoll")) {
7553 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7554 }
7555 else if (!strcmp(args[0], "nopoll")) {
7556 cfg_polling_mechanism &= ~POLL_USE_POLL;
7557 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007558 else if (!strcmp(args[0], "quiet")) {
7559 global.mode |= MODE_QUIET;
7560 }
7561 else if (!strcmp(args[0], "stats")) {
7562 global.mode |= MODE_STATS;
7563 }
7564 else if (!strcmp(args[0], "uid")) {
7565 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007566 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007567 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007568 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007569 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007570 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007571 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007572 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007573 global.uid = atol(args[1]);
7574 }
7575 else if (!strcmp(args[0], "gid")) {
7576 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007577 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007578 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007579 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007580 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007581 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007582 return -1;
7583 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007584 global.gid = atol(args[1]);
7585 }
7586 else if (!strcmp(args[0], "nbproc")) {
7587 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007588 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007589 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007590 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007591 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007592 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007593 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007594 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007595 global.nbproc = atol(args[1]);
7596 }
7597 else if (!strcmp(args[0], "maxconn")) {
7598 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007599 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007600 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007601 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007602 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007603 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007604 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007605 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007606 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007607#ifdef SYSTEM_MAXCONN
7608 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7609 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);
7610 global.maxconn = DEFAULT_MAXCONN;
7611 }
7612#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007613 }
willy tarreaub1285d52005-12-18 01:20:14 +01007614 else if (!strcmp(args[0], "ulimit-n")) {
7615 if (global.rlimit_nofile != 0) {
7616 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7617 return 0;
7618 }
7619 if (*(args[1]) == 0) {
7620 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7621 return -1;
7622 }
7623 global.rlimit_nofile = atol(args[1]);
7624 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007625 else if (!strcmp(args[0], "chroot")) {
7626 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007627 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007628 return 0;
7629 }
7630 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007631 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007632 return -1;
7633 }
7634 global.chroot = strdup(args[1]);
7635 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007636 else if (!strcmp(args[0], "pidfile")) {
7637 if (global.pidfile != NULL) {
7638 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7639 return 0;
7640 }
7641 if (*(args[1]) == 0) {
7642 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7643 return -1;
7644 }
7645 global.pidfile = strdup(args[1]);
7646 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007647 else if (!strcmp(args[0], "log")) { /* syslog server address */
7648 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007649 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007650
7651 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007652 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007653 return -1;
7654 }
7655
7656 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7657 if (!strcmp(log_facilities[facility], args[2]))
7658 break;
7659
7660 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007661 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007662 exit(1);
7663 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007664
7665 level = 7; /* max syslog level = debug */
7666 if (*(args[3])) {
7667 while (level >= 0 && strcmp(log_levels[level], args[3]))
7668 level--;
7669 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007670 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007671 exit(1);
7672 }
7673 }
7674
willy tarreau9fe663a2005-12-17 13:02:59 +01007675 sa = str2sa(args[1]);
7676 if (!sa->sin_port)
7677 sa->sin_port = htons(SYSLOG_PORT);
7678
7679 if (global.logfac1 == -1) {
7680 global.logsrv1 = *sa;
7681 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007682 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007683 }
7684 else if (global.logfac2 == -1) {
7685 global.logsrv2 = *sa;
7686 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007687 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007688 }
7689 else {
7690 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7691 return -1;
7692 }
7693
7694 }
7695 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007696 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007697 return -1;
7698 }
7699 return 0;
7700}
7701
7702
willy tarreaua41a8b42005-12-17 14:02:24 +01007703void init_default_instance() {
7704 memset(&defproxy, 0, sizeof(defproxy));
7705 defproxy.mode = PR_MODE_TCP;
7706 defproxy.state = PR_STNEW;
7707 defproxy.maxconn = cfg_maxpconn;
7708 defproxy.conn_retries = CONN_RETRIES;
7709 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7710}
7711
willy tarreau9fe663a2005-12-17 13:02:59 +01007712/*
7713 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7714 */
7715int cfg_parse_listen(char *file, int linenum, char **args) {
7716 static struct proxy *curproxy = NULL;
7717 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007718 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007719 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007720
7721 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007722 if (!*args[1]) {
7723 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7724 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007725 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007726 return -1;
7727 }
7728
7729 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007730 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007731 return -1;
7732 }
willy tarreaudfece232006-05-02 00:19:57 +02007733
willy tarreau9fe663a2005-12-17 13:02:59 +01007734 curproxy->next = proxy;
7735 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007736 LIST_INIT(&curproxy->pendconns);
7737
willy tarreau9fe663a2005-12-17 13:02:59 +01007738 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007739
7740 /* parse the listener address if any */
7741 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007742 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007743 if (!curproxy->listen)
7744 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007745 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007746 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007747
willy tarreau9fe663a2005-12-17 13:02:59 +01007748 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007749 curproxy->state = defproxy.state;
7750 curproxy->maxconn = defproxy.maxconn;
7751 curproxy->conn_retries = defproxy.conn_retries;
7752 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007753
7754 if (defproxy.check_req)
7755 curproxy->check_req = strdup(defproxy.check_req);
7756 curproxy->check_len = defproxy.check_len;
7757
7758 if (defproxy.cookie_name)
7759 curproxy->cookie_name = strdup(defproxy.cookie_name);
7760 curproxy->cookie_len = defproxy.cookie_len;
7761
7762 if (defproxy.capture_name)
7763 curproxy->capture_name = strdup(defproxy.capture_name);
7764 curproxy->capture_namelen = defproxy.capture_namelen;
7765 curproxy->capture_len = defproxy.capture_len;
7766
7767 if (defproxy.errmsg.msg400)
7768 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7769 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7770
7771 if (defproxy.errmsg.msg403)
7772 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7773 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7774
7775 if (defproxy.errmsg.msg408)
7776 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7777 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7778
7779 if (defproxy.errmsg.msg500)
7780 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7781 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7782
7783 if (defproxy.errmsg.msg502)
7784 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7785 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7786
7787 if (defproxy.errmsg.msg503)
7788 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7789 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7790
7791 if (defproxy.errmsg.msg504)
7792 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7793 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7794
willy tarreaua41a8b42005-12-17 14:02:24 +01007795 curproxy->clitimeout = defproxy.clitimeout;
7796 curproxy->contimeout = defproxy.contimeout;
7797 curproxy->srvtimeout = defproxy.srvtimeout;
7798 curproxy->mode = defproxy.mode;
7799 curproxy->logfac1 = defproxy.logfac1;
7800 curproxy->logsrv1 = defproxy.logsrv1;
7801 curproxy->loglev1 = defproxy.loglev1;
7802 curproxy->logfac2 = defproxy.logfac2;
7803 curproxy->logsrv2 = defproxy.logsrv2;
7804 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007805 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007806 curproxy->grace = defproxy.grace;
7807 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007808 curproxy->mon_net = defproxy.mon_net;
7809 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007810 return 0;
7811 }
7812 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007813 /* some variables may have already been initialized earlier */
7814 if (defproxy.check_req) free(defproxy.check_req);
7815 if (defproxy.cookie_name) free(defproxy.cookie_name);
7816 if (defproxy.capture_name) free(defproxy.capture_name);
7817 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7818 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7819 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7820 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7821 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7822 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7823 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7824
7825 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007826 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007827 return 0;
7828 }
7829 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007830 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007831 return -1;
7832 }
7833
willy tarreaua41a8b42005-12-17 14:02:24 +01007834 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7835 if (curproxy == &defproxy) {
7836 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7837 return -1;
7838 }
7839
7840 if (strchr(args[1], ':') == NULL) {
7841 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7842 file, linenum, args[0]);
7843 return -1;
7844 }
7845 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007846 if (!curproxy->listen)
7847 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007848 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007849 return 0;
7850 }
willy tarreaub1285d52005-12-18 01:20:14 +01007851 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7852 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7853 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7854 file, linenum, args[0]);
7855 return -1;
7856 }
7857 /* flush useless bits */
7858 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7859 return 0;
7860 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007861 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007862 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7863 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7864 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7865 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007866 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007867 return -1;
7868 }
7869 }
7870 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007871 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007872 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007873 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7874 curproxy->state = PR_STNEW;
7875 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007876 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7877 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007878// if (curproxy == &defproxy) {
7879// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7880// return -1;
7881// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007882
willy tarreau9fe663a2005-12-17 13:02:59 +01007883 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007884// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7885// file, linenum);
7886// return 0;
7887 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007888 }
7889
7890 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007891 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7892 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007893 return -1;
7894 }
7895 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007896 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007897
7898 cur_arg = 2;
7899 while (*(args[cur_arg])) {
7900 if (!strcmp(args[cur_arg], "rewrite")) {
7901 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007902 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007903 else if (!strcmp(args[cur_arg], "indirect")) {
7904 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007905 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007906 else if (!strcmp(args[cur_arg], "insert")) {
7907 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007908 }
willy tarreau240afa62005-12-17 13:14:35 +01007909 else if (!strcmp(args[cur_arg], "nocache")) {
7910 curproxy->options |= PR_O_COOK_NOC;
7911 }
willy tarreaucd878942005-12-17 13:27:43 +01007912 else if (!strcmp(args[cur_arg], "postonly")) {
7913 curproxy->options |= PR_O_COOK_POST;
7914 }
willy tarreau0174f312005-12-18 01:02:42 +01007915 else if (!strcmp(args[cur_arg], "prefix")) {
7916 curproxy->options |= PR_O_COOK_PFX;
7917 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007918 else {
willy tarreau0174f312005-12-18 01:02:42 +01007919 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007920 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007921 return -1;
7922 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007923 cur_arg++;
7924 }
willy tarreau0174f312005-12-18 01:02:42 +01007925 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7926 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7927 file, linenum);
7928 return -1;
7929 }
7930
7931 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7932 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007933 file, linenum);
7934 return -1;
7935 }
willy tarreau12350152005-12-18 01:03:27 +01007936 }/* end else if (!strcmp(args[0], "cookie")) */
7937 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7938// if (curproxy == &defproxy) {
7939// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7940// return -1;
7941// }
7942
7943 if (curproxy->appsession_name != NULL) {
7944// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7945// file, linenum);
7946// return 0;
7947 free(curproxy->appsession_name);
7948 }
7949
7950 if (*(args[5]) == 0) {
7951 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7952 file, linenum, args[0]);
7953 return -1;
7954 }
7955 have_appsession = 1;
7956 curproxy->appsession_name = strdup(args[1]);
7957 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7958 curproxy->appsession_len = atoi(args[3]);
7959 curproxy->appsession_timeout = atoi(args[5]);
7960 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7961 if (rc) {
7962 Alert("Error Init Appsession Hashtable.\n");
7963 return -1;
7964 }
7965 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007966 else if (!strcmp(args[0], "capture")) {
7967 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7968 // if (curproxy == &defproxy) {
7969 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7970 // return -1;
7971 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007972
willy tarreau4302f492005-12-18 01:00:37 +01007973 if (curproxy->capture_name != NULL) {
7974 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7975 // file, linenum, args[0]);
7976 // return 0;
7977 free(curproxy->capture_name);
7978 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007979
willy tarreau4302f492005-12-18 01:00:37 +01007980 if (*(args[4]) == 0) {
7981 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7982 file, linenum, args[0]);
7983 return -1;
7984 }
7985 curproxy->capture_name = strdup(args[2]);
7986 curproxy->capture_namelen = strlen(curproxy->capture_name);
7987 curproxy->capture_len = atol(args[4]);
7988 if (curproxy->capture_len >= CAPTURE_LEN) {
7989 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7990 file, linenum, CAPTURE_LEN - 1);
7991 curproxy->capture_len = CAPTURE_LEN - 1;
7992 }
7993 curproxy->to_log |= LW_COOKIE;
7994 }
7995 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7996 struct cap_hdr *hdr;
7997
7998 if (curproxy == &defproxy) {
7999 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8000 return -1;
8001 }
8002
8003 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8004 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8005 file, linenum, args[0], args[1]);
8006 return -1;
8007 }
8008
8009 hdr = calloc(sizeof(struct cap_hdr), 1);
8010 hdr->next = curproxy->req_cap;
8011 hdr->name = strdup(args[3]);
8012 hdr->namelen = strlen(args[3]);
8013 hdr->len = atol(args[5]);
8014 hdr->index = curproxy->nb_req_cap++;
8015 curproxy->req_cap = hdr;
8016 curproxy->to_log |= LW_REQHDR;
8017 }
8018 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
8019 struct cap_hdr *hdr;
8020
8021 if (curproxy == &defproxy) {
8022 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
8023 return -1;
8024 }
8025
8026 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
8027 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
8028 file, linenum, args[0], args[1]);
8029 return -1;
8030 }
8031 hdr = calloc(sizeof(struct cap_hdr), 1);
8032 hdr->next = curproxy->rsp_cap;
8033 hdr->name = strdup(args[3]);
8034 hdr->namelen = strlen(args[3]);
8035 hdr->len = atol(args[5]);
8036 hdr->index = curproxy->nb_rsp_cap++;
8037 curproxy->rsp_cap = hdr;
8038 curproxy->to_log |= LW_RSPHDR;
8039 }
8040 else {
8041 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008042 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008043 return -1;
8044 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008045 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008046 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008047 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008048 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008049 return 0;
8050 }
8051 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008052 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8053 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008054 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008055 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008056 curproxy->contimeout = atol(args[1]);
8057 }
8058 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008059 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008060 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
8061 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008062 return 0;
8063 }
8064 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008065 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8066 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008067 return -1;
8068 }
8069 curproxy->clitimeout = atol(args[1]);
8070 }
8071 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01008072 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008073 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008074 return 0;
8075 }
8076 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008077 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
8078 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01008079 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008080 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008081 curproxy->srvtimeout = atol(args[1]);
8082 }
8083 else if (!strcmp(args[0], "retries")) { /* connection retries */
8084 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008085 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
8086 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008087 return -1;
8088 }
8089 curproxy->conn_retries = atol(args[1]);
8090 }
willy tarreau9e138862006-05-14 23:06:28 +02008091 else if (!strcmp(args[0], "stats")) {
8092 if (*(args[1]) == 0) {
8093 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth' or 'enable'.\n", file, linenum, args[0]);
8094 return -1;
8095 } else if (!strcmp(args[1], "uri")) {
8096 if (*(args[2]) == 0) {
8097 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
8098 return -1;
8099 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
8100 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8101 return -1;
8102 }
8103 } else if (!strcmp(args[1], "realm")) {
8104 if (*(args[2]) == 0) {
8105 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
8106 return -1;
8107 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
8108 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8109 return -1;
8110 }
8111 } else if (!strcmp(args[1], "auth")) {
8112 if (*(args[2]) == 0) {
8113 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
8114 return -1;
8115 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
8116 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8117 return -1;
8118 }
8119 } else if (!strcmp(args[1], "enable")) {
8120 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
8121 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8122 return -1;
8123 }
8124 } else {
8125 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
8126 file, linenum, args[0]);
8127 return -1;
8128 }
8129 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008130 else if (!strcmp(args[0], "option")) {
8131 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008132 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008133 return -1;
8134 }
8135 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008136 /* enable reconnections to dispatch */
8137 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01008138#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008139 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01008140 /* enable transparent proxy connections */
8141 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01008142#endif
8143 else if (!strcmp(args[1], "keepalive"))
8144 /* enable keep-alive */
8145 curproxy->options |= PR_O_KEEPALIVE;
8146 else if (!strcmp(args[1], "forwardfor"))
8147 /* insert x-forwarded-for field */
8148 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01008149 else if (!strcmp(args[1], "logasap"))
8150 /* log as soon as possible, without waiting for the session to complete */
8151 curproxy->options |= PR_O_LOGASAP;
8152 else if (!strcmp(args[1], "httpclose"))
8153 /* force connection: close in both directions in HTTP mode */
8154 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01008155 else if (!strcmp(args[1], "forceclose"))
8156 /* force connection: close in both directions in HTTP mode and enforce end of session */
8157 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01008158 else if (!strcmp(args[1], "checkcache"))
8159 /* require examination of cacheability of the 'set-cookie' field */
8160 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01008161 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01008162 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008163 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01008164 else if (!strcmp(args[1], "tcplog"))
8165 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01008166 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01008167 else if (!strcmp(args[1], "dontlognull")) {
8168 /* don't log empty requests */
8169 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008170 }
willy tarreaub952e1d2005-12-18 01:31:20 +01008171 else if (!strcmp(args[1], "tcpka")) {
8172 /* enable TCP keep-alives on client and server sessions */
8173 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
8174 }
8175 else if (!strcmp(args[1], "clitcpka")) {
8176 /* enable TCP keep-alives on client sessions */
8177 curproxy->options |= PR_O_TCP_CLI_KA;
8178 }
8179 else if (!strcmp(args[1], "srvtcpka")) {
8180 /* enable TCP keep-alives on server sessions */
8181 curproxy->options |= PR_O_TCP_SRV_KA;
8182 }
Willy TARREAU3481c462006-03-01 22:37:57 +01008183 else if (!strcmp(args[1], "allbackups")) {
8184 /* Use all backup servers simultaneously */
8185 curproxy->options |= PR_O_USE_ALL_BK;
8186 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008187 else if (!strcmp(args[1], "httpchk")) {
8188 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008189 if (curproxy->check_req != NULL) {
8190 free(curproxy->check_req);
8191 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008192 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01008193 if (!*args[2]) { /* no argument */
8194 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
8195 curproxy->check_len = strlen(DEF_CHECK_REQ);
8196 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01008197 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
8198 curproxy->check_req = (char *)malloc(reqlen);
8199 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8200 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01008201 } else { /* more arguments : METHOD URI [HTTP_VER] */
8202 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
8203 if (*args[4])
8204 reqlen += strlen(args[4]);
8205 else
8206 reqlen += strlen("HTTP/1.0");
8207
8208 curproxy->check_req = (char *)malloc(reqlen);
8209 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
8210 "%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 +01008211 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01008212 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008213 else if (!strcmp(args[1], "persist")) {
8214 /* persist on using the server specified by the cookie, even when it's down */
8215 curproxy->options |= PR_O_PERSIST;
8216 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008217 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008218 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008219 return -1;
8220 }
8221 return 0;
8222 }
8223 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
8224 /* enable reconnections to dispatch */
8225 curproxy->options |= PR_O_REDISP;
8226 }
willy tarreaua1598082005-12-17 13:08:06 +01008227#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01008228 else if (!strcmp(args[0], "transparent")) {
8229 /* enable transparent proxy connections */
8230 curproxy->options |= PR_O_TRANSP;
8231 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008232#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01008233 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
8234 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008235 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008236 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008237 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008238 curproxy->maxconn = atol(args[1]);
8239 }
8240 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
8241 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008242 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008243 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008244 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008245 curproxy->grace = atol(args[1]);
8246 }
8247 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01008248 if (curproxy == &defproxy) {
8249 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8250 return -1;
8251 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008252 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008253 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008254 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008255 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008256 curproxy->dispatch_addr = *str2sa(args[1]);
8257 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008258 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01008259 if (*(args[1])) {
8260 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008261 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01008262 }
willy tarreau1a3442d2006-03-24 21:03:20 +01008263 else if (!strcmp(args[1], "source")) {
8264 curproxy->options |= PR_O_BALANCE_SH;
8265 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008266 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01008267 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008268 return -1;
8269 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008270 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008271 else /* if no option is set, use round-robin by default */
8272 curproxy->options |= PR_O_BALANCE_RR;
8273 }
8274 else if (!strcmp(args[0], "server")) { /* server address */
8275 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008276 char *rport;
8277 char *raddr;
8278 short realport;
8279 int do_check;
8280
8281 if (curproxy == &defproxy) {
8282 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8283 return -1;
8284 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008285
willy tarreaua41a8b42005-12-17 14:02:24 +01008286 if (!*args[2]) {
8287 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008288 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008289 return -1;
8290 }
8291 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
8292 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8293 return -1;
8294 }
willy tarreau0174f312005-12-18 01:02:42 +01008295
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008296 /* the servers are linked backwards first */
8297 newsrv->next = curproxy->srv;
8298 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01008299 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008300
willy tarreau18a957c2006-04-12 19:26:23 +02008301 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01008302 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01008303 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01008304 newsrv->id = strdup(args[1]);
8305
8306 /* several ways to check the port component :
8307 * - IP => port=+0, relative
8308 * - IP: => port=+0, relative
8309 * - IP:N => port=N, absolute
8310 * - IP:+N => port=+N, relative
8311 * - IP:-N => port=-N, relative
8312 */
8313 raddr = strdup(args[2]);
8314 rport = strchr(raddr, ':');
8315 if (rport) {
8316 *rport++ = 0;
8317 realport = atol(rport);
8318 if (!isdigit((int)*rport))
8319 newsrv->state |= SRV_MAPPORTS;
8320 } else {
8321 realport = 0;
8322 newsrv->state |= SRV_MAPPORTS;
8323 }
8324
8325 newsrv->addr = *str2sa(raddr);
8326 newsrv->addr.sin_port = htons(realport);
8327 free(raddr);
8328
willy tarreau9fe663a2005-12-17 13:02:59 +01008329 newsrv->curfd = -1; /* no health-check in progress */
8330 newsrv->inter = DEF_CHKINTR;
8331 newsrv->rise = DEF_RISETIME;
8332 newsrv->fall = DEF_FALLTIME;
8333 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
8334 cur_arg = 3;
8335 while (*args[cur_arg]) {
8336 if (!strcmp(args[cur_arg], "cookie")) {
8337 newsrv->cookie = strdup(args[cur_arg + 1]);
8338 newsrv->cklen = strlen(args[cur_arg + 1]);
8339 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008340 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008341 else if (!strcmp(args[cur_arg], "rise")) {
8342 newsrv->rise = atol(args[cur_arg + 1]);
8343 newsrv->health = newsrv->rise;
8344 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01008345 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008346 else if (!strcmp(args[cur_arg], "fall")) {
8347 newsrv->fall = atol(args[cur_arg + 1]);
8348 cur_arg += 2;
8349 }
8350 else if (!strcmp(args[cur_arg], "inter")) {
8351 newsrv->inter = atol(args[cur_arg + 1]);
8352 cur_arg += 2;
8353 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008354 else if (!strcmp(args[cur_arg], "port")) {
8355 newsrv->check_port = atol(args[cur_arg + 1]);
8356 cur_arg += 2;
8357 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008358 else if (!strcmp(args[cur_arg], "backup")) {
8359 newsrv->state |= SRV_BACKUP;
8360 cur_arg ++;
8361 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008362 else if (!strcmp(args[cur_arg], "weight")) {
8363 int w;
8364 w = atol(args[cur_arg + 1]);
8365 if (w < 1 || w > 256) {
8366 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
8367 file, linenum, newsrv->id, w);
8368 return -1;
8369 }
8370 newsrv->uweight = w - 1;
8371 cur_arg += 2;
8372 }
willy tarreau18a957c2006-04-12 19:26:23 +02008373 else if (!strcmp(args[cur_arg], "maxconn")) {
8374 newsrv->maxconn = atol(args[cur_arg + 1]);
8375 cur_arg += 2;
8376 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008377 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01008378 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01008379 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008380 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008381 }
willy tarreau0174f312005-12-18 01:02:42 +01008382 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
8383 if (!*args[cur_arg + 1]) {
8384 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
8385 file, linenum, "source");
8386 return -1;
8387 }
8388 newsrv->state |= SRV_BIND_SRC;
8389 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
8390 cur_arg += 2;
8391 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008392 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02008393 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01008394 file, linenum, newsrv->id);
8395 return -1;
8396 }
8397 }
8398
8399 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008400 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
8401 newsrv->check_port = realport; /* by default */
8402 if (!newsrv->check_port) {
8403 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 +01008404 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008405 return -1;
8406 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008407 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01008408 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008409
willy tarreau62084d42006-03-24 18:57:41 +01008410 if (newsrv->state & SRV_BACKUP)
8411 curproxy->srv_bck++;
8412 else
8413 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01008414 }
8415 else if (!strcmp(args[0], "log")) { /* syslog server address */
8416 struct sockaddr_in *sa;
8417 int facility;
8418
8419 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
8420 curproxy->logfac1 = global.logfac1;
8421 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01008422 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008423 curproxy->logfac2 = global.logfac2;
8424 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01008425 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01008426 }
8427 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01008428 int level;
8429
willy tarreau0f7af912005-12-17 12:21:26 +01008430 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
8431 if (!strcmp(log_facilities[facility], args[2]))
8432 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01008433
willy tarreau0f7af912005-12-17 12:21:26 +01008434 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008435 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01008436 exit(1);
8437 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008438
willy tarreau8337c6b2005-12-17 13:41:01 +01008439 level = 7; /* max syslog level = debug */
8440 if (*(args[3])) {
8441 while (level >= 0 && strcmp(log_levels[level], args[3]))
8442 level--;
8443 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008444 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008445 exit(1);
8446 }
8447 }
8448
willy tarreau0f7af912005-12-17 12:21:26 +01008449 sa = str2sa(args[1]);
8450 if (!sa->sin_port)
8451 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01008452
willy tarreau0f7af912005-12-17 12:21:26 +01008453 if (curproxy->logfac1 == -1) {
8454 curproxy->logsrv1 = *sa;
8455 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008456 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008457 }
8458 else if (curproxy->logfac2 == -1) {
8459 curproxy->logsrv2 = *sa;
8460 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008461 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008462 }
8463 else {
8464 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008465 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008466 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008467 }
8468 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008469 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008470 file, linenum);
8471 return -1;
8472 }
8473 }
willy tarreaua1598082005-12-17 13:08:06 +01008474 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01008475 if (!*args[1]) {
8476 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008477 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01008478 return -1;
8479 }
8480
8481 curproxy->source_addr = *str2sa(args[1]);
8482 curproxy->options |= PR_O_BIND_SRC;
8483 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008484 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
8485 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008486 if (curproxy == &defproxy) {
8487 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8488 return -1;
8489 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008490
8491 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008492 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8493 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008494 return -1;
8495 }
8496
8497 preg = calloc(1, sizeof(regex_t));
8498 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008499 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008500 return -1;
8501 }
8502
willy tarreauc1f47532005-12-18 01:08:26 +01008503 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8504 if (err) {
8505 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8506 file, linenum, *err);
8507 return -1;
8508 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008509 }
8510 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
8511 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008512 if (curproxy == &defproxy) {
8513 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8514 return -1;
8515 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008516
8517 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008518 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008519 return -1;
8520 }
8521
8522 preg = calloc(1, sizeof(regex_t));
8523 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008524 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008525 return -1;
8526 }
8527
8528 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8529 }
8530 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
8531 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008532 if (curproxy == &defproxy) {
8533 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8534 return -1;
8535 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008536
8537 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008538 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008539 return -1;
8540 }
8541
8542 preg = calloc(1, sizeof(regex_t));
8543 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008544 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008545 return -1;
8546 }
8547
8548 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8549 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008550 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
8551 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008552 if (curproxy == &defproxy) {
8553 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8554 return -1;
8555 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008556
8557 if (*(args[1]) == 0) {
8558 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8559 return -1;
8560 }
8561
8562 preg = calloc(1, sizeof(regex_t));
8563 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8564 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8565 return -1;
8566 }
8567
8568 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8569 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008570 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
8571 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008572 if (curproxy == &defproxy) {
8573 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8574 return -1;
8575 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008576
8577 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008578 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008579 return -1;
8580 }
8581
8582 preg = calloc(1, sizeof(regex_t));
8583 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008584 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008585 return -1;
8586 }
8587
8588 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8589 }
8590 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8591 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008592 if (curproxy == &defproxy) {
8593 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8594 return -1;
8595 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008596
8597 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008598 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8599 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008600 return -1;
8601 }
8602
8603 preg = calloc(1, sizeof(regex_t));
8604 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008605 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008606 return -1;
8607 }
8608
willy tarreauc1f47532005-12-18 01:08:26 +01008609 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8610 if (err) {
8611 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8612 file, linenum, *err);
8613 return -1;
8614 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008615 }
8616 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8617 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008618 if (curproxy == &defproxy) {
8619 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8620 return -1;
8621 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008622
8623 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008624 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008625 return -1;
8626 }
8627
8628 preg = calloc(1, sizeof(regex_t));
8629 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008630 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008631 return -1;
8632 }
8633
8634 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8635 }
8636 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8637 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008638 if (curproxy == &defproxy) {
8639 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8640 return -1;
8641 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008642
8643 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008644 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008645 return -1;
8646 }
8647
8648 preg = calloc(1, sizeof(regex_t));
8649 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008650 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008651 return -1;
8652 }
8653
8654 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8655 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008656 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8657 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008658 if (curproxy == &defproxy) {
8659 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8660 return -1;
8661 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008662
8663 if (*(args[1]) == 0) {
8664 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8665 return -1;
8666 }
8667
8668 preg = calloc(1, sizeof(regex_t));
8669 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8670 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8671 return -1;
8672 }
8673
8674 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8675 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008676 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8677 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008678 if (curproxy == &defproxy) {
8679 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8680 return -1;
8681 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008682
8683 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008684 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008685 return -1;
8686 }
8687
8688 preg = calloc(1, sizeof(regex_t));
8689 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008690 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008691 return -1;
8692 }
8693
8694 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8695 }
8696 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008697 if (curproxy == &defproxy) {
8698 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8699 return -1;
8700 }
8701
willy tarreau9fe663a2005-12-17 13:02:59 +01008702 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008703 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008704 return 0;
8705 }
8706
8707 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008708 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008709 return -1;
8710 }
8711
willy tarreau4302f492005-12-18 01:00:37 +01008712 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8713 }
8714 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8715 regex_t *preg;
8716
8717 if (*(args[1]) == 0 || *(args[2]) == 0) {
8718 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8719 file, linenum, args[0]);
8720 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008721 }
willy tarreau4302f492005-12-18 01:00:37 +01008722
8723 preg = calloc(1, sizeof(regex_t));
8724 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8725 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8726 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008727 }
willy tarreau4302f492005-12-18 01:00:37 +01008728
willy tarreauc1f47532005-12-18 01:08:26 +01008729 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8730 if (err) {
8731 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8732 file, linenum, *err);
8733 return -1;
8734 }
willy tarreau4302f492005-12-18 01:00:37 +01008735 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008736 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8737 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008738 if (curproxy == &defproxy) {
8739 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8740 return -1;
8741 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008742
8743 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008744 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008745 return -1;
8746 }
willy tarreaue39cd132005-12-17 13:00:18 +01008747
willy tarreau9fe663a2005-12-17 13:02:59 +01008748 preg = calloc(1, sizeof(regex_t));
8749 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008750 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008751 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008752 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008753
willy tarreauc1f47532005-12-18 01:08:26 +01008754 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8755 if (err) {
8756 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8757 file, linenum, *err);
8758 return -1;
8759 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008760 }
willy tarreau982249e2005-12-18 00:57:06 +01008761 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8762 regex_t *preg;
8763 if (curproxy == &defproxy) {
8764 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8765 return -1;
8766 }
8767
8768 if (*(args[1]) == 0) {
8769 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8770 return -1;
8771 }
8772
8773 preg = calloc(1, sizeof(regex_t));
8774 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8775 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8776 return -1;
8777 }
8778
willy tarreauc1f47532005-12-18 01:08:26 +01008779 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8780 if (err) {
8781 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8782 file, linenum, *err);
8783 return -1;
8784 }
willy tarreau982249e2005-12-18 00:57:06 +01008785 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008786 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008787 regex_t *preg;
8788 if (curproxy == &defproxy) {
8789 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8790 return -1;
8791 }
willy tarreaue39cd132005-12-17 13:00:18 +01008792
willy tarreaua41a8b42005-12-17 14:02:24 +01008793 if (*(args[1]) == 0 || *(args[2]) == 0) {
8794 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8795 file, linenum, args[0]);
8796 return -1;
8797 }
willy tarreaue39cd132005-12-17 13:00:18 +01008798
willy tarreaua41a8b42005-12-17 14:02:24 +01008799 preg = calloc(1, sizeof(regex_t));
8800 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8801 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8802 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008803 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008804
willy tarreauc1f47532005-12-18 01:08:26 +01008805 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8806 if (err) {
8807 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8808 file, linenum, *err);
8809 return -1;
8810 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008811 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008812 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8813 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008814 if (curproxy == &defproxy) {
8815 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8816 return -1;
8817 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008818
8819 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008820 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008821 return -1;
8822 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008823
willy tarreau9fe663a2005-12-17 13:02:59 +01008824 preg = calloc(1, sizeof(regex_t));
8825 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008826 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008827 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008828 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008829
willy tarreauc1f47532005-12-18 01:08:26 +01008830 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8831 if (err) {
8832 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8833 file, linenum, *err);
8834 return -1;
8835 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008836 }
willy tarreau982249e2005-12-18 00:57:06 +01008837 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8838 regex_t *preg;
8839 if (curproxy == &defproxy) {
8840 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8841 return -1;
8842 }
8843
8844 if (*(args[1]) == 0) {
8845 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8846 return -1;
8847 }
8848
8849 preg = calloc(1, sizeof(regex_t));
8850 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8851 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8852 return -1;
8853 }
8854
willy tarreauc1f47532005-12-18 01:08:26 +01008855 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8856 if (err) {
8857 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8858 file, linenum, *err);
8859 return -1;
8860 }
willy tarreau982249e2005-12-18 00:57:06 +01008861 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008862 else if (!strcmp(args[0], "rspadd")) { /* add response header */
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 }
8867
willy tarreau9fe663a2005-12-17 13:02:59 +01008868 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008869 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008870 return 0;
8871 }
8872
8873 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008874 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008875 return -1;
8876 }
8877
8878 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8879 }
willy tarreauc1f47532005-12-18 01:08:26 +01008880 else if (!strcmp(args[0], "errorloc") ||
8881 !strcmp(args[0], "errorloc302") ||
8882 !strcmp(args[0], "errorloc303")) { /* error location */
8883 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008884 char *err;
8885
willy tarreaueedaa9f2005-12-17 14:08:03 +01008886 // if (curproxy == &defproxy) {
8887 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8888 // return -1;
8889 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008890
willy tarreau8337c6b2005-12-17 13:41:01 +01008891 if (*(args[2]) == 0) {
8892 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8893 return -1;
8894 }
8895
8896 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008897 if (!strcmp(args[0], "errorloc303")) {
8898 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8899 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8900 } else {
8901 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8902 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8903 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008904
8905 if (errnum == 400) {
8906 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008907 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008908 free(curproxy->errmsg.msg400);
8909 }
8910 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008911 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008912 }
8913 else if (errnum == 403) {
8914 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008915 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008916 free(curproxy->errmsg.msg403);
8917 }
8918 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008919 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008920 }
8921 else if (errnum == 408) {
8922 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008923 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008924 free(curproxy->errmsg.msg408);
8925 }
8926 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008927 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008928 }
8929 else if (errnum == 500) {
8930 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008931 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008932 free(curproxy->errmsg.msg500);
8933 }
8934 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008935 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008936 }
8937 else if (errnum == 502) {
8938 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008939 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008940 free(curproxy->errmsg.msg502);
8941 }
8942 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008943 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008944 }
8945 else if (errnum == 503) {
8946 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008947 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008948 free(curproxy->errmsg.msg503);
8949 }
8950 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008951 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008952 }
8953 else if (errnum == 504) {
8954 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008955 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008956 free(curproxy->errmsg.msg504);
8957 }
8958 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008959 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008960 }
8961 else {
8962 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8963 free(err);
8964 }
8965 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008966 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008967 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008968 return -1;
8969 }
8970 return 0;
8971}
willy tarreaue39cd132005-12-17 13:00:18 +01008972
willy tarreau5cbea6f2005-12-17 12:48:26 +01008973
willy tarreau9fe663a2005-12-17 13:02:59 +01008974/*
8975 * This function reads and parses the configuration file given in the argument.
8976 * returns 0 if OK, -1 if error.
8977 */
8978int readcfgfile(char *file) {
8979 char thisline[256];
8980 char *line;
8981 FILE *f;
8982 int linenum = 0;
8983 char *end;
8984 char *args[MAX_LINE_ARGS];
8985 int arg;
8986 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008987 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008988 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008989
willy tarreau9fe663a2005-12-17 13:02:59 +01008990 struct proxy *curproxy = NULL;
8991 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008992
willy tarreau9fe663a2005-12-17 13:02:59 +01008993 if ((f=fopen(file,"r")) == NULL)
8994 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008995
willy tarreaueedaa9f2005-12-17 14:08:03 +01008996 init_default_instance();
8997
willy tarreau9fe663a2005-12-17 13:02:59 +01008998 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8999 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009000
willy tarreau9fe663a2005-12-17 13:02:59 +01009001 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01009002
willy tarreau9fe663a2005-12-17 13:02:59 +01009003 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01009004 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01009005 line++;
9006
9007 arg = 0;
9008 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01009009
willy tarreau9fe663a2005-12-17 13:02:59 +01009010 while (*line && arg < MAX_LINE_ARGS) {
9011 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
9012 * C equivalent value. Other combinations left unchanged (eg: \1).
9013 */
9014 if (*line == '\\') {
9015 int skip = 0;
9016 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
9017 *line = line[1];
9018 skip = 1;
9019 }
9020 else if (line[1] == 'r') {
9021 *line = '\r';
9022 skip = 1;
9023 }
9024 else if (line[1] == 'n') {
9025 *line = '\n';
9026 skip = 1;
9027 }
9028 else if (line[1] == 't') {
9029 *line = '\t';
9030 skip = 1;
9031 }
willy tarreauc1f47532005-12-18 01:08:26 +01009032 else if (line[1] == 'x') {
9033 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
9034 unsigned char hex1, hex2;
9035 hex1 = toupper(line[2]) - '0';
9036 hex2 = toupper(line[3]) - '0';
9037 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
9038 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
9039 *line = (hex1<<4) + hex2;
9040 skip = 3;
9041 }
9042 else {
9043 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
9044 return -1;
9045 }
9046 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009047 if (skip) {
9048 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
9049 end -= skip;
9050 }
9051 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009052 }
willy tarreaua1598082005-12-17 13:08:06 +01009053 else if (*line == '#' || *line == '\n' || *line == '\r') {
9054 /* end of string, end of loop */
9055 *line = 0;
9056 break;
9057 }
willy tarreauc29948c2005-12-17 13:10:27 +01009058 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009059 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01009060 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01009061 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01009062 line++;
9063 args[++arg] = line;
9064 }
9065 else {
9066 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01009067 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009068 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009069
willy tarreau9fe663a2005-12-17 13:02:59 +01009070 /* empty line */
9071 if (!**args)
9072 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01009073
willy tarreau9fe663a2005-12-17 13:02:59 +01009074 /* zero out remaining args */
9075 while (++arg < MAX_LINE_ARGS) {
9076 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009077 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009078
willy tarreaua41a8b42005-12-17 14:02:24 +01009079 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01009080 confsect = CFG_LISTEN;
9081 else if (!strcmp(args[0], "global")) /* global config */
9082 confsect = CFG_GLOBAL;
9083 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01009084
willy tarreau9fe663a2005-12-17 13:02:59 +01009085 switch (confsect) {
9086 case CFG_LISTEN:
9087 if (cfg_parse_listen(file, linenum, args) < 0)
9088 return -1;
9089 break;
9090 case CFG_GLOBAL:
9091 if (cfg_parse_global(file, linenum, args) < 0)
9092 return -1;
9093 break;
9094 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01009095 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01009096 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01009097 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009098
9099
willy tarreau0f7af912005-12-17 12:21:26 +01009100 }
9101 fclose(f);
9102
9103 /*
9104 * Now, check for the integrity of all that we have collected.
9105 */
9106
Willy TARREAU3759f982006-03-01 22:44:17 +01009107 /* will be needed further to delay some tasks */
9108 tv_now(&now);
9109
willy tarreau0f7af912005-12-17 12:21:26 +01009110 if ((curproxy = proxy) == NULL) {
9111 Alert("parsing %s : no <listen> line. Nothing to do !\n",
9112 file);
9113 return -1;
9114 }
9115
9116 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01009117 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01009118 curproxy = curproxy->next;
9119 continue;
9120 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009121
9122 if (curproxy->listen == NULL) {
9123 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);
9124 cfgerr++;
9125 }
9126 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01009127 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01009128 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009129 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
9130 file, curproxy->id);
9131 cfgerr++;
9132 }
9133 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
9134 if (curproxy->options & PR_O_TRANSP) {
9135 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
9136 file, curproxy->id);
9137 cfgerr++;
9138 }
9139 else if (curproxy->srv == NULL) {
9140 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
9141 file, curproxy->id);
9142 cfgerr++;
9143 }
willy tarreaua1598082005-12-17 13:08:06 +01009144 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01009145 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
9146 file, curproxy->id);
9147 }
9148 }
9149 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01009150 if (curproxy->cookie_name != NULL) {
9151 Warning("parsing %s : cookie will be ignored for listener %s.\n",
9152 file, curproxy->id);
9153 }
9154 if ((newsrv = curproxy->srv) != NULL) {
9155 Warning("parsing %s : servers will be ignored for listener %s.\n",
9156 file, curproxy->id);
9157 }
willy tarreaue39cd132005-12-17 13:00:18 +01009158 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009159 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
9160 file, curproxy->id);
9161 }
willy tarreaue39cd132005-12-17 13:00:18 +01009162 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01009163 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
9164 file, curproxy->id);
9165 }
9166 }
9167 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
9168 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
9169 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
9170 file, curproxy->id);
9171 cfgerr++;
9172 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009173 }
willy tarreaue3f023f2006-04-08 21:52:24 +02009174
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009175 /* first, we will invert the servers list order */
9176 newsrv = NULL;
9177 while (curproxy->srv) {
9178 struct server *next;
9179
9180 next = curproxy->srv->next;
9181 curproxy->srv->next = newsrv;
9182 newsrv = curproxy->srv;
9183 if (!next)
9184 break;
9185 curproxy->srv = next;
9186 }
9187
9188 /* now, newsrv == curproxy->srv */
9189 if (newsrv) {
9190 struct server *srv;
9191 int pgcd;
9192 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02009193
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009194 /* We will factor the weights to reduce the table,
9195 * using Euclide's largest common divisor algorithm
9196 */
9197 pgcd = newsrv->uweight + 1;
9198 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
9199 int t, w;
9200
9201 w = srv->uweight + 1;
9202 while (w) {
9203 t = pgcd % w;
9204 pgcd = w;
9205 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02009206 }
willy tarreau0f7af912005-12-17 12:21:26 +01009207 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02009208
9209 act = bck = 0;
9210 for (srv = newsrv; srv; srv = srv->next) {
9211 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
9212 if (srv->state & SRV_BACKUP)
9213 bck += srv->eweight + 1;
9214 else
9215 act += srv->eweight + 1;
9216 }
9217
9218 /* this is the largest map we will ever need for this servers list */
9219 if (act < bck)
9220 act = bck;
9221
9222 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
9223 /* recounts servers and their weights */
9224 recount_servers(curproxy);
9225 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01009226 }
willy tarreau25c4ea52005-12-18 00:49:49 +01009227
9228 if (curproxy->options & PR_O_LOGASAP)
9229 curproxy->to_log &= ~LW_BYTES;
9230
willy tarreau8337c6b2005-12-17 13:41:01 +01009231 if (curproxy->errmsg.msg400 == NULL) {
9232 curproxy->errmsg.msg400 = (char *)HTTP_400;
9233 curproxy->errmsg.len400 = strlen(HTTP_400);
9234 }
9235 if (curproxy->errmsg.msg403 == NULL) {
9236 curproxy->errmsg.msg403 = (char *)HTTP_403;
9237 curproxy->errmsg.len403 = strlen(HTTP_403);
9238 }
9239 if (curproxy->errmsg.msg408 == NULL) {
9240 curproxy->errmsg.msg408 = (char *)HTTP_408;
9241 curproxy->errmsg.len408 = strlen(HTTP_408);
9242 }
9243 if (curproxy->errmsg.msg500 == NULL) {
9244 curproxy->errmsg.msg500 = (char *)HTTP_500;
9245 curproxy->errmsg.len500 = strlen(HTTP_500);
9246 }
9247 if (curproxy->errmsg.msg502 == NULL) {
9248 curproxy->errmsg.msg502 = (char *)HTTP_502;
9249 curproxy->errmsg.len502 = strlen(HTTP_502);
9250 }
9251 if (curproxy->errmsg.msg503 == NULL) {
9252 curproxy->errmsg.msg503 = (char *)HTTP_503;
9253 curproxy->errmsg.len503 = strlen(HTTP_503);
9254 }
9255 if (curproxy->errmsg.msg504 == NULL) {
9256 curproxy->errmsg.msg504 = (char *)HTTP_504;
9257 curproxy->errmsg.len504 = strlen(HTTP_504);
9258 }
Willy TARREAU3759f982006-03-01 22:44:17 +01009259
willy tarreau59a6cc22006-05-12 01:29:08 +02009260 /*
9261 * If this server supports a maxconn parameter, it needs a dedicated
9262 * tasks to fill the emptied slots when a connection leaves.
9263 */
9264 newsrv = curproxy->srv;
9265 while (newsrv != NULL) {
9266 if (newsrv->maxconn > 0) {
9267 struct task *t;
9268
9269 if ((t = pool_alloc(task)) == NULL) {
9270 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9271 return -1;
9272 }
9273
9274 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
9275 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
9276 t->state = TASK_IDLE;
9277 t->process = process_srv_queue;
9278 t->context = newsrv;
9279 newsrv->queue_mgt = t;
9280
9281 /* never run it unless specifically woken up */
9282 tv_eternity(&t->expire);
9283 task_queue(t);
9284 }
9285 newsrv = newsrv->next;
9286 }
9287
Willy TARREAU3759f982006-03-01 22:44:17 +01009288 /* now we'll start this proxy's health checks if any */
9289 /* 1- count the checkers to run simultaneously */
9290 nbchk = 0;
9291 mininter = 0;
9292 newsrv = curproxy->srv;
9293 while (newsrv != NULL) {
9294 if (newsrv->state & SRV_CHECKED) {
9295 if (!mininter || mininter > newsrv->inter)
9296 mininter = newsrv->inter;
9297 nbchk++;
9298 }
9299 newsrv = newsrv->next;
9300 }
9301
9302 /* 2- start them as far as possible from each others while respecting
9303 * their own intervals. For this, we will start them after their own
9304 * interval added to the min interval divided by the number of servers,
9305 * weighted by the server's position in the list.
9306 */
9307 if (nbchk > 0) {
9308 struct task *t;
9309 int srvpos;
9310
9311 newsrv = curproxy->srv;
9312 srvpos = 0;
9313 while (newsrv != NULL) {
9314 /* should this server be checked ? */
9315 if (newsrv->state & SRV_CHECKED) {
9316 if ((t = pool_alloc(task)) == NULL) {
9317 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
9318 return -1;
9319 }
9320
9321 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02009322 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01009323 t->state = TASK_IDLE;
9324 t->process = process_chk;
9325 t->context = newsrv;
9326
9327 /* check this every ms */
9328 tv_delayfrom(&t->expire, &now,
9329 newsrv->inter + mininter * srvpos / nbchk);
9330 task_queue(t);
9331 //task_wakeup(&rq, t);
9332 srvpos++;
9333 }
9334 newsrv = newsrv->next;
9335 }
9336 }
9337
willy tarreau0f7af912005-12-17 12:21:26 +01009338 curproxy = curproxy->next;
9339 }
9340 if (cfgerr > 0) {
9341 Alert("Errors found in configuration file, aborting.\n");
9342 return -1;
9343 }
9344 else
9345 return 0;
9346}
9347
9348
9349/*
9350 * This function initializes all the necessary variables. It only returns
9351 * if everything is OK. If something fails, it exits.
9352 */
9353void init(int argc, char **argv) {
9354 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01009355 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01009356 char *old_argv = *argv;
9357 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009358 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009359
9360 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01009361 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01009362 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01009363 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01009364 exit(1);
9365 }
9366
willy tarreau746e26b2006-03-25 11:14:35 +01009367#ifdef HAPROXY_MEMMAX
9368 global.rlimit_memmax = HAPROXY_MEMMAX;
9369#endif
9370
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009371 /* initialize the libc's localtime structures once for all so that we
9372 * won't be missing memory if we want to send alerts under OOM conditions.
9373 */
9374 tv_now(&now);
9375 localtime(&now.tv_sec);
willy tarreaue0331262006-05-15 03:02:46 +02009376 start_date = now;
Willy TARREAUa9e75f62006-03-01 22:27:48 +01009377
willy tarreau4302f492005-12-18 01:00:37 +01009378 /* initialize the log header encoding map : '{|}"#' should be encoded with
9379 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
9380 * URL encoding only requires '"', '#' to be encoded as well as non-
9381 * printable characters above.
9382 */
9383 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
9384 memset(url_encode_map, 0, sizeof(url_encode_map));
9385 for (i = 0; i < 32; i++) {
9386 FD_SET(i, hdr_encode_map);
9387 FD_SET(i, url_encode_map);
9388 }
9389 for (i = 127; i < 256; i++) {
9390 FD_SET(i, hdr_encode_map);
9391 FD_SET(i, url_encode_map);
9392 }
9393
9394 tmp = "\"#{|}";
9395 while (*tmp) {
9396 FD_SET(*tmp, hdr_encode_map);
9397 tmp++;
9398 }
9399
9400 tmp = "\"#";
9401 while (*tmp) {
9402 FD_SET(*tmp, url_encode_map);
9403 tmp++;
9404 }
9405
willy tarreau64a3cc32005-12-18 01:13:11 +01009406 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
9407#if defined(ENABLE_POLL)
9408 cfg_polling_mechanism |= POLL_USE_POLL;
9409#endif
9410#if defined(ENABLE_EPOLL)
9411 cfg_polling_mechanism |= POLL_USE_EPOLL;
9412#endif
9413
willy tarreau0f7af912005-12-17 12:21:26 +01009414 pid = getpid();
9415 progname = *argv;
9416 while ((tmp = strchr(progname, '/')) != NULL)
9417 progname = tmp + 1;
9418
9419 argc--; argv++;
9420 while (argc > 0) {
9421 char *flag;
9422
9423 if (**argv == '-') {
9424 flag = *argv+1;
9425
9426 /* 1 arg */
9427 if (*flag == 'v') {
9428 display_version();
9429 exit(0);
9430 }
willy tarreau1c2ad212005-12-18 01:11:29 +01009431#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009432 else if (*flag == 'd' && flag[1] == 'e')
9433 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009434#endif
9435#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009436 else if (*flag == 'd' && flag[1] == 'p')
9437 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009438#endif
willy tarreau982249e2005-12-18 00:57:06 +01009439 else if (*flag == 'V')
9440 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009441 else if (*flag == 'd' && flag[1] == 'b')
9442 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01009443 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01009444 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01009445 else if (*flag == 'c')
9446 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01009447 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01009448 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009449 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01009450 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01009451 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
9452 /* list of pids to finish ('f') or terminate ('t') */
9453
9454 if (flag[1] == 'f')
9455 oldpids_sig = SIGUSR1; /* finish then exit */
9456 else
9457 oldpids_sig = SIGTERM; /* terminate immediately */
9458 argv++; argc--;
9459
9460 if (argc > 0) {
9461 oldpids = calloc(argc, sizeof(int));
9462 while (argc > 0) {
9463 oldpids[nb_oldpids] = atol(*argv);
9464 if (oldpids[nb_oldpids] <= 0)
9465 usage(old_argv);
9466 argc--; argv++;
9467 nb_oldpids++;
9468 }
9469 }
9470 }
willy tarreau2c513732006-04-15 19:25:16 +02009471#if STATTIME > 0
9472 else if (*flag == 's')
9473 arg_mode |= MODE_STATS;
9474 else if (*flag == 'l')
9475 arg_mode |= MODE_LOG;
9476#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009477 else { /* >=2 args */
9478 argv++; argc--;
9479 if (argc == 0)
9480 usage(old_argv);
9481
9482 switch (*flag) {
9483 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01009484 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01009485 case 'N' : cfg_maxpconn = atol(*argv); break;
9486 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009487 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01009488 default: usage(old_argv);
9489 }
9490 }
9491 }
9492 else
9493 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01009494 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01009495 }
9496
willy tarreaud0fb4652005-12-18 01:32:04 +01009497 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009498 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
9499 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01009500
willy tarreau0f7af912005-12-17 12:21:26 +01009501 if (!cfg_cfgfile)
9502 usage(old_argv);
9503
9504 gethostname(hostname, MAX_HOSTNAME_LEN);
9505
willy tarreau12350152005-12-18 01:03:27 +01009506 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01009507 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01009508 if (readcfgfile(cfg_cfgfile) < 0) {
9509 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
9510 exit(1);
9511 }
willy tarreau12350152005-12-18 01:03:27 +01009512 if (have_appsession)
9513 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01009514
willy tarreau982249e2005-12-18 00:57:06 +01009515 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01009516 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
9517 exit(0);
9518 }
9519
willy tarreau9fe663a2005-12-17 13:02:59 +01009520 if (cfg_maxconn > 0)
9521 global.maxconn = cfg_maxconn;
9522
willy tarreaufe2c5c12005-12-17 14:14:34 +01009523 if (cfg_pidfile) {
9524 if (global.pidfile)
9525 free(global.pidfile);
9526 global.pidfile = strdup(cfg_pidfile);
9527 }
9528
willy tarreau9fe663a2005-12-17 13:02:59 +01009529 if (global.maxconn == 0)
9530 global.maxconn = DEFAULT_MAXCONN;
9531
Willy TARREAU203b0b62006-03-12 18:00:28 +01009532 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01009533
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009534 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009535 /* command line debug mode inhibits configuration mode */
9536 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9537 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009538 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
9539 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01009540
9541 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
9542 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
9543 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9544 }
9545
9546 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009547 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
9548 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01009549 global.nbproc = 1;
9550 }
9551
9552 if (global.nbproc < 1)
9553 global.nbproc = 1;
9554
willy tarreau0f7af912005-12-17 12:21:26 +01009555 StaticReadEvent = (fd_set *)calloc(1,
9556 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009557 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009558 StaticWriteEvent = (fd_set *)calloc(1,
9559 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009560 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009561
9562 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01009563 sizeof(struct fdtab) * (global.maxsock));
9564 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01009565 fdtab[i].state = FD_STCLOSE;
9566 }
9567}
9568
9569/*
willy tarreau41310e72006-03-25 18:17:56 +01009570 * this function starts all the proxies. Its return value is composed from
9571 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
9572 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01009573 */
willy tarreau41310e72006-03-25 18:17:56 +01009574int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01009575 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01009576 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01009577 int err = ERR_NONE;
9578 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01009579
9580 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009581 if (curproxy->state != PR_STNEW)
9582 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009583
willy tarreau41310e72006-03-25 18:17:56 +01009584 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009585 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009586 if (listener->fd != -1)
9587 continue; /* already initialized */
9588
9589 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9590 if (verbose)
9591 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9592 curproxy->id);
9593 err |= ERR_RETRYABLE;
9594 pxerr |= 1;
9595 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009596 }
willy tarreau0f7af912005-12-17 12:21:26 +01009597
willy tarreaua41a8b42005-12-17 14:02:24 +01009598 if (fd >= global.maxsock) {
9599 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9600 curproxy->id);
9601 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009602 err |= ERR_FATAL;
9603 pxerr |= 1;
9604 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009605 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009606
willy tarreaua41a8b42005-12-17 14:02:24 +01009607 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9608 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9609 (char *) &one, sizeof(one)) == -1)) {
9610 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9611 curproxy->id);
9612 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009613 err |= ERR_FATAL;
9614 pxerr |= 1;
9615 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009616 }
willy tarreau0f7af912005-12-17 12:21:26 +01009617
willy tarreaua41a8b42005-12-17 14:02:24 +01009618 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9619 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9620 curproxy->id);
9621 }
willy tarreau0f7af912005-12-17 12:21:26 +01009622
willy tarreaua41a8b42005-12-17 14:02:24 +01009623 if (bind(fd,
9624 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009625 listener->addr.ss_family == AF_INET6 ?
9626 sizeof(struct sockaddr_in6) :
9627 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009628 if (verbose)
9629 Alert("cannot bind socket for proxy %s. Aborting.\n",
9630 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009631 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009632 err |= ERR_RETRYABLE;
9633 pxerr |= 1;
9634 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009635 }
willy tarreau0f7af912005-12-17 12:21:26 +01009636
willy tarreaua41a8b42005-12-17 14:02:24 +01009637 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009638 if (verbose)
9639 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9640 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009641 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009642 err |= ERR_RETRYABLE;
9643 pxerr |= 1;
9644 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009645 }
willy tarreau0f7af912005-12-17 12:21:26 +01009646
willy tarreau41310e72006-03-25 18:17:56 +01009647 /* the socket is ready */
9648 listener->fd = fd;
9649
willy tarreaua41a8b42005-12-17 14:02:24 +01009650 /* the function for the accept() event */
9651 fdtab[fd].read = &event_accept;
9652 fdtab[fd].write = NULL; /* never called */
9653 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009654 fdtab[fd].state = FD_STLISTEN;
9655 FD_SET(fd, StaticReadEvent);
9656 fd_insert(fd);
9657 listeners++;
9658 }
willy tarreau41310e72006-03-25 18:17:56 +01009659
9660 if (!pxerr) {
9661 curproxy->state = PR_STRUN;
9662 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9663 }
willy tarreau0f7af912005-12-17 12:21:26 +01009664 }
willy tarreau41310e72006-03-25 18:17:56 +01009665
9666 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009667}
9668
willy tarreaub952e1d2005-12-18 01:31:20 +01009669int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009670
9671 appsess *temp1,*temp2;
9672 temp1 = (appsess *)key1;
9673 temp2 = (appsess *)key2;
9674
9675 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9676 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9677
9678 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9679}/* end match_str */
9680
willy tarreaub952e1d2005-12-18 01:31:20 +01009681void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009682 appsess *temp1;
9683
9684 //printf("destroy called\n");
9685 temp1 = (appsess *)data;
9686
9687 if (temp1->sessid)
9688 pool_free_to(apools.sessid, temp1->sessid);
9689
9690 if (temp1->serverid)
9691 pool_free_to(apools.serverid, temp1->serverid);
9692
9693 pool_free(appsess, temp1);
9694} /* end destroy */
9695
9696void appsession_cleanup( void )
9697{
9698 struct proxy *p = proxy;
9699
9700 while(p) {
9701 chtbl_destroy(&(p->htbl_proxy));
9702 p = p->next;
9703 }
9704}/* end appsession_cleanup() */
9705
9706void pool_destroy(void **pool)
9707{
9708 void *temp, *next;
9709 next = pool;
9710 while (next) {
9711 temp = next;
9712 next = *(void **)temp;
9713 free(temp);
9714 }
9715}/* end pool_destroy() */
9716
willy tarreaub952e1d2005-12-18 01:31:20 +01009717void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009718 struct proxy *p = proxy;
9719 struct cap_hdr *h,*h_next;
9720 struct server *s,*s_next;
9721 struct listener *l,*l_next;
9722
9723 while (p) {
9724 if (p->id)
9725 free(p->id);
9726
9727 if (p->check_req)
9728 free(p->check_req);
9729
9730 if (p->cookie_name)
9731 free(p->cookie_name);
9732
9733 if (p->capture_name)
9734 free(p->capture_name);
9735
9736 /* only strup if the user have set in config.
9737 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009738 if (p->errmsg.msg400) free(p->errmsg.msg400);
9739 if (p->errmsg.msg403) free(p->errmsg.msg403);
9740 if (p->errmsg.msg408) free(p->errmsg.msg408);
9741 if (p->errmsg.msg500) free(p->errmsg.msg500);
9742 if (p->errmsg.msg502) free(p->errmsg.msg502);
9743 if (p->errmsg.msg503) free(p->errmsg.msg503);
9744 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009745 */
9746 if (p->appsession_name)
9747 free(p->appsession_name);
9748
9749 h = p->req_cap;
9750 while (h) {
9751 h_next = h->next;
9752 if (h->name)
9753 free(h->name);
9754 pool_destroy(h->pool);
9755 free(h);
9756 h = h_next;
9757 }/* end while(h) */
9758
9759 h = p->rsp_cap;
9760 while (h) {
9761 h_next = h->next;
9762 if (h->name)
9763 free(h->name);
9764
9765 pool_destroy(h->pool);
9766 free(h);
9767 h = h_next;
9768 }/* end while(h) */
9769
9770 s = p->srv;
9771 while (s) {
9772 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009773 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009774 free(s->id);
9775
willy tarreaub952e1d2005-12-18 01:31:20 +01009776 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009777 free(s->cookie);
9778
9779 free(s);
9780 s = s_next;
9781 }/* end while(s) */
9782
9783 l = p->listen;
9784 while (l) {
9785 l_next = l->next;
9786 free(l);
9787 l = l_next;
9788 }/* end while(l) */
9789
9790 pool_destroy((void **) p->req_cap_pool);
9791 pool_destroy((void **) p->rsp_cap_pool);
9792 p = p->next;
9793 }/* end while(p) */
9794
9795 if (global.chroot) free(global.chroot);
9796 if (global.pidfile) free(global.pidfile);
9797
willy tarreau12350152005-12-18 01:03:27 +01009798 if (StaticReadEvent) free(StaticReadEvent);
9799 if (StaticWriteEvent) free(StaticWriteEvent);
9800 if (fdtab) free(fdtab);
9801
9802 pool_destroy(pool_session);
9803 pool_destroy(pool_buffer);
9804 pool_destroy(pool_fdtab);
9805 pool_destroy(pool_requri);
9806 pool_destroy(pool_task);
9807 pool_destroy(pool_capture);
9808 pool_destroy(pool_appsess);
9809
9810 if (have_appsession) {
9811 pool_destroy(apools.serverid);
9812 pool_destroy(apools.sessid);
9813 }
9814} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009815
willy tarreau41310e72006-03-25 18:17:56 +01009816/* sends the signal <sig> to all pids found in <oldpids> */
9817static void tell_old_pids(int sig) {
9818 int p;
9819 for (p = 0; p < nb_oldpids; p++)
9820 kill(oldpids[p], sig);
9821}
9822
willy tarreau0f7af912005-12-17 12:21:26 +01009823int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009824 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009825 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009826 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009827 init(argc, argv);
9828
willy tarreau0f7af912005-12-17 12:21:26 +01009829 signal(SIGQUIT, dump);
9830 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009831 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009832#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009833 signal(SIGINT, sig_int);
9834 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009835#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009836
9837 /* on very high loads, a sigpipe sometimes happen just between the
9838 * getsockopt() which tells "it's OK to write", and the following write :-(
9839 */
willy tarreau3242e862005-12-17 12:27:53 +01009840#ifndef MSG_NOSIGNAL
9841 signal(SIGPIPE, SIG_IGN);
9842#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009843
willy tarreau41310e72006-03-25 18:17:56 +01009844 /* We will loop at most 100 times with 10 ms delay each time.
9845 * That's at most 1 second. We only send a signal to old pids
9846 * if we cannot grab at least one port.
9847 */
9848 retry = MAX_START_RETRIES;
9849 err = ERR_NONE;
9850 while (retry >= 0) {
9851 struct timeval w;
9852 err = start_proxies(retry == 0 || nb_oldpids == 0);
9853 if (err != ERR_RETRYABLE)
9854 break;
9855 if (nb_oldpids == 0)
9856 break;
9857
Willy TARREAU007aa462006-05-14 09:55:23 +02009858 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
9859 * listening sockets. So on those platforms, it would be wiser to
9860 * simply send SIGUSR1, which will not be undoable.
9861 */
willy tarreau41310e72006-03-25 18:17:56 +01009862 tell_old_pids(SIGTTOU);
9863 /* give some time to old processes to stop listening */
9864 w.tv_sec = 0;
9865 w.tv_usec = 10*1000;
9866 select(0, NULL, NULL, NULL, &w);
9867 retry--;
9868 }
9869
9870 /* Note: start_proxies() sends an alert when it fails. */
9871 if (err != ERR_NONE) {
9872 if (retry != MAX_START_RETRIES && nb_oldpids)
9873 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009874 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009875 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009876
9877 if (listeners == 0) {
9878 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009879 /* Note: we don't have to send anything to the old pids because we
9880 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009881 exit(1);
9882 }
9883
willy tarreaudbd3bef2006-01-20 19:35:18 +01009884 /* prepare pause/play signals */
9885 signal(SIGTTOU, sig_pause);
9886 signal(SIGTTIN, sig_listen);
9887
Willy TARREAUe3283d12006-03-01 22:15:29 +01009888 if (global.mode & MODE_DAEMON) {
9889 global.mode &= ~MODE_VERBOSE;
9890 global.mode |= MODE_QUIET;
9891 }
9892
willy tarreaud0fb4652005-12-18 01:32:04 +01009893 /* MODE_QUIET can inhibit alerts and warnings below this line */
9894
9895 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009896 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009897 /* detach from the tty */
9898 fclose(stdin); fclose(stdout); fclose(stderr);
9899 close(0); close(1); close(2);
9900 }
willy tarreau0f7af912005-12-17 12:21:26 +01009901
willy tarreaufe2c5c12005-12-17 14:14:34 +01009902 /* open log & pid files before the chroot */
9903 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9904 int pidfd;
9905 unlink(global.pidfile);
9906 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9907 if (pidfd < 0) {
9908 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009909 if (nb_oldpids)
9910 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009911 exit(1);
9912 }
9913 pidfile = fdopen(pidfd, "w");
9914 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009915
9916 /* chroot if needed */
9917 if (global.chroot != NULL) {
9918 if (chroot(global.chroot) == -1) {
9919 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009920 if (nb_oldpids)
9921 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009922 }
9923 chdir("/");
9924 }
9925
willy tarreaub1285d52005-12-18 01:20:14 +01009926 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009927 if (!global.rlimit_nofile)
9928 global.rlimit_nofile = global.maxsock;
9929
willy tarreaub1285d52005-12-18 01:20:14 +01009930 if (global.rlimit_nofile) {
9931 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9932 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9933 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9934 }
willy tarreau746e26b2006-03-25 11:14:35 +01009935 }
9936
9937 if (global.rlimit_memmax) {
9938 limit.rlim_cur = limit.rlim_max =
9939 global.rlimit_memmax * 1048576 / global.nbproc;
9940#ifdef RLIMIT_AS
9941 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9942 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9943 argv[0], global.rlimit_memmax);
9944 }
9945#else
9946 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9947 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9948 argv[0], global.rlimit_memmax);
9949 }
9950#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009951 }
9952
willy tarreau41310e72006-03-25 18:17:56 +01009953 if (nb_oldpids)
9954 tell_old_pids(oldpids_sig);
9955
9956 /* Note that any error at this stage will be fatal because we will not
9957 * be able to restart the old pids.
9958 */
9959
willy tarreau9fe663a2005-12-17 13:02:59 +01009960 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009961 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009962 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9963 exit(1);
9964 }
9965
willy tarreau036e1ce2005-12-17 13:46:33 +01009966 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009967 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9968 exit(1);
9969 }
9970
willy tarreaub1285d52005-12-18 01:20:14 +01009971 /* check ulimits */
9972 limit.rlim_cur = limit.rlim_max = 0;
9973 getrlimit(RLIMIT_NOFILE, &limit);
9974 if (limit.rlim_cur < global.maxsock) {
9975 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",
9976 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9977 }
9978
willy tarreau9fe663a2005-12-17 13:02:59 +01009979 if (global.mode & MODE_DAEMON) {
9980 int ret = 0;
9981 int proc;
9982
9983 /* the father launches the required number of processes */
9984 for (proc = 0; proc < global.nbproc; proc++) {
9985 ret = fork();
9986 if (ret < 0) {
9987 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009988 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009989 exit(1); /* there has been an error */
9990 }
9991 else if (ret == 0) /* child breaks here */
9992 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009993 if (pidfile != NULL) {
9994 fprintf(pidfile, "%d\n", ret);
9995 fflush(pidfile);
9996 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009997 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009998 /* close the pidfile both in children and father */
9999 if (pidfile != NULL)
10000 fclose(pidfile);
10001 free(global.pidfile);
10002
willy tarreau9fe663a2005-12-17 13:02:59 +010010003 if (proc == global.nbproc)
10004 exit(0); /* parent must leave */
10005
willy tarreau750a4722005-12-17 13:21:24 +010010006 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
10007 * that we can detach from the TTY. We MUST NOT do it in other cases since
10008 * it would have already be done, and 0-2 would have been affected to listening
10009 * sockets
10010 */
10011 if (!(global.mode & MODE_QUIET)) {
10012 /* detach from the tty */
10013 fclose(stdin); fclose(stdout); fclose(stderr);
10014 close(0); close(1); close(2); /* close all fd's */
10015 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
10016 }
willy tarreaua1598082005-12-17 13:08:06 +010010017 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +010010018 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +010010019 }
10020
willy tarreau1c2ad212005-12-18 01:11:29 +010010021#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010022 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010023 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
10024 epoll_loop(POLL_LOOP_ACTION_RUN);
10025 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010026 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010027 }
10028 else {
willy tarreau64a3cc32005-12-18 01:13:11 +010010029 Warning("epoll() is not available. Using poll()/select() instead.\n");
10030 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010031 }
10032 }
10033#endif
10034
10035#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +010010036 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010037 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
10038 poll_loop(POLL_LOOP_ACTION_RUN);
10039 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010040 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010041 }
10042 else {
10043 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +010010044 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +010010045 }
10046 }
10047#endif
willy tarreau64a3cc32005-12-18 01:13:11 +010010048 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +010010049 if (select_loop(POLL_LOOP_ACTION_INIT)) {
10050 select_loop(POLL_LOOP_ACTION_RUN);
10051 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +010010052 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +010010053 }
10054 }
10055
willy tarreau0f7af912005-12-17 12:21:26 +010010056
willy tarreau12350152005-12-18 01:03:27 +010010057 /* Free all Hash Keys and all Hash elements */
10058 appsession_cleanup();
10059 /* Do some cleanup */
10060 deinit();
10061
willy tarreau0f7af912005-12-17 12:21:26 +010010062 exit(0);
10063}
willy tarreau12350152005-12-18 01:03:27 +010010064
10065#if defined(DEBUG_HASH)
10066static void print_table(const CHTbl *htbl) {
10067
10068 ListElmt *element;
10069 int i;
10070 appsess *asession;
10071
10072 /*****************************************************************************
10073 * *
10074 * Display the chained hash table. *
10075 * *
10076 *****************************************************************************/
10077
10078 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
10079
10080 for (i = 0; i < TBLSIZ; i++) {
10081 fprintf(stdout, "Bucket[%03d]\n", i);
10082
10083 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10084 //fprintf(stdout, "%c", *(char *)list_data(element));
10085 asession = (appsess *)list_data(element);
10086 fprintf(stdout, "ELEM :%s:", asession->sessid);
10087 fprintf(stdout, " Server :%s: \n", asession->serverid);
10088 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
10089 }
10090
10091 fprintf(stdout, "\n");
10092 }
10093 return;
10094} /* end print_table */
10095#endif
10096
10097static int appsession_init(void)
10098{
10099 static int initialized = 0;
10100 int idlen;
10101 struct server *s;
10102 struct proxy *p = proxy;
10103
10104 if (!initialized) {
10105 if (!appsession_task_init()) {
10106 apools.sessid = NULL;
10107 apools.serverid = NULL;
10108 apools.ser_waste = 0;
10109 apools.ser_use = 0;
10110 apools.ser_msize = sizeof(void *);
10111 apools.ses_waste = 0;
10112 apools.ses_use = 0;
10113 apools.ses_msize = sizeof(void *);
10114 while (p) {
10115 s = p->srv;
10116 if (apools.ses_msize < p->appsession_len)
10117 apools.ses_msize = p->appsession_len;
10118 while (s) {
10119 idlen = strlen(s->id);
10120 if (apools.ser_msize < idlen)
10121 apools.ser_msize = idlen;
10122 s = s->next;
10123 }
10124 p = p->next;
10125 }
10126 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
10127 apools.ses_msize ++;
10128 }
10129 else {
10130 fprintf(stderr, "appsession_task_init failed\n");
10131 return -1;
10132 }
10133 initialized ++;
10134 }
10135 return 0;
10136}
10137
10138static int appsession_task_init(void)
10139{
10140 static int initialized = 0;
10141 struct task *t;
10142 if (!initialized) {
10143 if ((t = pool_alloc(task)) == NULL)
10144 return -1;
10145 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +020010146 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +010010147 t->state = TASK_IDLE;
10148 t->context = NULL;
10149 tv_delayfrom(&t->expire, &now, TBLCHKINT);
10150 task_queue(t);
10151 t->process = appsession_refresh;
10152 initialized ++;
10153 }
10154 return 0;
10155}
10156
10157static int appsession_refresh(struct task *t) {
10158 struct proxy *p = proxy;
10159 CHTbl *htbl;
10160 ListElmt *element, *last;
10161 int i;
10162 appsess *asession;
10163 void *data;
10164
10165 while (p) {
10166 if (p->appsession_name != NULL) {
10167 htbl = &p->htbl_proxy;
10168 /* if we ever give up the use of TBLSIZ, we need to change this */
10169 for (i = 0; i < TBLSIZ; i++) {
10170 last = NULL;
10171 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
10172 asession = (appsess *)list_data(element);
10173 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
10174 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
10175 int len;
10176 /*
10177 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
10178 */
10179 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
10180 asession->sessid, asession->serverid?asession->serverid:"(null)");
10181 write(1, trash, len);
10182 }
10183 /* delete the expired element from within the hash table */
10184 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
10185 && (htbl->table[i].destroy != NULL)) {
10186 htbl->table[i].destroy(data);
10187 }
10188 if (last == NULL) {/* patient lost his head, get a new one */
10189 element = list_head(&htbl->table[i]);
10190 if (element == NULL) break; /* no heads left, go to next patient */
10191 }
10192 else
10193 element = last;
10194 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
10195 else
10196 last = element;
10197 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
10198 }
10199 }
10200 p = p->next;
10201 }
10202 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
10203 return TBLCHKINT;
10204} /* end appsession_refresh */
10205
willy tarreau18a957c2006-04-12 19:26:23 +020010206
10207/*
10208 * Local variables:
10209 * c-indent-level: 4
10210 * c-basic-offset: 4
10211 * End:
10212 */