blob: acc97c65dc0609c69dcb77c5cd6e77df89602ec8 [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 tarreau0f7af912005-12-17 12:21:26 +0100174/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
175#define INTBITS 5
176
177/* show stats this every millisecond, 0 to disable */
178#ifndef STATTIME
179#define STATTIME 2000
180#endif
181
willy tarreau5cbea6f2005-12-17 12:48:26 +0100182/* this reduces the number of calls to select() by choosing appropriate
183 * sheduler precision in milliseconds. It should be near the minimum
184 * time that is needed by select() to collect all events. All timeouts
185 * are rounded up by adding this value prior to pass it to select().
186 */
187#define SCHEDULER_RESOLUTION 9
188
willy tarreaub952e1d2005-12-18 01:31:20 +0100189#define TIME_ETERNITY -1
190/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100191#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
192#define SETNOW(a) (*a=now)
193
willy tarreau9da061b2005-12-17 12:29:56 +0100194/****** string-specific macros and functions ******/
195/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
196#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
197
198/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
199#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
200
willy tarreau0174f312005-12-18 01:02:42 +0100201/* returns 1 only if only zero or one bit is set in X, which means that X is a
202 * power of 2, and 0 otherwise */
203#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100204/*
205 * copies at most <size-1> chars from <src> to <dst>. Last char is always
206 * set to 0, unless <size> is 0. The number of chars copied is returned
207 * (excluding the terminating zero).
208 * This code has been optimized for size and speed : on x86, it's 45 bytes
209 * long, uses only registers, and consumes only 4 cycles per char.
210 */
willy tarreau750a4722005-12-17 13:21:24 +0100211int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100212 char *orig = dst;
213 if (size) {
214 while (--size && (*dst = *src)) {
215 src++; dst++;
216 }
217 *dst = 0;
218 }
219 return dst - orig;
220}
willy tarreau9da061b2005-12-17 12:29:56 +0100221
willy tarreau4302f492005-12-18 01:00:37 +0100222/*
223 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
224 * dynamically allocated. In the first case, <__pool> is updated to point to
225 * the next element in the list.
226 */
227#define pool_alloc_from(__pool, __len) ({ \
228 void *__p; \
229 if ((__p = (__pool)) == NULL) \
230 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
231 else { \
232 __pool = *(void **)(__pool); \
233 } \
234 __p; \
235})
236
237/*
238 * Puts a memory area back to the corresponding pool.
239 * Items are chained directly through a pointer that
240 * is written in the beginning of the memory area, so
241 * there's no need for any carrier cell. This implies
242 * that each memory area is at least as big as one
243 * pointer.
244 */
245#define pool_free_to(__pool, __ptr) ({ \
246 *(void **)(__ptr) = (void *)(__pool); \
247 __pool = (void *)(__ptr); \
248})
249
250
willy tarreau0f7af912005-12-17 12:21:26 +0100251#define MEM_OPTIM
252#ifdef MEM_OPTIM
253/*
254 * Returns a pointer to type <type> taken from the
255 * pool <pool_type> or dynamically allocated. In the
256 * first case, <pool_type> is updated to point to the
257 * next element in the list.
258 */
259#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100260 void *__p; \
261 if ((__p = pool_##type) == NULL) \
262 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100263 else { \
264 pool_##type = *(void **)pool_##type; \
265 } \
willy tarreau4302f492005-12-18 01:00:37 +0100266 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100267})
268
269/*
270 * Puts a memory area back to the corresponding pool.
271 * Items are chained directly through a pointer that
272 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100273 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100274 * that each memory area is at least as big as one
275 * pointer.
276 */
277#define pool_free(type, ptr) ({ \
278 *(void **)ptr = (void *)pool_##type; \
279 pool_##type = (void *)ptr; \
280})
281
282#else
283#define pool_alloc(type) (calloc(1,sizeof_##type));
284#define pool_free(type, ptr) (free(ptr));
285#endif /* MEM_OPTIM */
286
willy tarreau5cbea6f2005-12-17 12:48:26 +0100287#define sizeof_task sizeof(struct task)
288#define sizeof_session sizeof(struct session)
willy tarreau18a957c2006-04-12 19:26:23 +0200289#define sizeof_pendconn sizeof(struct pendconn)
willy tarreau0f7af912005-12-17 12:21:26 +0100290#define sizeof_buffer sizeof(struct buffer)
291#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100292#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100293#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100294#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100295#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100296
willy tarreau5cbea6f2005-12-17 12:48:26 +0100297/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100298#define FD_STCLOSE 0
299#define FD_STLISTEN 1
300#define FD_STCONN 2
301#define FD_STREADY 3
302#define FD_STERROR 4
303
willy tarreau5cbea6f2005-12-17 12:48:26 +0100304/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100305#define TASK_IDLE 0
306#define TASK_RUNNING 1
307
willy tarreau5cbea6f2005-12-17 12:48:26 +0100308/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100309#define PR_STNEW 0
310#define PR_STIDLE 1
311#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100312#define PR_STSTOPPED 3
313#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100314
willy tarreau5cbea6f2005-12-17 12:48:26 +0100315/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100316#define PR_MODE_TCP 0
317#define PR_MODE_HTTP 1
318#define PR_MODE_HEALTH 2
319
willy tarreau1c2ad212005-12-18 01:11:29 +0100320/* possible actions for the *poll() loops */
321#define POLL_LOOP_ACTION_INIT 0
322#define POLL_LOOP_ACTION_RUN 1
323#define POLL_LOOP_ACTION_CLEAN 2
324
willy tarreau64a3cc32005-12-18 01:13:11 +0100325/* poll mechanisms available */
326#define POLL_USE_SELECT (1<<0)
327#define POLL_USE_POLL (1<<1)
328#define POLL_USE_EPOLL (1<<2)
329
willy tarreau5cbea6f2005-12-17 12:48:26 +0100330/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100331#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
332#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
333#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
334#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
335#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
336#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
337#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
338#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100339#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
340#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
341#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
342#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
343#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
344#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
345#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
346#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
347#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
348#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
349#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100350#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
351#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100352#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100353#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100354#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
355#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100356
willy tarreaua5e8c662006-04-29 10:43:46 +0200357/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100358#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
359#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
360#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
361#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
362#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
363#define SN_POST 0x00000020 /* the request was an HTTP POST */
364
willy tarreaua5e8c662006-04-29 10:43:46 +0200365/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100366#define SN_CK_NONE 0x00000000 /* this session had no cookie */
367#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
368#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
369#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
370#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
371#define SN_CK_SHIFT 6 /* bit shift */
372
willy tarreaua5e8c662006-04-29 10:43:46 +0200373/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100374#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100375#define SN_ERR_CLITO 0x00000100 /* client time-out */
376#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
377#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
378#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
379#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100380#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
381#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100382#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
383#define SN_ERR_SHIFT 8 /* bit shift */
384
willy tarreaua5e8c662006-04-29 10:43:46 +0200385/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100386#define SN_FINST_R 0x00001000 /* session ended during client request */
387#define SN_FINST_C 0x00002000 /* session ended during server connect */
388#define SN_FINST_H 0x00003000 /* session ended during server headers */
389#define SN_FINST_D 0x00004000 /* session ended during data phase */
390#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
willy tarreau078c79a2006-05-13 12:23:58 +0200391#define SN_FINST_Q 0x00006000 /* session ended while waiting in queue for a server slot */
willy tarreau036e1ce2005-12-17 13:46:33 +0100392#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
393#define SN_FINST_SHIFT 12 /* bit shift */
394
willy tarreaua5e8c662006-04-29 10:43:46 +0200395/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100396#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
397#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
398#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
399#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
400#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100401#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100402#define SN_SCK_SHIFT 16 /* bit shift */
403
willy tarreaua5e8c662006-04-29 10:43:46 +0200404/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100405#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
406#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
407#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100408
willy tarreaua5e8c662006-04-29 10:43:46 +0200409/* various other session flags, bits values 0x400000 and above */
410#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200411#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
412#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaua5e8c662006-04-29 10:43:46 +0200413
414
willy tarreau5cbea6f2005-12-17 12:48:26 +0100415/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100416#define CL_STHEADERS 0
417#define CL_STDATA 1
418#define CL_STSHUTR 2
419#define CL_STSHUTW 3
420#define CL_STCLOSE 4
421
willy tarreau5cbea6f2005-12-17 12:48:26 +0100422/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100423#define SV_STIDLE 0
willy tarreau9fea1942006-05-12 19:46:40 +0200424#define SV_STCONN 1
425#define SV_STHEADERS 2
426#define SV_STDATA 3
427#define SV_STSHUTR 4
428#define SV_STSHUTW 5
429#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100430
431/* result of an I/O event */
432#define RES_SILENT 0 /* didn't happen */
433#define RES_DATA 1 /* data were sent or received */
434#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
435#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
436
willy tarreau9fe663a2005-12-17 13:02:59 +0100437/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100438#define MODE_DEBUG 1
439#define MODE_STATS 2
440#define MODE_LOG 4
441#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100442#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100443#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100444#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100445#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100446#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100447
448/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100449#define SRV_RUNNING 1 /* the server is UP */
450#define SRV_BACKUP 2 /* this server is a backup server */
451#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100452#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100453#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100454
willy tarreaudfece232006-05-02 00:19:57 +0200455/* function which act on servers need to return various errors */
456#define SRV_STATUS_OK 0 /* everything is OK. */
457#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
458#define SRV_STATUS_NOSRV 2 /* no server is available */
459#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
460#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
461
willy tarreaue39cd132005-12-17 13:00:18 +0100462/* what to do when a header matches a regex */
463#define ACT_ALLOW 0 /* allow the request */
464#define ACT_REPLACE 1 /* replace the matching header */
465#define ACT_REMOVE 2 /* remove the matching header */
466#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100467#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100468
willy tarreau9fe663a2005-12-17 13:02:59 +0100469/* configuration sections */
470#define CFG_NONE 0
471#define CFG_GLOBAL 1
472#define CFG_LISTEN 2
473
willy tarreaua1598082005-12-17 13:08:06 +0100474/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100475#define LW_DATE 1 /* date */
476#define LW_CLIP 2 /* CLient IP */
477#define LW_SVIP 4 /* SerVer IP */
478#define LW_SVID 8 /* server ID */
479#define LW_REQ 16 /* http REQuest */
480#define LW_RESP 32 /* http RESPonse */
481#define LW_PXIP 64 /* proxy IP */
482#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100483#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100484#define LW_COOKIE 512 /* captured cookie */
485#define LW_REQHDR 1024 /* request header(s) */
486#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100487
willy tarreau41310e72006-03-25 18:17:56 +0100488#define ERR_NONE 0 /* no error */
489#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
490#define ERR_FATAL 2 /* fatal error, may be cumulated */
491
willy tarreau0f7af912005-12-17 12:21:26 +0100492/*********************************************************************/
493
494#define LIST_HEAD(a) ((void *)(&(a)))
495
496/*********************************************************************/
497
willy tarreau9e138862006-05-14 23:06:28 +0200498/* describes a chunk of string */
499struct chunk {
500 char *str; /* beginning of the string itself. Might not be 0-terminated */
501 int len; /* size of the string from first to last char. <0 = uninit. */
502};
503
willy tarreau4302f492005-12-18 01:00:37 +0100504struct cap_hdr {
505 struct cap_hdr *next;
506 char *name; /* header name, case insensitive */
507 int namelen; /* length of the header name, to speed-up lookups */
508 int len; /* capture length, not including terminal zero */
509 int index; /* index in the output array */
510 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
511};
512
willy tarreau0f7af912005-12-17 12:21:26 +0100513struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100514 struct hdr_exp *next;
515 regex_t *preg; /* expression to look for */
516 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
517 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100518};
519
520struct buffer {
521 unsigned int l; /* data length */
522 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100523 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100524 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100525 char data[BUFSIZE];
526};
527
willy tarreau18a957c2006-04-12 19:26:23 +0200528struct pendconn {
529 struct list list; /* chaining ... */
530 struct session *sess; /* the session waiting for a connection */
531 struct server *srv; /* the server we are waiting for */
532};
533
willy tarreau0f7af912005-12-17 12:21:26 +0100534struct server {
535 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100536 int state; /* server state (SRV_*) */
537 int cklen; /* the len of the cookie, to speed up checks */
538 char *cookie; /* the id set in the cookie */
539 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200540 struct list pendconns; /* pending connections */
541 int nbpend; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200542 struct task *queue_mgt; /* the task associated to the queue processing */
willy tarreau0f7af912005-12-17 12:21:26 +0100543 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100544 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100545 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100546 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100547 int rise, fall; /* time in iterations */
548 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100549 int result; /* 0 = connect OK, -1 = connect KO */
550 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200551 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200552 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaua647c702006-04-15 22:45:52 +0200553 int cur_sess; /* number of currently active sessions (including syn_sent) */
554 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200555 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreau535ae7a2005-12-17 12:58:00 +0100556 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100557};
558
willy tarreau5cbea6f2005-12-17 12:48:26 +0100559/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100560struct task {
561 struct task *next, *prev; /* chaining ... */
562 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100563 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100564 int state; /* task state : IDLE or RUNNING */
565 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100566 int (*process)(struct task *t); /* the function which processes the task */
567 void *context; /* the task's context */
568};
569
570/* WARNING: if new fields are added, they must be initialized in event_accept() */
571struct session {
572 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100573 /* application specific below */
574 struct timeval crexpire; /* expiration date for a client read */
575 struct timeval cwexpire; /* expiration date for a client write */
576 struct timeval srexpire; /* expiration date for a server read */
577 struct timeval swexpire; /* expiration date for a server write */
578 struct timeval cnexpire; /* expiration date for a connect */
579 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
580 struct proxy *proxy; /* the proxy this socket belongs to */
581 int cli_fd; /* the client side fd */
582 int srv_fd; /* the server side fd */
583 int cli_state; /* state of the client side */
584 int srv_state; /* state of the server side */
585 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100586 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100587 struct buffer *req; /* request buffer */
588 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100589 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100590 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100591 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200592 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100593 char **req_cap; /* array of captured request headers (may be NULL) */
594 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreau9e138862006-05-14 23:06:28 +0200595 struct chunk req_line; /* points to first line */
596 struct chunk auth_hdr; /* points to 'Authorization:' header */
willy tarreaua1598082005-12-17 13:08:06 +0100597 struct {
598 int logwait; /* log fields waiting to be collected : LW_* */
599 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
600 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200601 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100602 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
603 long t_data; /* delay before the first data byte from the server ... */
604 unsigned long t_close; /* total session duration */
willy tarreau5e69b162006-05-12 19:49:37 +0200605 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
606 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 +0100607 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100608 char *cli_cookie; /* cookie presented by the client, in capture mode */
609 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100610 int status; /* HTTP status from the server, negative if from proxy */
611 long long bytes; /* number of bytes transferred from the server */
612 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100613 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100614};
615
willy tarreaua41a8b42005-12-17 14:02:24 +0100616struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100617 int fd; /* the listen socket */
618 struct sockaddr_storage addr; /* the address we listen to */
619 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100620};
willy tarreauf32f5242006-05-02 22:54:52 +0200621
willy tarreau0f7af912005-12-17 12:21:26 +0100622struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100623 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100624 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 +0100625 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100626 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200627 struct server *srv; /* known servers */
628 int srv_act, srv_bck; /* # of running servers */
629 int tot_wact, tot_wbck; /* total weights of active and backup servers */
630 struct server **srv_map; /* the server map used to apply weights */
631 int srv_map_sz; /* the size of the effective server map */
632 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100633 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100634 int cookie_len; /* strlen(cookie_name), computed only once */
635 char *appsession_name; /* name of the cookie to look for */
636 int appsession_name_len; /* strlen(appsession_name), computed only once */
637 int appsession_len; /* length of the appsession cookie value to be used */
638 int appsession_timeout;
639 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100640 char *capture_name; /* beginning of the name of the cookie to capture */
641 int capture_namelen; /* length of the cookie name to match */
642 int capture_len; /* length of the string to be captured */
willy tarreau9e138862006-05-14 23:06:28 +0200643 struct uri_auth *uri_auth; /* if non-NULL, the (list of) per-URI authentications */
willy tarreau0f7af912005-12-17 12:21:26 +0100644 int clitimeout; /* client I/O timeout (in milliseconds) */
645 int srvtimeout; /* server I/O timeout (in milliseconds) */
646 int contimeout; /* connect timeout (in milliseconds) */
647 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200648 struct list pendconns; /* pending connections with no server assigned yet */
649 int nbpend; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200650 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreau0f7af912005-12-17 12:21:26 +0100651 int nbconn; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200652 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100653 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100654 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100655 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100656 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100657 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100658 struct proxy *next;
659 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100660 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100661 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100662 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100663 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100664 int nb_reqadd, nb_rspadd;
665 struct hdr_exp *req_exp; /* regular expressions for request headers */
666 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100667 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
668 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
669 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
670 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100671 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100672 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100673 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
674 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100675 struct {
676 char *msg400; /* message for error 400 */
677 int len400; /* message length for error 400 */
678 char *msg403; /* message for error 403 */
679 int len403; /* message length for error 403 */
680 char *msg408; /* message for error 408 */
681 int len408; /* message length for error 408 */
682 char *msg500; /* message for error 500 */
683 int len500; /* message length for error 500 */
684 char *msg502; /* message for error 502 */
685 int len502; /* message length for error 502 */
686 char *msg503; /* message for error 503 */
687 int len503; /* message length for error 503 */
688 char *msg504; /* message for error 504 */
689 int len504; /* message length for error 504 */
690 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100691};
692
693/* info about one given fd */
694struct fdtab {
695 int (*read)(int fd); /* read function */
696 int (*write)(int fd); /* write function */
697 struct task *owner; /* the session (or proxy) associated with this fd */
698 int state; /* the state of this fd */
699};
700
701/*********************************************************************/
702
willy tarreaub952e1d2005-12-18 01:31:20 +0100703int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100704int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100705char *cfg_cfgfile = NULL; /* configuration file */
706char *progname = NULL; /* program name */
707int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100708
709/* global options */
710static struct {
711 int uid;
712 int gid;
713 int nbproc;
714 int maxconn;
715 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100716 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100717 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100718 int mode;
719 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100720 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100721 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100722 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100723 struct sockaddr_in logsrv1, logsrv2;
724} global = {
725 logfac1 : -1,
726 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100727 loglev1 : 7, /* max syslog level : debug */
728 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100729 /* others NULL OK */
730};
731
willy tarreau0f7af912005-12-17 12:21:26 +0100732/*********************************************************************/
733
willy tarreau1c2ad212005-12-18 01:11:29 +0100734fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100735 *StaticWriteEvent;
736
willy tarreau64a3cc32005-12-18 01:13:11 +0100737int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100738
willy tarreau0f7af912005-12-17 12:21:26 +0100739void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200740 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100741 **pool_buffer = NULL,
742 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100743 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100744 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100745 **pool_capture = NULL,
746 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100747
748struct proxy *proxy = NULL; /* list of all existing proxies */
749struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100750struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200751struct task wait_queue[2] = { /* global wait queue */
752 {
753 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
754 next:LIST_HEAD(wait_queue[0]),
755 },
756 {
757 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
758 next:LIST_HEAD(wait_queue[1]),
759 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100760};
willy tarreau0f7af912005-12-17 12:21:26 +0100761
willy tarreau0f7af912005-12-17 12:21:26 +0100762static int totalconn = 0; /* total # of terminated sessions */
763static int actconn = 0; /* # of active sessions */
764static int maxfd = 0; /* # of the highest fd + 1 */
765static int listeners = 0; /* # of listeners */
766static int stopping = 0; /* non zero means stopping in progress */
767static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100768static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100769
willy tarreau53e99702006-03-25 18:53:50 +0100770/* Here we store informations about the pids of the processes we may pause
771 * or kill. We will send them a signal every 10 ms until we can bind to all
772 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100773 */
willy tarreau53e99702006-03-25 18:53:50 +0100774#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100775static int nb_oldpids = 0;
776static int *oldpids = NULL;
777static int oldpids_sig; /* use USR1 or TERM */
778
willy tarreau08dedbe2005-12-18 01:13:48 +0100779#if defined(ENABLE_EPOLL)
780/* FIXME: this is dirty, but at the moment, there's no other solution to remove
781 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
782 * structure with pointers to functions such as init_fd() and close_fd(), plus
783 * a private structure with several pointers to places such as below.
784 */
785
786static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
787#endif
788
willy tarreau0f7af912005-12-17 12:21:26 +0100789static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100790/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100791static char trash[BUFSIZE];
792
willy tarreaudd07e972005-12-18 00:48:48 +0100793const int zero = 0;
794const int one = 1;
795
willy tarreau0f7af912005-12-17 12:21:26 +0100796/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100797 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100798 */
799
800#define MAX_SYSLOG_LEN 1024
801#define NB_LOG_FACILITIES 24
802const char *log_facilities[NB_LOG_FACILITIES] = {
803 "kern", "user", "mail", "daemon",
804 "auth", "syslog", "lpr", "news",
805 "uucp", "cron", "auth2", "ftp",
806 "ntp", "audit", "alert", "cron2",
807 "local0", "local1", "local2", "local3",
808 "local4", "local5", "local6", "local7"
809};
810
811
812#define NB_LOG_LEVELS 8
813const char *log_levels[NB_LOG_LEVELS] = {
814 "emerg", "alert", "crit", "err",
815 "warning", "notice", "info", "debug"
816};
817
818#define SYSLOG_PORT 514
819
820const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
821 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100822
willy tarreaub1285d52005-12-18 01:20:14 +0100823const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau078c79a2006-05-13 12:23:58 +0200824const char sess_fin_state[8] = "-RCHDLQ7"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, unknown */
willy tarreau036e1ce2005-12-17 13:46:33 +0100825const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
826const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
827 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
828 unknown, Set-cookie Rewritten */
829
willy tarreau0f7af912005-12-17 12:21:26 +0100830#define MAX_HOSTNAME_LEN 32
831static char hostname[MAX_HOSTNAME_LEN] = "";
832
willy tarreau8337c6b2005-12-17 13:41:01 +0100833const char *HTTP_302 =
834 "HTTP/1.0 302 Found\r\n"
835 "Cache-Control: no-cache\r\n"
836 "Connection: close\r\n"
837 "Location: "; /* not terminated since it will be concatenated with the URL */
838
willy tarreauc1f47532005-12-18 01:08:26 +0100839/* same as 302 except that the browser MUST retry with the GET method */
840const char *HTTP_303 =
841 "HTTP/1.0 303 See Other\r\n"
842 "Cache-Control: no-cache\r\n"
843 "Connection: close\r\n"
844 "Location: "; /* not terminated since it will be concatenated with the URL */
845
willy tarreaua1598082005-12-17 13:08:06 +0100846const char *HTTP_400 =
847 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100848 "Cache-Control: no-cache\r\n"
849 "Connection: close\r\n"
850 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100851 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100852
willy tarreau9e138862006-05-14 23:06:28 +0200853/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
854const char *HTTP_401_fmt =
855 "HTTP/1.0 401 Unauthorized\r\n"
856 "Cache-Control: no-cache\r\n"
857 "Connection: close\r\n"
858 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
859 "\r\n"
860 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
861
willy tarreaua1598082005-12-17 13:08:06 +0100862const char *HTTP_403 =
863 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100864 "Cache-Control: no-cache\r\n"
865 "Connection: close\r\n"
866 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100867 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
868
willy tarreau8337c6b2005-12-17 13:41:01 +0100869const char *HTTP_408 =
870 "HTTP/1.0 408 Request Time-out\r\n"
871 "Cache-Control: no-cache\r\n"
872 "Connection: close\r\n"
873 "\r\n"
874 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
875
willy tarreau750a4722005-12-17 13:21:24 +0100876const char *HTTP_500 =
877 "HTTP/1.0 500 Server Error\r\n"
878 "Cache-Control: no-cache\r\n"
879 "Connection: close\r\n"
880 "\r\n"
881 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100882
883const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100884 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100885 "Cache-Control: no-cache\r\n"
886 "Connection: close\r\n"
887 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100888 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
889
890const char *HTTP_503 =
891 "HTTP/1.0 503 Service Unavailable\r\n"
892 "Cache-Control: no-cache\r\n"
893 "Connection: close\r\n"
894 "\r\n"
895 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
896
897const char *HTTP_504 =
898 "HTTP/1.0 504 Gateway Time-out\r\n"
899 "Cache-Control: no-cache\r\n"
900 "Connection: close\r\n"
901 "\r\n"
902 "<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 +0100903
willy tarreau0f7af912005-12-17 12:21:26 +0100904/*********************************************************************/
905/* statistics ******************************************************/
906/*********************************************************************/
907
willy tarreau750a4722005-12-17 13:21:24 +0100908#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100909static int stats_tsk_lsrch, stats_tsk_rsrch,
910 stats_tsk_good, stats_tsk_right, stats_tsk_left,
911 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100912#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100913
914
915/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100916/* debugging *******************************************************/
917/*********************************************************************/
918#ifdef DEBUG_FULL
919static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau3504a012006-05-14 23:20:07 +0200920static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100921#endif
922
923/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100924/* function prototypes *********************************************/
925/*********************************************************************/
926
927int event_accept(int fd);
928int event_cli_read(int fd);
929int event_cli_write(int fd);
930int event_srv_read(int fd);
931int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100932int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100933
willy tarreau12350152005-12-18 01:03:27 +0100934static int appsession_task_init(void);
935static int appsession_init(void);
936static int appsession_refresh(struct task *t);
937
willy tarreau0f7af912005-12-17 12:21:26 +0100938/*********************************************************************/
939/* general purpose functions ***************************************/
940/*********************************************************************/
941
942void display_version() {
943 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100944 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100945}
946
947/*
948 * This function prints the command line usage and exits
949 */
950void usage(char *name) {
951 display_version();
952 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100953 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100954#if STATTIME > 0
955 "sl"
956#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100957 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
958 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100959 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100960 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100961 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100962#if STATTIME > 0
963 " -s enables statistics output\n"
964 " -l enables long statistics format\n"
965#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100966 " -D goes daemon ; implies -q\n"
967 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100968 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100969 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100970 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100971 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100972 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100973#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100974 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100975#endif
976#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100977 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100978#endif
willy tarreau53e99702006-03-25 18:53:50 +0100979 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100980 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100981 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100982 exit(1);
983}
984
985
986/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100987 * Displays the message on stderr with the date and pid. Overrides the quiet
988 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100989 */
990void Alert(char *fmt, ...) {
991 va_list argp;
992 struct timeval tv;
993 struct tm *tm;
994
willy tarreaud0fb4652005-12-18 01:32:04 +0100995 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100996 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100997
willy tarreau5cbea6f2005-12-17 12:48:26 +0100998 gettimeofday(&tv, NULL);
999 tm=localtime(&tv.tv_sec);
1000 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001001 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001002 vfprintf(stderr, fmt, argp);
1003 fflush(stderr);
1004 va_end(argp);
1005 }
willy tarreau0f7af912005-12-17 12:21:26 +01001006}
1007
1008
1009/*
1010 * Displays the message on stderr with the date and pid.
1011 */
1012void Warning(char *fmt, ...) {
1013 va_list argp;
1014 struct timeval tv;
1015 struct tm *tm;
1016
willy tarreau982249e2005-12-18 00:57:06 +01001017 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001018 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +01001019
willy tarreau5cbea6f2005-12-17 12:48:26 +01001020 gettimeofday(&tv, NULL);
1021 tm=localtime(&tv.tv_sec);
1022 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001023 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001024 vfprintf(stderr, fmt, argp);
1025 fflush(stderr);
1026 va_end(argp);
1027 }
1028}
1029
1030/*
1031 * Displays the message on <out> only if quiet mode is not set.
1032 */
1033void qfprintf(FILE *out, char *fmt, ...) {
1034 va_list argp;
1035
willy tarreau982249e2005-12-18 00:57:06 +01001036 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001037 va_start(argp, fmt);
1038 vfprintf(out, fmt, argp);
1039 fflush(out);
1040 va_end(argp);
1041 }
willy tarreau0f7af912005-12-17 12:21:26 +01001042}
1043
1044
1045/*
1046 * converts <str> to a struct sockaddr_in* which is locally allocated.
1047 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1048 * INADDR_ANY.
1049 */
1050struct sockaddr_in *str2sa(char *str) {
1051 static struct sockaddr_in sa;
1052 char *c;
1053 int port;
1054
willy tarreaua1598082005-12-17 13:08:06 +01001055 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001056 str=strdup(str);
1057
1058 if ((c=strrchr(str,':')) != NULL) {
1059 *c++=0;
1060 port=atol(c);
1061 }
1062 else
1063 port=0;
1064
1065 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1066 sa.sin_addr.s_addr = INADDR_ANY;
1067 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001068 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001069 struct hostent *he;
1070
1071 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001072 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001073 }
1074 else
1075 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1076 }
1077 sa.sin_port=htons(port);
1078 sa.sin_family=AF_INET;
1079
1080 free(str);
1081 return &sa;
1082}
1083
willy tarreaub1285d52005-12-18 01:20:14 +01001084/*
1085 * converts <str> to a two struct in_addr* which are locally allocated.
1086 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1087 * is optionnal and either in the dotted or CIDR notation.
1088 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1089 */
1090int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1091 char *c;
1092 unsigned long len;
1093
1094 memset(mask, 0, sizeof(*mask));
1095 memset(addr, 0, sizeof(*addr));
1096 str=strdup(str);
1097
1098 if ((c = strrchr(str, '/')) != NULL) {
1099 *c++ = 0;
1100 /* c points to the mask */
1101 if (strchr(c, '.') != NULL) { /* dotted notation */
1102 if (!inet_pton(AF_INET, c, mask))
1103 return 0;
1104 }
1105 else { /* mask length */
1106 char *err;
1107 len = strtol(c, &err, 10);
1108 if (!*c || (err && *err) || (unsigned)len > 32)
1109 return 0;
1110 if (len)
1111 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1112 else
1113 mask->s_addr = 0;
1114 }
1115 }
1116 else {
1117 mask->s_addr = 0xFFFFFFFF;
1118 }
1119 if (!inet_pton(AF_INET, str, addr)) {
1120 struct hostent *he;
1121
1122 if ((he = gethostbyname(str)) == NULL) {
1123 return 0;
1124 }
1125 else
1126 *addr = *(struct in_addr *) *(he->h_addr_list);
1127 }
1128 free(str);
1129 return 1;
1130}
1131
willy tarreau9fe663a2005-12-17 13:02:59 +01001132
1133/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001134 * converts <str> to a list of listeners which are dynamically allocated.
1135 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1136 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1137 * - <port> is a numerical port from 1 to 65535 ;
1138 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1139 * This can be repeated as many times as necessary, separated by a coma.
1140 * The <tail> argument is a pointer to a current list which should be appended
1141 * to the tail of the new list. The pointer to the new list is returned.
1142 */
1143struct listener *str2listener(char *str, struct listener *tail) {
1144 struct listener *l;
1145 char *c, *next, *range, *dupstr;
1146 int port, end;
1147
1148 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001149
willy tarreaua41a8b42005-12-17 14:02:24 +01001150 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001151 struct sockaddr_storage ss;
1152
willy tarreaua41a8b42005-12-17 14:02:24 +01001153 str = next;
1154 /* 1) look for the end of the first address */
1155 if ((next = strrchr(str, ',')) != NULL) {
1156 *next++ = 0;
1157 }
1158
willy tarreau8a86dbf2005-12-18 00:45:59 +01001159 /* 2) look for the addr/port delimiter, it's the last colon. */
1160 if ((range = strrchr(str, ':')) == NULL) {
1161 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001162 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001163 }
1164
1165 *range++ = 0;
1166
1167 if (strrchr(str, ':') != NULL) {
1168 /* IPv6 address contains ':' */
1169 memset(&ss, 0, sizeof(ss));
1170 ss.ss_family = AF_INET6;
1171
1172 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1173 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001174 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001175 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001176 }
1177 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001178 memset(&ss, 0, sizeof(ss));
1179 ss.ss_family = AF_INET;
1180
1181 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1182 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1183 }
1184 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1185 struct hostent *he;
1186
1187 if ((he = gethostbyname(str)) == NULL) {
1188 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001189 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001190 }
1191 else
1192 ((struct sockaddr_in *)&ss)->sin_addr =
1193 *(struct in_addr *) *(he->h_addr_list);
1194 }
1195 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001196
1197 /* 3) look for the port-end delimiter */
1198 if ((c = strchr(range, '-')) != NULL) {
1199 *c++ = 0;
1200 end = atol(c);
1201 }
1202 else {
1203 end = atol(range);
1204 }
1205
willy tarreaud0fb4652005-12-18 01:32:04 +01001206 port = atol(range);
1207
1208 if (port < 1 || port > 65535) {
1209 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1210 goto fail;
1211 }
1212
1213 if (end < 1 || end > 65535) {
1214 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1215 goto fail;
1216 }
1217
1218 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001219 l = (struct listener *)calloc(1, sizeof(struct listener));
1220 l->next = tail;
1221 tail = l;
1222
willy tarreau41310e72006-03-25 18:17:56 +01001223 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001224 l->addr = ss;
1225 if (ss.ss_family == AF_INET6)
1226 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1227 else
1228 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1229
willy tarreaua41a8b42005-12-17 14:02:24 +01001230 } /* end for(port) */
1231 } /* end while(next) */
1232 free(dupstr);
1233 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001234 fail:
1235 free(dupstr);
1236 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001237}
1238
willy tarreau4302f492005-12-18 01:00:37 +01001239
1240#define FD_SETS_ARE_BITFIELDS
1241#ifdef FD_SETS_ARE_BITFIELDS
1242/*
1243 * This map is used with all the FD_* macros to check whether a particular bit
1244 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1245 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1246 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1247 * exclusively to the macros.
1248 */
1249fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1250fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1251
1252#else
1253#error "Check if your OS uses bitfields for fd_sets"
1254#endif
1255
1256/* will try to encode the string <string> replacing all characters tagged in
1257 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1258 * prefixed by <escape>, and will store the result between <start> (included
1259 *) and <stop> (excluded), and will always terminate the string with a '\0'
1260 * before <stop>. The position of the '\0' is returned if the conversion
1261 * completes. If bytes are missing between <start> and <stop>, then the
1262 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1263 * cannot even be stored so we return <start> without writing the 0.
1264 * The input string must also be zero-terminated.
1265 */
1266char hextab[16] = "0123456789ABCDEF";
1267char *encode_string(char *start, char *stop,
1268 const char escape, const fd_set *map,
1269 const char *string)
1270{
1271 if (start < stop) {
1272 stop--; /* reserve one byte for the final '\0' */
1273 while (start < stop && *string != 0) {
1274 if (!FD_ISSET((unsigned char)(*string), map))
1275 *start++ = *string;
1276 else {
1277 if (start + 3 >= stop)
1278 break;
1279 *start++ = escape;
1280 *start++ = hextab[(*string >> 4) & 15];
1281 *start++ = hextab[*string & 15];
1282 }
1283 string++;
1284 }
1285 *start = '\0';
1286 }
1287 return start;
1288}
willy tarreaua41a8b42005-12-17 14:02:24 +01001289
1290/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001291 * This function sends a syslog message to both log servers of a proxy,
1292 * or to global log servers if the proxy is NULL.
1293 * It also tries not to waste too much time computing the message header.
1294 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001295 */
1296void send_log(struct proxy *p, int level, char *message, ...) {
1297 static int logfd = -1; /* syslog UDP socket */
1298 static long tvsec = -1; /* to force the string to be initialized */
1299 struct timeval tv;
1300 va_list argp;
1301 static char logmsg[MAX_SYSLOG_LEN];
1302 static char *dataptr = NULL;
1303 int fac_level;
1304 int hdr_len, data_len;
1305 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001306 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001307 int nbloggers = 0;
1308 char *log_ptr;
1309
1310 if (logfd < 0) {
1311 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1312 return;
1313 }
1314
1315 if (level < 0 || progname == NULL || message == NULL)
1316 return;
1317
1318 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001319 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001320 /* this string is rebuild only once a second */
1321 struct tm *tm = localtime(&tv.tv_sec);
1322 tvsec = tv.tv_sec;
1323
willy tarreauc29948c2005-12-17 13:10:27 +01001324 hdr_len = snprintf(logmsg, sizeof(logmsg),
1325 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1326 monthname[tm->tm_mon],
1327 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1328 progname, pid);
1329 /* WARNING: depending upon implementations, snprintf may return
1330 * either -1 or the number of bytes that would be needed to store
1331 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001332 */
willy tarreauc29948c2005-12-17 13:10:27 +01001333 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1334 hdr_len = sizeof(logmsg);
1335
1336 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001337 }
1338
1339 va_start(argp, message);
1340 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001341 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1342 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001343 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001344 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001345
1346 if (p == NULL) {
1347 if (global.logfac1 >= 0) {
1348 sa[nbloggers] = &global.logsrv1;
1349 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001350 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001351 nbloggers++;
1352 }
1353 if (global.logfac2 >= 0) {
1354 sa[nbloggers] = &global.logsrv2;
1355 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001356 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001357 nbloggers++;
1358 }
1359 } else {
1360 if (p->logfac1 >= 0) {
1361 sa[nbloggers] = &p->logsrv1;
1362 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001363 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001364 nbloggers++;
1365 }
1366 if (p->logfac2 >= 0) {
1367 sa[nbloggers] = &p->logsrv2;
1368 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001369 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001370 nbloggers++;
1371 }
1372 }
1373
1374 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001375 /* we can filter the level of the messages that are sent to each logger */
1376 if (level > loglevel[nbloggers])
1377 continue;
1378
willy tarreauc29948c2005-12-17 13:10:27 +01001379 /* For each target, we may have a different facility.
1380 * We can also have a different log level for each message.
1381 * This induces variations in the message header length.
1382 * Since we don't want to recompute it each time, nor copy it every
1383 * time, we only change the facility in the pre-computed header,
1384 * and we change the pointer to the header accordingly.
1385 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001386 fac_level = (facilities[nbloggers] << 3) + level;
1387 log_ptr = logmsg + 3; /* last digit of the log level */
1388 do {
1389 *log_ptr = '0' + fac_level % 10;
1390 fac_level /= 10;
1391 log_ptr--;
1392 } while (fac_level && log_ptr > logmsg);
1393 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001394
willy tarreauc29948c2005-12-17 13:10:27 +01001395 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001396
1397#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001398 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001399 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1400#else
willy tarreauc29948c2005-12-17 13:10:27 +01001401 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001402 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1403#endif
1404 }
willy tarreau0f7af912005-12-17 12:21:26 +01001405}
1406
1407
1408/* sets <tv> to the current time */
1409static inline struct timeval *tv_now(struct timeval *tv) {
1410 if (tv)
1411 gettimeofday(tv, NULL);
1412 return tv;
1413}
1414
1415/*
1416 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1417 */
willy tarreaudab722b2006-05-04 19:23:38 +02001418static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001419 if (!tv || !from)
1420 return NULL;
1421 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1422 tv->tv_sec = from->tv_sec + (ms/1000);
1423 while (tv->tv_usec >= 1000000) {
1424 tv->tv_usec -= 1000000;
1425 tv->tv_sec++;
1426 }
1427 return tv;
1428}
1429
1430/*
1431 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001432 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001433 */
1434static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001435 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001436 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001437 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001438 return 1;
1439 else if (tv1->tv_usec < tv2->tv_usec)
1440 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001441 else if (tv1->tv_usec > tv2->tv_usec)
1442 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001443 else
1444 return 0;
1445}
1446
1447/*
1448 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001449 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001450 */
1451unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1452 int cmp;
1453 unsigned long ret;
1454
1455
willy tarreauef900ab2005-12-17 12:52:52 +01001456 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001457 if (!cmp)
1458 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001459 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001460 struct timeval *tmp = tv1;
1461 tv1 = tv2;
1462 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001463 }
willy tarreauef900ab2005-12-17 12:52:52 +01001464 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001465 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001466 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001467 else
willy tarreauef900ab2005-12-17 12:52:52 +01001468 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001469 return (unsigned long) ret;
1470}
1471
1472/*
willy tarreau750a4722005-12-17 13:21:24 +01001473 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001474 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001475 */
1476static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1477 unsigned long ret;
1478
willy tarreau6e682ce2005-12-17 13:26:49 +01001479 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1480 if (tv2->tv_usec > tv1->tv_usec)
1481 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001482 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001483 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001484 return (unsigned long) ret;
1485}
1486
1487/*
willy tarreau0f7af912005-12-17 12:21:26 +01001488 * 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 +01001489 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001490 */
willy tarreaudab722b2006-05-04 19:23:38 +02001491static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001492 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001493 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001494 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001495 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001496 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001497 else
1498 return 0;
1499 }
willy tarreau0f7af912005-12-17 12:21:26 +01001500 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001501 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001502 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001503 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001504 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001505 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001506 else
1507 return 0;
1508}
1509
1510/*
1511 * returns the remaining time between tv1=now and event=tv2
1512 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001513 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001514 */
1515static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1516 unsigned long ret;
1517
willy tarreau0f7af912005-12-17 12:21:26 +01001518 if (tv_cmp_ms(tv1, tv2) >= 0)
1519 return 0; /* event elapsed */
1520
willy tarreauef900ab2005-12-17 12:52:52 +01001521 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001522 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001523 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001524 else
willy tarreauef900ab2005-12-17 12:52:52 +01001525 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001526 return (unsigned long) ret;
1527}
1528
1529
1530/*
1531 * zeroes a struct timeval
1532 */
1533
1534static inline struct timeval *tv_eternity(struct timeval *tv) {
1535 tv->tv_sec = tv->tv_usec = 0;
1536 return tv;
1537}
1538
1539/*
1540 * returns 1 if tv is null, else 0
1541 */
1542static inline int tv_iseternity(struct timeval *tv) {
1543 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1544 return 1;
1545 else
1546 return 0;
1547}
1548
1549/*
1550 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1551 * considering that 0 is the eternity.
1552 */
willy tarreaudab722b2006-05-04 19:23:38 +02001553static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001554 if (tv_iseternity(tv1))
1555 if (tv_iseternity(tv2))
1556 return 0; /* same */
1557 else
1558 return 1; /* tv1 later than tv2 */
1559 else if (tv_iseternity(tv2))
1560 return -1; /* tv2 later than tv1 */
1561
1562 if (tv1->tv_sec > tv2->tv_sec)
1563 return 1;
1564 else if (tv1->tv_sec < tv2->tv_sec)
1565 return -1;
1566 else if (tv1->tv_usec > tv2->tv_usec)
1567 return 1;
1568 else if (tv1->tv_usec < tv2->tv_usec)
1569 return -1;
1570 else
1571 return 0;
1572}
1573
1574/*
1575 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1576 * considering that 0 is the eternity.
1577 */
willy tarreaudab722b2006-05-04 19:23:38 +02001578static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001579 if (tv_iseternity(tv1))
1580 if (tv_iseternity(tv2))
1581 return 0; /* same */
1582 else
1583 return 1; /* tv1 later than tv2 */
1584 else if (tv_iseternity(tv2))
1585 return -1; /* tv2 later than tv1 */
1586
willy tarreauefae1842005-12-17 12:51:03 +01001587 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001588 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001589 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001590 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001591 return -1;
1592 else
1593 return 0;
1594 }
1595 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001596 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001597 return 1;
1598 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001599 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001600 return -1;
1601 else
1602 return 0;
1603}
1604
1605/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001606 * returns the remaining time between tv1=now and event=tv2
1607 * if tv2 is passed, 0 is returned.
1608 * Returns TIME_ETERNITY if tv2 is eternity.
1609 */
willy tarreaudab722b2006-05-04 19:23:38 +02001610static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001611 unsigned long ret;
1612
1613 if (tv_iseternity(tv2))
1614 return TIME_ETERNITY;
1615
1616 if (tv_cmp_ms(tv1, tv2) >= 0)
1617 return 0; /* event elapsed */
1618
1619 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1620 if (tv2->tv_usec > tv1->tv_usec)
1621 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1622 else
1623 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1624 return (unsigned long) ret;
1625}
1626
1627/*
willy tarreau0f7af912005-12-17 12:21:26 +01001628 * returns the first event between tv1 and tv2 into tvmin.
1629 * a zero tv is ignored. tvmin is returned.
1630 */
1631static inline struct timeval *tv_min(struct timeval *tvmin,
1632 struct timeval *tv1, struct timeval *tv2) {
1633
1634 if (tv_cmp2(tv1, tv2) <= 0)
1635 *tvmin = *tv1;
1636 else
1637 *tvmin = *tv2;
1638
1639 return tvmin;
1640}
1641
1642
1643
1644/***********************************************************/
1645/* fd management ***************************************/
1646/***********************************************************/
1647
1648
1649
willy tarreau5cbea6f2005-12-17 12:48:26 +01001650/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1651 * The file descriptor is also closed.
1652 */
willy tarreaudab722b2006-05-04 19:23:38 +02001653static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001654 FD_CLR(fd, StaticReadEvent);
1655 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001656#if defined(ENABLE_EPOLL)
1657 if (PrevReadEvent) {
1658 FD_CLR(fd, PrevReadEvent);
1659 FD_CLR(fd, PrevWriteEvent);
1660 }
1661#endif
1662
willy tarreau5cbea6f2005-12-17 12:48:26 +01001663 close(fd);
1664 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001665
1666 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1667 maxfd--;
1668}
1669
1670/* recomputes the maxfd limit from the fd */
1671static inline void fd_insert(int fd) {
1672 if (fd+1 > maxfd)
1673 maxfd = fd+1;
1674}
1675
1676/*************************************************************/
1677/* task management ***************************************/
1678/*************************************************************/
1679
willy tarreau5cbea6f2005-12-17 12:48:26 +01001680/* puts the task <t> in run queue <q>, and returns <t> */
1681static inline struct task *task_wakeup(struct task **q, struct task *t) {
1682 if (t->state == TASK_RUNNING)
1683 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001684 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001685 t->rqnext = *q;
1686 t->state = TASK_RUNNING;
1687 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001688 }
1689}
1690
willy tarreau5cbea6f2005-12-17 12:48:26 +01001691/* removes the task <t> from the queue <q>
1692 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001693 * set the run queue to point to the next one, and return it
1694 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001695static inline struct task *task_sleep(struct task **q, struct task *t) {
1696 if (t->state == TASK_RUNNING) {
1697 *q = t->rqnext;
1698 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001699 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001701}
1702
1703/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001704 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001705 * from the run queue. A pointer to the task itself is returned.
1706 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001707static inline struct task *task_delete(struct task *t) {
1708 t->prev->next = t->next;
1709 t->next->prev = t->prev;
1710 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001711}
1712
1713/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001714 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001715 */
1716static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001717 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001718}
1719
willy tarreau5cbea6f2005-12-17 12:48:26 +01001720/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001721 * may be only moved or left where it was, depending on its timing requirements.
1722 * <task> is returned.
1723 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001724struct task *task_queue(struct task *task) {
1725 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001726 struct task *start_from;
1727
willy tarreau5e698ef2006-05-02 14:51:00 +02001728 /* This is a very dirty hack to queue non-expirable tasks in another queue
1729 * in order to avoid pulluting the tail of the standard queue. This will go
1730 * away with the new O(log(n)) scheduler anyway.
1731 */
1732 if (tv_iseternity(&task->expire)) {
1733 /* if the task was queued in the standard wait queue, we must dequeue it */
1734 if (task->prev) {
1735 if (task->wq == LIST_HEAD(wait_queue[1]))
1736 return task;
1737 else {
1738 task_delete(task);
1739 task->prev = NULL;
1740 }
1741 }
1742 list = task->wq = LIST_HEAD(wait_queue[1]);
1743 } else {
1744 /* if the task was queued in the eternity queue, we must dequeue it */
1745 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1746 task_delete(task);
1747 task->prev = NULL;
1748 list = task->wq = LIST_HEAD(wait_queue[0]);
1749 }
1750 }
1751
1752 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001753 if (task->prev == NULL) {
1754 // start_from = list;
1755 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001756#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001757 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001758#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001759 /* insert the unlinked <task> into the list, searching back from the last entry */
1760 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1761 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001762#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001763 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001764#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001765 }
1766
1767 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1768 // start_from = start_from->next;
1769 // stats_tsk_nsrch++;
1770 // }
1771 }
1772 else if (task->prev == list ||
1773 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1774 start_from = task->next;
1775 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001776#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001777 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001778#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001779 return task; /* it's already in the right place */
1780 }
1781
willy tarreau750a4722005-12-17 13:21:24 +01001782#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001783 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001784#endif
1785
1786 /* if the task is not at the right place, there's little chance that
1787 * it has only shifted a bit, and it will nearly always be queued
1788 * at the end of the list because of constant timeouts
1789 * (observed in real case).
1790 */
1791#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1792 start_from = list->prev; /* assume we'll queue to the end of the list */
1793 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1794 start_from = start_from->prev;
1795#if STATTIME > 0
1796 stats_tsk_lsrch++;
1797#endif
1798 }
1799#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001800 /* insert the unlinked <task> into the list, searching after position <start_from> */
1801 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1802 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001803#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001804 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001805#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001806 }
willy tarreau750a4722005-12-17 13:21:24 +01001807#endif /* WE_REALLY_... */
1808
willy tarreau0f7af912005-12-17 12:21:26 +01001809 /* we need to unlink it now */
1810 task_delete(task);
1811 }
1812 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001813#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001814 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001815#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001816#ifdef LEFT_TO_TOP /* not very good */
1817 start_from = list;
1818 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1819 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001820#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001821 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001822#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001823 }
1824#else
1825 start_from = task->prev->prev; /* valid because of the previous test above */
1826 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1827 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001828#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001829 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001830#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001831 }
1832#endif
1833 /* we need to unlink it now */
1834 task_delete(task);
1835 }
1836 task->prev = start_from;
1837 task->next = start_from->next;
1838 task->next->prev = task;
1839 start_from->next = task;
1840 return task;
1841}
1842
1843
1844/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001845/* pending connections queues **************************************/
1846/*********************************************************************/
1847
1848/*
willy tarreaudfece232006-05-02 00:19:57 +02001849 * Detaches pending connection <p>, decreases the pending count, and frees
1850 * the pending connection. The connection might have been queued to a specific
1851 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001852 */
willy tarreaudfece232006-05-02 00:19:57 +02001853static void pendconn_free(struct pendconn *p) {
1854 LIST_DEL(&p->list);
1855 p->sess->pend_pos = NULL;
1856 if (p->srv)
1857 p->srv->nbpend--;
1858 else
1859 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001860 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001861 pool_free(pendconn, p);
1862}
1863
1864/* Returns the first pending connection for server <s>, which may be NULL if
1865 * nothing is pending.
1866 */
1867static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001868 if (!s->nbpend)
1869 return NULL;
1870
1871 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1872}
1873
willy tarreaudfece232006-05-02 00:19:57 +02001874/* Returns the first pending connection for proxy <px>, which may be NULL if
1875 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001876 */
willy tarreaudfece232006-05-02 00:19:57 +02001877static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1878 if (!px->nbpend)
1879 return NULL;
1880
1881 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001882}
1883
willy tarreaubc2eda62006-05-04 15:16:23 +02001884/* Detaches the next pending connection from either a server or a proxy, and
1885 * returns its associated session. If no pending connection is found, NULL is
1886 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001887 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001888static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001889 struct pendconn *p;
1890 struct session *sess;
1891
willy tarreaubc2eda62006-05-04 15:16:23 +02001892 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001893 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001894 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001895 if (!p)
1896 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001897 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001898 }
willy tarreau18a957c2006-04-12 19:26:23 +02001899 sess = p->sess;
1900 pendconn_free(p);
1901 return sess;
1902}
1903
willy tarreaudfece232006-05-02 00:19:57 +02001904/* Adds the session <sess> to the pending connection list of server <sess>->srv
1905 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1906 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1907 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001908 */
willy tarreaudfece232006-05-02 00:19:57 +02001909static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001910 struct pendconn *p;
1911
1912 p = pool_alloc(pendconn);
1913 if (!p)
1914 return NULL;
1915
willy tarreau18a957c2006-04-12 19:26:23 +02001916 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001917 p->sess = sess;
1918 p->srv = sess->srv;
1919 if (sess->srv) {
1920 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001921 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001922 sess->srv->nbpend++;
1923 } else {
1924 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001925 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001926 sess->proxy->nbpend++;
1927 }
willy tarreauf32f5242006-05-02 22:54:52 +02001928 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001929 return p;
1930}
1931
willy tarreau59a6cc22006-05-12 01:29:08 +02001932/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1933 * and non-zero otherwise. Suited for and if/else usage.
1934 */
1935static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1936 return (s && (s->nbpend || p->nbpend) &&
1937 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1938}
1939
1940
1941
willy tarreau18a957c2006-04-12 19:26:23 +02001942/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001943/* more specific functions ***************************************/
1944/*********************************************************************/
1945
1946/* some prototypes */
1947static int maintain_proxies(void);
1948
willy tarreaub952e1d2005-12-18 01:31:20 +01001949/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001950 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1951 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001952static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001953#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001954 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1955#else
willy tarreaua1598082005-12-17 13:08:06 +01001956#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001957 return getsockname(fd, (struct sockaddr *)sa, salen);
1958#else
1959 return -1;
1960#endif
1961#endif
1962}
1963
1964/*
1965 * frees the context associated to a session. It must have been removed first.
1966 */
willy tarreaudfece232006-05-02 00:19:57 +02001967static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001968 if (s->pend_pos)
1969 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001970 if (s->req)
1971 pool_free(buffer, s->req);
1972 if (s->rep)
1973 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001974
1975 if (s->rsp_cap != NULL) {
1976 struct cap_hdr *h;
1977 for (h = s->proxy->rsp_cap; h; h = h->next) {
1978 if (s->rsp_cap[h->index] != NULL)
1979 pool_free_to(h->pool, s->rsp_cap[h->index]);
1980 }
1981 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1982 }
1983 if (s->req_cap != NULL) {
1984 struct cap_hdr *h;
1985 for (h = s->proxy->req_cap; h; h = h->next) {
1986 if (s->req_cap[h->index] != NULL)
1987 pool_free_to(h->pool, s->req_cap[h->index]);
1988 }
1989 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1990 }
1991
willy tarreaua1598082005-12-17 13:08:06 +01001992 if (s->logs.uri)
1993 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001994 if (s->logs.cli_cookie)
1995 pool_free(capture, s->logs.cli_cookie);
1996 if (s->logs.srv_cookie)
1997 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001998
willy tarreau5cbea6f2005-12-17 12:48:26 +01001999 pool_free(session, s);
2000}
2001
willy tarreau0f7af912005-12-17 12:21:26 +01002002
2003/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01002004 * This function recounts the number of usable active and backup servers for
2005 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002006 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01002007 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002008static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002009 struct server *srv;
2010
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002011 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002012 for (srv = px->srv; srv != NULL; srv = srv->next) {
2013 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002014 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002015 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002016 px->tot_wbck += srv->eweight + 1;
2017 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01002018 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002019 px->tot_wact += srv->eweight + 1;
2020 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002021 }
2022 }
2023}
2024
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002025/* This function recomputes the server map for proxy px. It
2026 * relies on px->tot_wact and px->tot_wbck, so it must be
2027 * called after recount_servers(). It also expects px->srv_map
2028 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002029 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002030static void recalc_server_map(struct proxy *px) {
2031 int o, tot, flag;
2032 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002033
willy tarreau4c8c2b52006-03-24 19:36:41 +01002034 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002035 flag = SRV_RUNNING;
2036 tot = px->tot_wact;
2037 } else if (px->srv_bck) {
2038 flag = SRV_RUNNING | SRV_BACKUP;
2039 if (px->options & PR_O_USE_ALL_BK)
2040 tot = px->tot_wbck;
2041 else
2042 tot = 1; /* the first server is enough */
2043 } else {
2044 px->srv_map_sz = 0;
2045 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002046 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002047
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002048 /* this algorithm gives priority to the first server, which means that
2049 * it will respect the declaration order for equivalent weights, and
2050 * that whatever the weights, the first server called will always be
2051 * the first declard. This is an important asumption for the backup
2052 * case, where we want the first server only.
2053 */
2054 for (cur = px->srv; cur; cur = cur->next)
2055 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002056
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002057 for (o = 0; o < tot; o++) {
2058 int max = 0;
2059 best = NULL;
2060 for (cur = px->srv; cur; cur = cur->next) {
2061 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2062 int v;
2063
2064 /* If we are forced to return only one server, we don't want to
2065 * go further, because we would return the wrong one due to
2066 * divide overflow.
2067 */
2068 if (tot == 1) {
2069 best = cur;
2070 break;
2071 }
2072
2073 cur->wscore += cur->eweight + 1;
2074 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2075 if (best == NULL || v > max) {
2076 max = v;
2077 best = cur;
2078 }
2079 }
2080 }
2081 px->srv_map[o] = best;
2082 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002083 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002084 px->srv_map_sz = tot;
2085}
Willy TARREAU3481c462006-03-01 22:37:57 +01002086
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002087/*
willy tarreau898db9d2006-04-12 20:29:08 +02002088 * This function tries to find a running server with free connection slots for
2089 * the proxy <px> following the round-robin method.
2090 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2091 * to point to the next server. If no valid server is found, NULL is returned.
2092 */
2093static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2094 int newidx;
2095 struct server *srv;
2096
2097 if (px->srv_map_sz == 0)
2098 return NULL;
2099
2100 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2101 px->srv_rr_idx = 0;
2102 newidx = px->srv_rr_idx;
2103
2104 do {
2105 srv = px->srv_map[newidx++];
2106 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2107 px->srv_rr_idx = newidx;
2108 return srv;
2109 }
2110 if (newidx == px->srv_map_sz)
2111 newidx = 0;
2112 } while (newidx != px->srv_rr_idx);
2113
2114 return NULL;
2115}
2116
2117
2118/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002119 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002120 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002121 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2122 * to point to the next server. If no valid server is found, NULL is returned.
2123 */
2124static inline struct server *get_server_rr(struct proxy *px) {
2125 if (px->srv_map_sz == 0)
2126 return NULL;
2127
2128 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2129 px->srv_rr_idx = 0;
2130 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002131}
2132
willy tarreau62084d42006-03-24 18:57:41 +01002133
2134/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002135 * This function tries to find a running server for the proxy <px> following
2136 * the source hash method. Depending on the number of active/backup servers,
2137 * it will either look for active servers, or for backup servers.
2138 * If any server is found, it will be returned. If no valid server is found,
2139 * NULL is returned.
2140 */
2141static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002142 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002143
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002144 if (px->srv_map_sz == 0)
2145 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002146
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002147 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002148 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002149 while ((l + sizeof (int)) <= len) {
2150 h ^= ntohl(*(unsigned int *)(&addr[l]));
2151 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002152 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002153 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002154 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002155 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002156}
2157
2158
2159/*
willy tarreaudfece232006-05-02 00:19:57 +02002160 * This function marks the session as 'assigned' in direct or dispatch modes,
2161 * or tries to assign one in balance mode, according to the algorithm. It does
2162 * nothing if the session had already been assigned a server.
2163 *
2164 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002165 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2166 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2167 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002168 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2169 *
2170 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2171 * not need to be called anymore. This usually means that s->srv can be trusted
2172 * in balance and direct modes. This flag is not cleared, so it's to the caller
2173 * to clear it if required (eg: redispatch).
2174 *
willy tarreau0f7af912005-12-17 12:21:26 +01002175 */
willy tarreau0f7af912005-12-17 12:21:26 +01002176
willy tarreaudfece232006-05-02 00:19:57 +02002177int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002178#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002179 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002180#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002181
willy tarreaudfece232006-05-02 00:19:57 +02002182 if (s->pend_pos)
2183 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002184
willy tarreaudfece232006-05-02 00:19:57 +02002185 if (!(s->flags & SN_ASSIGNED)) {
2186 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2187 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2188 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002189
willy tarreaudfece232006-05-02 00:19:57 +02002190 if (s->proxy->options & PR_O_BALANCE_RR) {
2191 s->srv = get_server_rr_with_conns(s->proxy);
2192 if (!s->srv)
2193 return SRV_STATUS_FULL;
2194 }
2195 else if (s->proxy->options & PR_O_BALANCE_SH) {
2196 int len;
2197
2198 if (s->cli_addr.ss_family == AF_INET)
2199 len = 4;
2200 else if (s->cli_addr.ss_family == AF_INET6)
2201 len = 16;
2202 else /* unknown IP family */
2203 return SRV_STATUS_INTERNAL;
2204
2205 s->srv = get_server_sh(s->proxy,
2206 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2207 len);
2208 }
2209 else /* unknown balancing algorithm */
2210 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002211 }
willy tarreaudfece232006-05-02 00:19:57 +02002212 s->flags |= SN_ASSIGNED;
2213 }
2214 return SRV_STATUS_OK;
2215}
willy tarreau1a3442d2006-03-24 21:03:20 +01002216
willy tarreaudfece232006-05-02 00:19:57 +02002217/*
2218 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2219 * The address is taken from the currently assigned server, or from the
2220 * dispatch or transparent address.
2221 *
2222 * It may return :
2223 * SRV_STATUS_OK if everything is OK.
2224 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2225 *
2226 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2227 * not cleared, so it's to the caller to clear it if required.
2228 *
2229 */
2230int assign_server_address(struct session *s) {
2231#ifdef DEBUG_FULL
2232 fprintf(stderr,"assign_server_address : s=%p\n",s);
2233#endif
2234
2235 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2236 /* A server is necessarily known for this session */
2237 if (!(s->flags & SN_ASSIGNED))
2238 return SRV_STATUS_INTERNAL;
2239
2240 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002241
willy tarreaudfece232006-05-02 00:19:57 +02002242 /* if this server remaps proxied ports, we'll use
2243 * the port the client connected to with an offset. */
2244 if (s->srv->state & SRV_MAPPORTS) {
2245 struct sockaddr_in sockname;
2246 socklen_t namelen = sizeof(sockname);
2247
2248 if (!(s->proxy->options & PR_O_TRANSP) ||
2249 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2250 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2251 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002252 }
willy tarreau0f7af912005-12-17 12:21:26 +01002253 }
willy tarreaua1598082005-12-17 13:08:06 +01002254 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002255 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002256 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002257 }
2258 else if (s->proxy->options & PR_O_TRANSP) {
2259 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002260 socklen_t salen = sizeof(s->srv_addr);
2261
willy tarreau5cbea6f2005-12-17 12:48:26 +01002262 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2263 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002264 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002265 }
2266 }
willy tarreau0f7af912005-12-17 12:21:26 +01002267
willy tarreaudfece232006-05-02 00:19:57 +02002268 s->flags |= SN_ADDR_SET;
2269 return SRV_STATUS_OK;
2270}
willy tarreaua41a8b42005-12-17 14:02:24 +01002271
willy tarreaudfece232006-05-02 00:19:57 +02002272/* This function assigns a server to session <s> if required, and can add the
2273 * connection to either the assigned server's queue or to the proxy's queue.
2274 *
2275 * Returns :
2276 *
2277 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002278 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002279 * SRV_STATUS_QUEUED if the connection has been queued.
2280 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2281 * connection could not be queued.
2282 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2283 *
2284 */
2285int assign_server_and_queue(struct session *s) {
2286 struct pendconn *p;
2287 int err;
2288
2289 if (s->pend_pos)
2290 return SRV_STATUS_INTERNAL;
2291
2292 if (s->flags & SN_ASSIGNED) {
2293 /* a server does not need to be assigned, perhaps because we're in
2294 * direct mode, or in dispatch or transparent modes where the server
2295 * is not needed.
2296 */
2297 if (s->srv &&
2298 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2299 p = pendconn_add(s);
2300 if (p)
2301 return SRV_STATUS_QUEUED;
2302 else
2303 return SRV_STATUS_FULL;
2304 }
2305 return SRV_STATUS_OK;
2306 }
2307
2308 /* a server needs to be assigned */
2309 err = assign_server(s);
2310 switch (err) {
2311 case SRV_STATUS_OK:
2312 /* in balance mode, we might have servers with connection limits */
2313 if (s->srv != NULL &&
2314 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2315 p = pendconn_add(s);
2316 if (p)
2317 return SRV_STATUS_QUEUED;
2318 else
2319 return SRV_STATUS_FULL;
2320 }
2321 return SRV_STATUS_OK;
2322
2323 case SRV_STATUS_FULL:
2324 /* queue this session into the proxy's queue */
2325 p = pendconn_add(s);
2326 if (p)
2327 return SRV_STATUS_QUEUED;
2328 else
2329 return SRV_STATUS_FULL;
2330
2331 case SRV_STATUS_NOSRV:
2332 case SRV_STATUS_INTERNAL:
2333 return err;
2334 default:
2335 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002336 }
willy tarreaudfece232006-05-02 00:19:57 +02002337}
2338
2339
2340/*
2341 * This function initiates a connection to the server assigned to this session
2342 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2343 * It can return one of :
2344 * - SN_ERR_NONE if everything's OK
2345 * - SN_ERR_SRVTO if there are no more servers
2346 * - SN_ERR_SRVCL if the connection was refused by the server
2347 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2348 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2349 * - SN_ERR_INTERNAL for any other purely internal errors
2350 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2351 */
2352int connect_server(struct session *s) {
2353 int fd, err;
2354
2355 if (!(s->flags & SN_ADDR_SET)) {
2356 err = assign_server_address(s);
2357 if (err != SRV_STATUS_OK)
2358 return SN_ERR_INTERNAL;
2359 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002360
willy tarreau0f7af912005-12-17 12:21:26 +01002361 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002362 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002363
2364 if (errno == ENFILE)
2365 send_log(s->proxy, LOG_EMERG,
2366 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2367 s->proxy->id, maxfd);
2368 else if (errno == EMFILE)
2369 send_log(s->proxy, LOG_EMERG,
2370 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2371 s->proxy->id, maxfd);
2372 else if (errno == ENOBUFS || errno == ENOMEM)
2373 send_log(s->proxy, LOG_EMERG,
2374 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2375 s->proxy->id, maxfd);
2376 /* this is a resource error */
2377 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002378 }
2379
willy tarreau9fe663a2005-12-17 13:02:59 +01002380 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002381 /* do not log anything there, it's a normal condition when this option
2382 * is used to serialize connections to a server !
2383 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002384 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2385 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002386 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002387 }
2388
willy tarreau0f7af912005-12-17 12:21:26 +01002389 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2390 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002391 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002392 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002393 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002394 }
2395
willy tarreaub952e1d2005-12-18 01:31:20 +01002396 if (s->proxy->options & PR_O_TCP_SRV_KA)
2397 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2398
willy tarreau0174f312005-12-18 01:02:42 +01002399 /* allow specific binding :
2400 * - server-specific at first
2401 * - proxy-specific next
2402 */
2403 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2404 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2405 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2406 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2407 s->proxy->id, s->srv->id);
2408 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002409 send_log(s->proxy, LOG_EMERG,
2410 "Cannot bind to source address before connect() for server %s/%s.\n",
2411 s->proxy->id, s->srv->id);
2412 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002413 }
2414 }
2415 else if (s->proxy->options & PR_O_BIND_SRC) {
2416 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2417 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2418 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2419 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002420 send_log(s->proxy, LOG_EMERG,
2421 "Cannot bind to source address before connect() for server %s/%s.\n",
2422 s->proxy->id, s->srv->id);
2423 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002424 }
willy tarreaua1598082005-12-17 13:08:06 +01002425 }
2426
willy tarreaub1285d52005-12-18 01:20:14 +01002427 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2428 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2429
2430 if (errno == EAGAIN || errno == EADDRINUSE) {
2431 char *msg;
2432 if (errno == EAGAIN) /* no free ports left, try again later */
2433 msg = "no free ports";
2434 else
2435 msg = "local address already in use";
2436
2437 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002438 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002439 send_log(s->proxy, LOG_EMERG,
2440 "Connect() failed for server %s/%s: %s.\n",
2441 s->proxy->id, s->srv->id, msg);
2442 return SN_ERR_RESOURCE;
2443 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002444 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002445 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002446 return SN_ERR_SRVTO;
2447 } else {
2448 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002449 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002450 close(fd);
2451 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002452 }
2453 }
2454
willy tarreau5cbea6f2005-12-17 12:48:26 +01002455 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002456 fdtab[fd].read = &event_srv_read;
2457 fdtab[fd].write = &event_srv_write;
2458 fdtab[fd].state = FD_STCONN; /* connection in progress */
2459
2460 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002461#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2462 if (PrevReadEvent) {
2463 assert(!(FD_ISSET(fd, PrevReadEvent)));
2464 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2465 }
2466#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002467
2468 fd_insert(fd);
willy tarreau926a3572006-05-01 15:26:35 +02002469 if (s->srv)
2470 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002471
2472 if (s->proxy->contimeout)
2473 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2474 else
2475 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002476 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002477}
2478
2479/*
2480 * this function is called on a read event from a client socket.
2481 * It returns 0.
2482 */
2483int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002484 struct task *t = fdtab[fd].owner;
2485 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002486 struct buffer *b = s->req;
2487 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002488
willy tarreau12350152005-12-18 01:03:27 +01002489#ifdef DEBUG_FULL
2490 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2491#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002492
willy tarreau0f7af912005-12-17 12:21:26 +01002493 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002494#ifdef FILL_BUFFERS
2495 while (1)
2496#else
2497 do
2498#endif
2499 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002500 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2501 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002502 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002503 }
2504 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002505 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002506 }
2507 else {
2508 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002509 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2510 * since it means that the rewrite protection has been removed. This
2511 * implies that the if statement can be removed.
2512 */
2513 if (max > b->rlim - b->data)
2514 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002515 }
2516
2517 if (max == 0) { /* not anymore room to store data */
2518 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002519 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002520 }
2521
willy tarreau3242e862005-12-17 12:27:53 +01002522#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002523 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002524 int skerr;
2525 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002526
willy tarreau5cbea6f2005-12-17 12:48:26 +01002527 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2528 if (skerr)
2529 ret = -1;
2530 else
2531 ret = recv(fd, b->r, max, 0);
2532 }
willy tarreau3242e862005-12-17 12:27:53 +01002533#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002534 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002535#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002536 if (ret > 0) {
2537 b->r += ret;
2538 b->l += ret;
2539 s->res_cr = RES_DATA;
2540
2541 if (b->r == b->data + BUFSIZE) {
2542 b->r = b->data; /* wrap around the buffer */
2543 }
willy tarreaua1598082005-12-17 13:08:06 +01002544
2545 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002546 /* we hope to read more data or to get a close on next round */
2547 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002548 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002549 else if (ret == 0) {
2550 s->res_cr = RES_NULL;
2551 break;
2552 }
2553 else if (errno == EAGAIN) {/* ignore EAGAIN */
2554 break;
2555 }
2556 else {
2557 s->res_cr = RES_ERROR;
2558 fdtab[fd].state = FD_STERROR;
2559 break;
2560 }
2561 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002562#ifndef FILL_BUFFERS
2563 while (0);
2564#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002565 }
2566 else {
2567 s->res_cr = RES_ERROR;
2568 fdtab[fd].state = FD_STERROR;
2569 }
2570
willy tarreau5cbea6f2005-12-17 12:48:26 +01002571 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002572 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002573 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2574 else
2575 tv_eternity(&s->crexpire);
2576
2577 task_wakeup(&rq, t);
2578 }
willy tarreau0f7af912005-12-17 12:21:26 +01002579
willy tarreau0f7af912005-12-17 12:21:26 +01002580 return 0;
2581}
2582
2583
2584/*
2585 * this function is called on a read event from a server socket.
2586 * It returns 0.
2587 */
2588int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002589 struct task *t = fdtab[fd].owner;
2590 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002591 struct buffer *b = s->rep;
2592 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002593
willy tarreau12350152005-12-18 01:03:27 +01002594#ifdef DEBUG_FULL
2595 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2596#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002597
willy tarreau0f7af912005-12-17 12:21:26 +01002598 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002599#ifdef FILL_BUFFERS
2600 while (1)
2601#else
2602 do
2603#endif
2604 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002605 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2606 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002607 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 }
2609 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002610 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002611 }
2612 else {
2613 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002614 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2615 * since it means that the rewrite protection has been removed. This
2616 * implies that the if statement can be removed.
2617 */
2618 if (max > b->rlim - b->data)
2619 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002620 }
2621
2622 if (max == 0) { /* not anymore room to store data */
2623 FD_CLR(fd, StaticReadEvent);
2624 break;
2625 }
2626
willy tarreau3242e862005-12-17 12:27:53 +01002627#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002628 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002629 int skerr;
2630 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631
willy tarreau5cbea6f2005-12-17 12:48:26 +01002632 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2633 if (skerr)
2634 ret = -1;
2635 else
2636 ret = recv(fd, b->r, max, 0);
2637 }
willy tarreau3242e862005-12-17 12:27:53 +01002638#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002639 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002640#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002641 if (ret > 0) {
2642 b->r += ret;
2643 b->l += ret;
2644 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002645
willy tarreau5cbea6f2005-12-17 12:48:26 +01002646 if (b->r == b->data + BUFSIZE) {
2647 b->r = b->data; /* wrap around the buffer */
2648 }
willy tarreaua1598082005-12-17 13:08:06 +01002649
2650 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002651 /* we hope to read more data or to get a close on next round */
2652 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002653 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002654 else if (ret == 0) {
2655 s->res_sr = RES_NULL;
2656 break;
2657 }
2658 else if (errno == EAGAIN) {/* ignore EAGAIN */
2659 break;
2660 }
2661 else {
2662 s->res_sr = RES_ERROR;
2663 fdtab[fd].state = FD_STERROR;
2664 break;
2665 }
2666 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002667#ifndef FILL_BUFFERS
2668 while (0);
2669#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002670 }
2671 else {
2672 s->res_sr = RES_ERROR;
2673 fdtab[fd].state = FD_STERROR;
2674 }
2675
willy tarreau5cbea6f2005-12-17 12:48:26 +01002676 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002677 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002678 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2679 else
2680 tv_eternity(&s->srexpire);
2681
2682 task_wakeup(&rq, t);
2683 }
willy tarreau0f7af912005-12-17 12:21:26 +01002684
willy tarreau0f7af912005-12-17 12:21:26 +01002685 return 0;
2686}
2687
2688/*
2689 * this function is called on a write event from a client socket.
2690 * It returns 0.
2691 */
2692int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002693 struct task *t = fdtab[fd].owner;
2694 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002695 struct buffer *b = s->rep;
2696 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002697
willy tarreau12350152005-12-18 01:03:27 +01002698#ifdef DEBUG_FULL
2699 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2700#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002701
2702 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002703 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002704 // max = BUFSIZE; BUG !!!!
2705 max = 0;
2706 }
2707 else if (b->r > b->w) {
2708 max = b->r - b->w;
2709 }
2710 else
2711 max = b->data + BUFSIZE - b->w;
2712
willy tarreau0f7af912005-12-17 12:21:26 +01002713 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002714 if (max == 0) {
2715 s->res_cw = RES_NULL;
2716 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002717 tv_eternity(&s->cwexpire);
2718 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002719 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002720 }
2721
willy tarreau3242e862005-12-17 12:27:53 +01002722#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002723 {
2724 int skerr;
2725 socklen_t lskerr = sizeof(skerr);
2726
2727 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2728 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002729 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002730 else
willy tarreau3242e862005-12-17 12:27:53 +01002731 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002732 }
willy tarreau3242e862005-12-17 12:27:53 +01002733#else
willy tarreau0f7af912005-12-17 12:21:26 +01002734 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002735#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002736
2737 if (ret > 0) {
2738 b->l -= ret;
2739 b->w += ret;
2740
2741 s->res_cw = RES_DATA;
2742
2743 if (b->w == b->data + BUFSIZE) {
2744 b->w = b->data; /* wrap around the buffer */
2745 }
2746 }
2747 else if (ret == 0) {
2748 /* nothing written, just make as if we were never called */
2749// s->res_cw = RES_NULL;
2750 return 0;
2751 }
2752 else if (errno == EAGAIN) /* ignore EAGAIN */
2753 return 0;
2754 else {
2755 s->res_cw = RES_ERROR;
2756 fdtab[fd].state = FD_STERROR;
2757 }
2758 }
2759 else {
2760 s->res_cw = RES_ERROR;
2761 fdtab[fd].state = FD_STERROR;
2762 }
2763
willy tarreaub1ff9db2005-12-17 13:51:03 +01002764 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002765 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002766 /* FIXME: to prevent the client from expiring read timeouts during writes,
2767 * we refresh it. A solution would be to merge read+write timeouts into a
2768 * unique one, although that needs some study particularly on full-duplex
2769 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002770 s->crexpire = s->cwexpire;
2771 }
willy tarreau0f7af912005-12-17 12:21:26 +01002772 else
2773 tv_eternity(&s->cwexpire);
2774
willy tarreau5cbea6f2005-12-17 12:48:26 +01002775 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002776 return 0;
2777}
2778
2779
2780/*
2781 * this function is called on a write event from a server socket.
2782 * It returns 0.
2783 */
2784int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002785 struct task *t = fdtab[fd].owner;
2786 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002787 struct buffer *b = s->req;
2788 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002789
willy tarreau12350152005-12-18 01:03:27 +01002790#ifdef DEBUG_FULL
2791 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2792#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002793
2794 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002795 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002796 // max = BUFSIZE; BUG !!!!
2797 max = 0;
2798 }
2799 else if (b->r > b->w) {
2800 max = b->r - b->w;
2801 }
2802 else
2803 max = b->data + BUFSIZE - b->w;
2804
willy tarreau0f7af912005-12-17 12:21:26 +01002805 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002806 if (max == 0) {
2807 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002808 if (s->srv_state == SV_STCONN) {
2809 int skerr;
2810 socklen_t lskerr = sizeof(skerr);
2811 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2812 if (skerr) {
2813 s->res_sw = RES_ERROR;
2814 fdtab[fd].state = FD_STERROR;
2815 task_wakeup(&rq, t);
2816 tv_eternity(&s->swexpire);
2817 FD_CLR(fd, StaticWriteEvent);
2818 return 0;
2819 }
2820 }
2821
willy tarreau0f7af912005-12-17 12:21:26 +01002822 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002823 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002824 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002825 tv_eternity(&s->swexpire);
2826 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002827 return 0;
2828 }
2829
willy tarreau3242e862005-12-17 12:27:53 +01002830#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002831 {
2832 int skerr;
2833 socklen_t lskerr = sizeof(skerr);
2834 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2835 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002836 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002837 else
willy tarreau3242e862005-12-17 12:27:53 +01002838 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002839 }
willy tarreau3242e862005-12-17 12:27:53 +01002840#else
willy tarreau0f7af912005-12-17 12:21:26 +01002841 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002842#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002843 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002844 if (ret > 0) {
2845 b->l -= ret;
2846 b->w += ret;
2847
2848 s->res_sw = RES_DATA;
2849
2850 if (b->w == b->data + BUFSIZE) {
2851 b->w = b->data; /* wrap around the buffer */
2852 }
2853 }
2854 else if (ret == 0) {
2855 /* nothing written, just make as if we were never called */
2856 // s->res_sw = RES_NULL;
2857 return 0;
2858 }
2859 else if (errno == EAGAIN) /* ignore EAGAIN */
2860 return 0;
2861 else {
2862 s->res_sw = RES_ERROR;
2863 fdtab[fd].state = FD_STERROR;
2864 }
2865 }
2866 else {
2867 s->res_sw = RES_ERROR;
2868 fdtab[fd].state = FD_STERROR;
2869 }
2870
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002871 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2872 * otherwise it could loop indefinitely !
2873 */
2874 if (s->srv_state != SV_STCONN) {
2875 if (s->proxy->srvtimeout) {
2876 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002877 /* FIXME: to prevent the server from expiring read timeouts during writes,
2878 * we refresh it. A solution would be to merge read+write+connect timeouts
2879 * into a unique one since we don't mind expiring on read or write, and none
2880 * of them is enabled while waiting for connect(), although that needs some
2881 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002882 s->srexpire = s->swexpire;
2883 }
2884 else
2885 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002886 }
willy tarreau0f7af912005-12-17 12:21:26 +01002887
willy tarreau5cbea6f2005-12-17 12:48:26 +01002888 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002889 return 0;
2890}
2891
2892
2893/*
willy tarreaue39cd132005-12-17 13:00:18 +01002894 * returns a message to the client ; the connection is shut down for read,
2895 * and the request is cleared so that no server connection can be initiated.
2896 * The client must be in a valid state for this (HEADER, DATA ...).
2897 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002898 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002899 */
2900void client_retnclose(struct session *s, int len, const char *msg) {
2901 FD_CLR(s->cli_fd, StaticReadEvent);
2902 FD_SET(s->cli_fd, StaticWriteEvent);
2903 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002904 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002905 shutdown(s->cli_fd, SHUT_RD);
2906 s->cli_state = CL_STSHUTR;
2907 strcpy(s->rep->data, msg);
2908 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002909 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002910 s->rep->r += len;
2911 s->req->l = 0;
2912}
2913
2914
2915/*
2916 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002917 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002918 */
2919void client_return(struct session *s, int len, const char *msg) {
2920 strcpy(s->rep->data, msg);
2921 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002922 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002923 s->rep->r += len;
2924 s->req->l = 0;
2925}
2926
willy tarreau9fe663a2005-12-17 13:02:59 +01002927/*
2928 * send a log for the session when we have enough info about it
2929 */
2930void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002931 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002932 struct proxy *p = s->proxy;
2933 int log;
2934 char *uri;
2935 char *pxid;
2936 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002937 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002938
2939 /* This is a first attempt at a better logging system.
2940 * For now, we rely on send_log() to provide the date, although it obviously
2941 * is the date of the log and not of the request, and most fields are not
2942 * computed.
2943 */
2944
willy tarreaua1598082005-12-17 13:08:06 +01002945 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002946
willy tarreau8a86dbf2005-12-18 00:45:59 +01002947 if (s->cli_addr.ss_family == AF_INET)
2948 inet_ntop(AF_INET,
2949 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2950 pn, sizeof(pn));
2951 else
2952 inet_ntop(AF_INET6,
2953 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2954 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002955
willy tarreauc1cae632005-12-17 14:12:23 +01002956 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002957 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002958 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002959
willy tarreauc1cae632005-12-17 14:12:23 +01002960 tm = localtime(&s->logs.tv_accept.tv_sec);
2961 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002962 char tmpline[MAX_SYSLOG_LEN], *h;
2963 int hdr;
2964
2965 h = tmpline;
2966 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2967 *(h++) = ' ';
2968 *(h++) = '{';
2969 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2970 if (hdr)
2971 *(h++) = '|';
2972 if (s->req_cap[hdr] != NULL)
2973 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2974 }
2975 *(h++) = '}';
2976 }
2977
2978 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2979 *(h++) = ' ';
2980 *(h++) = '{';
2981 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2982 if (hdr)
2983 *(h++) = '|';
2984 if (s->rsp_cap[hdr] != NULL)
2985 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2986 }
2987 *(h++) = '}';
2988 }
2989
2990 if (h < tmpline + sizeof(tmpline) - 4) {
2991 *(h++) = ' ';
2992 *(h++) = '"';
2993 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2994 *(h++) = '"';
2995 }
2996 *h = '\0';
2997
willy tarreau5e69b162006-05-12 19:49:37 +02002998 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 +01002999 pn,
3000 (s->cli_addr.ss_family == AF_INET) ?
3001 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3002 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01003003 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3004 tm->tm_hour, tm->tm_min, tm->tm_sec,
3005 pxid, srv,
3006 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02003007 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
3008 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01003009 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003010 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3011 s->logs.status,
3012 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01003013 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
3014 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01003015 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
3016 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
3017 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
3018 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02003019 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3020 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003021 }
3022 else {
willy tarreau5f15c552006-05-13 18:37:04 +02003023 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 +01003024 pn,
3025 (s->cli_addr.ss_family == AF_INET) ?
3026 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3027 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003028 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3029 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003030 pxid, srv,
willy tarreau5f15c552006-05-13 18:37:04 +02003031 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
3032 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003033 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3034 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003035 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003036 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003037 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3038 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003039 }
3040
3041 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003042}
3043
willy tarreaue39cd132005-12-17 13:00:18 +01003044
3045/*
willy tarreau0f7af912005-12-17 12:21:26 +01003046 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003047 * to an accept. It tries to accept as many connections as possible.
3048 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003049 */
3050int event_accept(int fd) {
3051 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003052 struct session *s;
3053 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003054 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003055 int max_accept;
3056
3057 if (global.nbproc > 1)
3058 max_accept = 8; /* let other processes catch some connections too */
3059 else
3060 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003061
willy tarreauc2becdc2006-03-19 19:36:48 +01003062 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003063 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003064 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003065
willy tarreaub1285d52005-12-18 01:20:14 +01003066 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3067 switch (errno) {
3068 case EAGAIN:
3069 case EINTR:
3070 case ECONNABORTED:
3071 return 0; /* nothing more to accept */
3072 case ENFILE:
3073 send_log(p, LOG_EMERG,
3074 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3075 p->id, maxfd);
3076 return 0;
3077 case EMFILE:
3078 send_log(p, LOG_EMERG,
3079 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3080 p->id, maxfd);
3081 return 0;
3082 case ENOBUFS:
3083 case ENOMEM:
3084 send_log(p, LOG_EMERG,
3085 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3086 p->id, maxfd);
3087 return 0;
3088 default:
3089 return 0;
3090 }
3091 }
willy tarreau0f7af912005-12-17 12:21:26 +01003092
willy tarreau5cbea6f2005-12-17 12:48:26 +01003093 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3094 Alert("out of memory in event_accept().\n");
3095 FD_CLR(fd, StaticReadEvent);
3096 p->state = PR_STIDLE;
3097 close(cfd);
3098 return 0;
3099 }
willy tarreau0f7af912005-12-17 12:21:26 +01003100
willy tarreaub1285d52005-12-18 01:20:14 +01003101 /* if this session comes from a known monitoring system, we want to ignore
3102 * it as soon as possible, which means closing it immediately for TCP.
3103 */
3104 s->flags = 0;
3105 if (addr.ss_family == AF_INET &&
3106 p->mon_mask.s_addr &&
3107 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3108 if (p->mode == PR_MODE_TCP) {
3109 close(cfd);
3110 pool_free(session, s);
3111 continue;
3112 }
3113 s->flags |= SN_MONITOR;
3114 }
3115
willy tarreau5cbea6f2005-12-17 12:48:26 +01003116 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3117 Alert("out of memory in event_accept().\n");
3118 FD_CLR(fd, StaticReadEvent);
3119 p->state = PR_STIDLE;
3120 close(cfd);
3121 pool_free(session, s);
3122 return 0;
3123 }
willy tarreau0f7af912005-12-17 12:21:26 +01003124
willy tarreau5cbea6f2005-12-17 12:48:26 +01003125 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003126 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3128 close(cfd);
3129 pool_free(task, t);
3130 pool_free(session, s);
3131 return 0;
3132 }
willy tarreau0f7af912005-12-17 12:21:26 +01003133
willy tarreau5cbea6f2005-12-17 12:48:26 +01003134 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3135 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3136 (char *) &one, sizeof(one)) == -1)) {
3137 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3138 close(cfd);
3139 pool_free(task, t);
3140 pool_free(session, s);
3141 return 0;
3142 }
willy tarreau0f7af912005-12-17 12:21:26 +01003143
willy tarreaub952e1d2005-12-18 01:31:20 +01003144 if (p->options & PR_O_TCP_CLI_KA)
3145 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3146
willy tarreau9fe663a2005-12-17 13:02:59 +01003147 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003148 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003149 t->state = TASK_IDLE;
3150 t->process = process_session;
3151 t->context = s;
3152
3153 s->task = t;
3154 s->proxy = p;
3155 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3156 s->srv_state = SV_STIDLE;
3157 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003158
willy tarreau9fe663a2005-12-17 13:02:59 +01003159 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3160 s->cli_fd = cfd;
3161 s->srv_fd = -1;
willy tarreau9e138862006-05-14 23:06:28 +02003162 s->req_line.len = -1;
3163 s->auth_hdr.len = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003164 s->srv = NULL;
Willy TARREAU1a71cc12006-05-14 09:10:03 +02003165 s->pend_pos = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003166 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003167
willy tarreaub1285d52005-12-18 01:20:14 +01003168 if (s->flags & SN_MONITOR)
3169 s->logs.logwait = 0;
3170 else
3171 s->logs.logwait = p->to_log;
3172
willy tarreaua1598082005-12-17 13:08:06 +01003173 s->logs.tv_accept = now;
3174 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003175 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003176 s->logs.t_connect = -1;
3177 s->logs.t_data = -1;
3178 s->logs.t_close = 0;
3179 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003180 s->logs.cli_cookie = NULL;
3181 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003182 s->logs.status = -1;
3183 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003184 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3185 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003186
willy tarreau2f6ba652005-12-17 13:57:42 +01003187 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003188 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003189
willy tarreau4302f492005-12-18 01:00:37 +01003190 if (p->nb_req_cap > 0) {
3191 if ((s->req_cap =
3192 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3193 == NULL) { /* no memory */
3194 close(cfd); /* nothing can be done for this fd without memory */
3195 pool_free(task, t);
3196 pool_free(session, s);
3197 return 0;
3198 }
3199 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3200 }
3201 else
3202 s->req_cap = NULL;
3203
3204 if (p->nb_rsp_cap > 0) {
3205 if ((s->rsp_cap =
3206 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3207 == NULL) { /* no memory */
3208 if (s->req_cap != NULL)
3209 pool_free_to(p->req_cap_pool, s->req_cap);
3210 close(cfd); /* nothing can be done for this fd without memory */
3211 pool_free(task, t);
3212 pool_free(session, s);
3213 return 0;
3214 }
3215 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3216 }
3217 else
3218 s->rsp_cap = NULL;
3219
willy tarreau5cbea6f2005-12-17 12:48:26 +01003220 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3221 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003222 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003223 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003224
willy tarreau8a86dbf2005-12-18 00:45:59 +01003225 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003226 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003227 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003228 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003229
willy tarreau9fe663a2005-12-17 13:02:59 +01003230 if (p->to_log) {
3231 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003232 if (s->logs.logwait & LW_CLIP)
3233 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003234 sess_log(s);
3235 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003236 else if (s->cli_addr.ss_family == AF_INET) {
3237 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3238 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3239 sn, sizeof(sn)) &&
3240 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3241 pn, sizeof(pn))) {
3242 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3243 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3244 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3245 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3246 }
3247 }
3248 else {
3249 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3250 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3251 sn, sizeof(sn)) &&
3252 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3253 pn, sizeof(pn))) {
3254 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3255 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3256 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3257 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3258 }
3259 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003260 }
willy tarreau0f7af912005-12-17 12:21:26 +01003261
willy tarreau982249e2005-12-18 00:57:06 +01003262 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003263 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003264 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003265 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003266 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003267 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003268 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003269 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003270
willy tarreau8a86dbf2005-12-18 00:45:59 +01003271 if (s->cli_addr.ss_family == AF_INET) {
3272 char pn[INET_ADDRSTRLEN];
3273 inet_ntop(AF_INET,
3274 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3275 pn, sizeof(pn));
3276
3277 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3278 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3279 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3280 }
3281 else {
3282 char pn[INET6_ADDRSTRLEN];
3283 inet_ntop(AF_INET6,
3284 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3285 pn, sizeof(pn));
3286
3287 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3288 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3289 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3290 }
3291
willy tarreauef900ab2005-12-17 12:52:52 +01003292 write(1, trash, len);
3293 }
willy tarreau0f7af912005-12-17 12:21:26 +01003294
willy tarreau5cbea6f2005-12-17 12:48:26 +01003295 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003296 if (s->rsp_cap != NULL)
3297 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3298 if (s->req_cap != NULL)
3299 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003300 close(cfd); /* nothing can be done for this fd without memory */
3301 pool_free(task, t);
3302 pool_free(session, s);
3303 return 0;
3304 }
willy tarreau4302f492005-12-18 01:00:37 +01003305
willy tarreau5cbea6f2005-12-17 12:48:26 +01003306 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003307 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003308 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3309 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003310 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003311 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003312
willy tarreau5cbea6f2005-12-17 12:48:26 +01003313 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3314 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003315 if (s->rsp_cap != NULL)
3316 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3317 if (s->req_cap != NULL)
3318 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003319 close(cfd); /* nothing can be done for this fd without memory */
3320 pool_free(task, t);
3321 pool_free(session, s);
3322 return 0;
3323 }
3324 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003325 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003326 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 +01003327
willy tarreau5cbea6f2005-12-17 12:48:26 +01003328 fdtab[cfd].read = &event_cli_read;
3329 fdtab[cfd].write = &event_cli_write;
3330 fdtab[cfd].owner = t;
3331 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003332
willy tarreaub1285d52005-12-18 01:20:14 +01003333 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3334 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3335 /* Either we got a request from a monitoring system on an HTTP instance,
3336 * or we're in health check mode with the 'httpchk' option enabled. In
3337 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3338 */
3339 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3340 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3341 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003342 }
3343 else {
3344 FD_SET(cfd, StaticReadEvent);
3345 }
3346
willy tarreaub952e1d2005-12-18 01:31:20 +01003347#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3348 if (PrevReadEvent) {
3349 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3350 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3351 }
3352#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003353 fd_insert(cfd);
3354
3355 tv_eternity(&s->cnexpire);
3356 tv_eternity(&s->srexpire);
3357 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003358 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003359 tv_eternity(&s->cwexpire);
3360
willy tarreaub1285d52005-12-18 01:20:14 +01003361 if (s->proxy->clitimeout) {
3362 if (FD_ISSET(cfd, StaticReadEvent))
3363 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3364 if (FD_ISSET(cfd, StaticWriteEvent))
3365 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3366 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003367
willy tarreaub1285d52005-12-18 01:20:14 +01003368 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003369
3370 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003371
3372 if (p->mode != PR_MODE_HEALTH)
3373 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003374
3375 p->nbconn++;
3376 actconn++;
3377 totalconn++;
3378
willy tarreaub952e1d2005-12-18 01:31:20 +01003379 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003380 } /* end of while (p->nbconn < p->maxconn) */
3381 return 0;
3382}
willy tarreau0f7af912005-12-17 12:21:26 +01003383
willy tarreau0f7af912005-12-17 12:21:26 +01003384
willy tarreau5cbea6f2005-12-17 12:48:26 +01003385/*
3386 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003387 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3388 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003389 * or -1 if an error occured.
3390 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003391int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003392 struct task *t = fdtab[fd].owner;
3393 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003394 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003395 socklen_t lskerr = sizeof(skerr);
3396
willy tarreau05be12b2006-03-19 19:35:00 +01003397 skerr = 1;
3398 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3399 || (skerr != 0)) {
3400 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003401 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003402 fdtab[fd].state = FD_STERROR;
3403 FD_CLR(fd, StaticWriteEvent);
3404 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003405 else if (s->result != -1) {
3406 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003407 if (s->proxy->options & PR_O_HTTP_CHK) {
3408 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003409 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003410 * so we'll send the request, and won't wake the checker up now.
3411 */
3412#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003413 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003414#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003415 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003416#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003417 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003418 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3419 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3420 return 0;
3421 }
willy tarreau05be12b2006-03-19 19:35:00 +01003422 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003423 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003424 FD_CLR(fd, StaticWriteEvent);
3425 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003426 }
3427 else {
3428 /* good TCP connection is enough */
3429 s->result = 1;
3430 }
3431 }
3432
3433 task_wakeup(&rq, t);
3434 return 0;
3435}
3436
willy tarreau0f7af912005-12-17 12:21:26 +01003437
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003438/*
3439 * This function is used only for server health-checks. It handles
3440 * the server's reply to an HTTP request. It returns 1 if the server replies
3441 * 2xx or 3xx (valid responses), or -1 in other cases.
3442 */
3443int event_srv_chk_r(int fd) {
3444 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003445 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003446 struct task *t = fdtab[fd].owner;
3447 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003448 int skerr;
3449 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003450
willy tarreaua4a583a2005-12-18 01:39:19 +01003451 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003452
willy tarreau05be12b2006-03-19 19:35:00 +01003453 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3454 if (!skerr) {
3455#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003456 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003457#else
willy tarreau05be12b2006-03-19 19:35:00 +01003458 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3459 * but the connection was closed on the remote end. Fortunately, recv still
3460 * works correctly and we don't need to do the getsockopt() on linux.
3461 */
3462 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003463#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003464
3465 if ((len >= sizeof("HTTP/1.0 000")) &&
3466 !memcmp(reply, "HTTP/1.", 7) &&
3467 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3468 result = 1;
3469 }
3470
3471 if (result == -1)
3472 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003473
3474 if (s->result != -1)
3475 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003476
3477 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003478 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003479 return 0;
3480}
3481
3482
3483/*
3484 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3485 * and moves <end> just after the end of <str>.
3486 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3487 * the shift value (positive or negative) is returned.
3488 * If there's no space left, the move is not done.
3489 *
3490 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003491int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003492 int delta;
3493 int len;
3494
3495 len = strlen(str);
3496 delta = len - (end - pos);
3497
3498 if (delta + b->r >= b->data + BUFSIZE)
3499 return 0; /* no space left */
3500
3501 /* first, protect the end of the buffer */
3502 memmove(end + delta, end, b->data + b->l - end);
3503
3504 /* now, copy str over pos */
3505 memcpy(pos, str,len);
3506
willy tarreau5cbea6f2005-12-17 12:48:26 +01003507 /* we only move data after the displaced zone */
3508 if (b->r > pos) b->r += delta;
3509 if (b->w > pos) b->w += delta;
3510 if (b->h > pos) b->h += delta;
3511 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003512 b->l += delta;
3513
3514 return delta;
3515}
3516
willy tarreau8337c6b2005-12-17 13:41:01 +01003517/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003518 * len is 0.
3519 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003520int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003521 int delta;
3522
3523 delta = len - (end - pos);
3524
3525 if (delta + b->r >= b->data + BUFSIZE)
3526 return 0; /* no space left */
3527
Willy TARREAUe78ae262006-01-08 01:24:12 +01003528 if (b->data + b->l < end)
3529 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3530 return 0;
3531
willy tarreau0f7af912005-12-17 12:21:26 +01003532 /* first, protect the end of the buffer */
3533 memmove(end + delta, end, b->data + b->l - end);
3534
3535 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003536 if (len)
3537 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003538
willy tarreau5cbea6f2005-12-17 12:48:26 +01003539 /* we only move data after the displaced zone */
3540 if (b->r > pos) b->r += delta;
3541 if (b->w > pos) b->w += delta;
3542 if (b->h > pos) b->h += delta;
3543 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003544 b->l += delta;
3545
3546 return delta;
3547}
3548
3549
3550int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3551 char *old_dst = dst;
3552
3553 while (*str) {
3554 if (*str == '\\') {
3555 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003556 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003557 int len, num;
3558
3559 num = *str - '0';
3560 str++;
3561
willy tarreau8a86dbf2005-12-18 00:45:59 +01003562 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003563 len = matches[num].rm_eo - matches[num].rm_so;
3564 memcpy(dst, src + matches[num].rm_so, len);
3565 dst += len;
3566 }
3567
3568 }
3569 else if (*str == 'x') {
3570 unsigned char hex1, hex2;
3571 str++;
3572
willy tarreauc1f47532005-12-18 01:08:26 +01003573 hex1 = toupper(*str++) - '0';
3574 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003575
3576 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3577 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3578 *dst++ = (hex1<<4) + hex2;
3579 }
3580 else
3581 *dst++ = *str++;
3582 }
3583 else
3584 *dst++ = *str++;
3585 }
3586 *dst = 0;
3587 return dst - old_dst;
3588}
3589
willy tarreauc1f47532005-12-18 01:08:26 +01003590static int ishex(char s)
3591{
3592 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3593}
3594
3595/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3596char *check_replace_string(char *str)
3597{
3598 char *err = NULL;
3599 while (*str) {
3600 if (*str == '\\') {
3601 err = str; /* in case of a backslash, we return the pointer to it */
3602 str++;
3603 if (!*str)
3604 return err;
3605 else if (isdigit((int)*str))
3606 err = NULL;
3607 else if (*str == 'x') {
3608 str++;
3609 if (!ishex(*str))
3610 return err;
3611 str++;
3612 if (!ishex(*str))
3613 return err;
3614 err = NULL;
3615 }
3616 else {
3617 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3618 err = NULL;
3619 }
3620 }
3621 str++;
3622 }
3623 return err;
3624}
3625
3626
willy tarreau9fe663a2005-12-17 13:02:59 +01003627
willy tarreau0f7af912005-12-17 12:21:26 +01003628/*
3629 * manages the client FSM and its socket. BTW, it also tries to handle the
3630 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3631 * 0 else.
3632 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003633int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003634 int s = t->srv_state;
3635 int c = t->cli_state;
3636 struct buffer *req = t->req;
3637 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003638 int method_checked = 0;
3639 appsess *asession_temp = NULL;
3640 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003641
willy tarreau750a4722005-12-17 13:21:24 +01003642#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003643 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3644 cli_stnames[c], srv_stnames[s],
3645 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3646 t->crexpire.tv_sec, t->crexpire.tv_usec,
3647 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003648#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003649 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3650 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3651 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3652 //);
3653 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003654 /* now parse the partial (or complete) headers */
3655 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3656 char *ptr;
3657 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003658 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003659
willy tarreau5cbea6f2005-12-17 12:48:26 +01003660 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003661
willy tarreau0f7af912005-12-17 12:21:26 +01003662 /* look for the end of the current header */
3663 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3664 ptr++;
3665
willy tarreau5cbea6f2005-12-17 12:48:26 +01003666 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003667 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003668
3669 /*
3670 * first, let's check that it's not a leading empty line, in
3671 * which case we'll ignore and remove it (according to RFC2616).
3672 */
3673 if (req->h == req->data) {
3674 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3675 if (ptr > req->r - 2) {
3676 /* this is a partial header, let's wait for more to come */
3677 req->lr = ptr;
3678 break;
3679 }
3680
3681 /* now we know that *ptr is either \r or \n,
3682 * and that there are at least 1 char after it.
3683 */
3684 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3685 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3686 else
3687 req->lr = ptr + 2; /* \r\n or \n\r */
3688 /* ignore empty leading lines */
3689 buffer_replace2(req, req->h, req->lr, NULL, 0);
3690 req->h = req->lr;
3691 continue;
3692 }
3693
willy tarreau5cbea6f2005-12-17 12:48:26 +01003694 /* we can only get here after an end of headers */
3695 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003696
willy tarreaue39cd132005-12-17 13:00:18 +01003697 if (t->flags & SN_CLDENY) {
3698 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003699 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003700 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003701 if (!(t->flags & SN_ERR_MASK))
3702 t->flags |= SN_ERR_PRXCOND;
3703 if (!(t->flags & SN_FINST_MASK))
3704 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003705 return 1;
3706 }
3707
willy tarreau9e138862006-05-14 23:06:28 +02003708 /* Right now, we know that we have processed the entire headers
3709 * and that unwanted requests have been filtered out. We can do
3710 * whatever we want.
3711 */
3712
3713 /* FIXME debugging code !!! */
3714 if (t->req_line.len >= 0) {
3715 write(2, t->req_line.str, t->req_line.len);
3716 }
3717
3718 if (t->proxy->uri_auth != NULL
3719 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
3720 if (!memcmp(t->req_line.str + 4,
3721 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
3722 && !memcmp(t->req_line.str, "GET ", 4)) {
3723 struct user_auth *user;
3724 int authenticated;
3725
3726 /* we are in front of a interceptable URI. Let's check
3727 * if there's an authentication and if it's valid.
3728 */
3729 user = t->proxy->uri_auth->users;
3730 if (!user) {
3731 /* no user auth required, it's OK */
3732 authenticated = 1;
3733 } else {
3734 authenticated = 0;
3735
3736 /* a user list is defined, we have to check.
3737 * skip 21 chars for "Authorization: Basic ".
3738 */
3739 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
3740 user = NULL;
3741
3742 while (user) {
3743 if ((t->auth_hdr.len == user->user_len + 21)
3744 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
3745 authenticated = 1;
3746 break;
3747 }
3748 user = user->next;
3749 write(2, t->auth_hdr.str, t->auth_hdr.len);
3750 }
3751 }
3752
3753 if (!authenticated) {
3754 int msglen;
3755
3756 /* no need to go further */
3757
3758 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
3759 t->logs.status = 401;
3760 client_retnclose(t, msglen, trash);
3761 if (!(t->flags & SN_ERR_MASK))
3762 t->flags |= SN_ERR_PRXCOND;
3763 if (!(t->flags & SN_FINST_MASK))
3764 t->flags |= SN_FINST_R;
3765 return 1;
3766 }
3767
3768 /* Hey, we have passed the authentication ! */
3769 }
3770 }
3771
3772
willy tarreau5cbea6f2005-12-17 12:48:26 +01003773 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003774 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3775 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003776 }
willy tarreau0f7af912005-12-17 12:21:26 +01003777
willy tarreau9fe663a2005-12-17 13:02:59 +01003778 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003779 if (t->cli_addr.ss_family == AF_INET) {
3780 unsigned char *pn;
3781 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3782 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3783 pn[0], pn[1], pn[2], pn[3]);
3784 buffer_replace2(req, req->h, req->h, trash, len);
3785 }
3786 else if (t->cli_addr.ss_family == AF_INET6) {
3787 char pn[INET6_ADDRSTRLEN];
3788 inet_ntop(AF_INET6,
3789 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3790 pn, sizeof(pn));
3791 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3792 buffer_replace2(req, req->h, req->h, trash, len);
3793 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003794 }
3795
willy tarreau25c4ea52005-12-18 00:49:49 +01003796 /* add a "connection: close" line if needed */
3797 if (t->proxy->options & PR_O_HTTP_CLOSE)
3798 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3799
willy tarreau982249e2005-12-18 00:57:06 +01003800 if (!memcmp(req->data, "POST ", 5)) {
3801 /* this is a POST request, which is not cacheable by default */
3802 t->flags |= SN_POST;
3803 }
willy tarreaucd878942005-12-17 13:27:43 +01003804
willy tarreau5cbea6f2005-12-17 12:48:26 +01003805 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003806 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003807
willy tarreau750a4722005-12-17 13:21:24 +01003808 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003809 /* FIXME: we'll set the client in a wait state while we try to
3810 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003811 * better to release the maximum of system buffers instead ?
3812 * The solution is to enable the FD but set its time-out to
3813 * eternity as long as the server-side does not enable data xfer.
3814 * CL_STDATA also has to take care of this, which is done below.
3815 */
willy tarreauef900ab2005-12-17 12:52:52 +01003816 //FD_CLR(t->cli_fd, StaticReadEvent);
3817 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003818
3819 /* FIXME: if we break here (as up to 1.1.23), having the client
3820 * shutdown its connection can lead to an abort further.
3821 * it's better to either return 1 or even jump directly to the
3822 * data state which will save one schedule.
3823 */
3824 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003825
3826 if (!t->proxy->clitimeout ||
3827 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3828 /* If the client has no timeout, or if the server is not ready yet,
3829 * and we know for sure that it can expire, then it's cleaner to
3830 * disable the timeout on the client side so that too low values
3831 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003832 *
3833 * FIXME-20050705: the server needs a way to re-enable this time-out
3834 * when it switches its state, otherwise a client can stay connected
3835 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003836 */
3837 tv_eternity(&t->crexpire);
3838
willy tarreau197e8ec2005-12-17 14:10:59 +01003839 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003840 }
willy tarreau0f7af912005-12-17 12:21:26 +01003841
Willy TARREAU13032e72006-03-12 17:31:45 +01003842 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3843 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003844 /* this is a partial header, let's wait for more to come */
3845 req->lr = ptr;
3846 break;
3847 }
willy tarreau0f7af912005-12-17 12:21:26 +01003848
willy tarreau5cbea6f2005-12-17 12:48:26 +01003849 /* now we know that *ptr is either \r or \n,
3850 * and that there are at least 1 char after it.
3851 */
3852 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3853 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3854 else
3855 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003856
willy tarreau5cbea6f2005-12-17 12:48:26 +01003857 /*
3858 * now we know that we have a full header ; we can do whatever
3859 * we want with these pointers :
3860 * req->h = beginning of header
3861 * ptr = end of header (first \r or \n)
3862 * req->lr = beginning of next line (next rep->h)
3863 * req->r = end of data (not used at this stage)
3864 */
willy tarreau0f7af912005-12-17 12:21:26 +01003865
willy tarreau12350152005-12-18 01:03:27 +01003866 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3867 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3868 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3869
3870 /* skip ; */
3871 request_line++;
3872
3873 /* look if we have a jsessionid */
3874
3875 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3876
3877 /* skip jsessionid= */
3878 request_line += t->proxy->appsession_name_len + 1;
3879
3880 /* First try if we allready have an appsession */
3881 asession_temp = &local_asession;
3882
3883 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3884 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3885 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3886 return 0;
3887 }
3888
3889 /* Copy the sessionid */
3890 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3891 asession_temp->sessid[t->proxy->appsession_len] = 0;
3892 asession_temp->serverid = NULL;
3893
3894 /* only do insert, if lookup fails */
3895 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3896 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3897 Alert("Not enough memory process_cli():asession:calloc().\n");
3898 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3899 return 0;
3900 }
3901 asession_temp->sessid = local_asession.sessid;
3902 asession_temp->serverid = local_asession.serverid;
3903 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003904 } /* end if (chtbl_lookup()) */
3905 else {
willy tarreau12350152005-12-18 01:03:27 +01003906 /*free wasted memory;*/
3907 pool_free_to(apools.sessid, local_asession.sessid);
3908 }
3909
3910 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3911 asession_temp->request_count++;
3912
3913#if defined(DEBUG_HASH)
3914 print_table(&(t->proxy->htbl_proxy));
3915#endif
3916
3917 if (asession_temp->serverid == NULL) {
3918 Alert("Found Application Session without matching server.\n");
3919 } else {
3920 struct server *srv = t->proxy->srv;
3921 while (srv) {
3922 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3923 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3924 /* we found the server and it's usable */
3925 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003926 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003927 t->srv = srv;
3928 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003929 } else {
willy tarreau12350152005-12-18 01:03:27 +01003930 t->flags &= ~SN_CK_MASK;
3931 t->flags |= SN_CK_DOWN;
3932 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003933 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003934 srv = srv->next;
3935 }/* end while(srv) */
3936 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003937 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003938 else {
3939 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3940 }
willy tarreau598da412005-12-18 01:07:29 +01003941 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003942 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003943 else{
3944 //printf("No Methode-Header with Session-String\n");
3945 }
3946
willy tarreau8337c6b2005-12-17 13:41:01 +01003947 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003948 /* we have a complete HTTP request that we must log */
3949 int urilen;
3950
willy tarreaua1598082005-12-17 13:08:06 +01003951 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003952 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003953 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003954 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003955 if (!(t->flags & SN_ERR_MASK))
3956 t->flags |= SN_ERR_PRXCOND;
3957 if (!(t->flags & SN_FINST_MASK))
3958 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003959 return 1;
3960 }
3961
3962 urilen = ptr - req->h;
3963 if (urilen >= REQURI_LEN)
3964 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003965 memcpy(t->logs.uri, req->h, urilen);
3966 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003967
willy tarreaua1598082005-12-17 13:08:06 +01003968 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003969 sess_log(t);
3970 }
willy tarreau4302f492005-12-18 01:00:37 +01003971 else if (t->logs.logwait & LW_REQHDR) {
3972 struct cap_hdr *h;
3973 int len;
3974 for (h = t->proxy->req_cap; h; h = h->next) {
3975 if ((h->namelen + 2 <= ptr - req->h) &&
3976 (req->h[h->namelen] == ':') &&
3977 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3978
3979 if (t->req_cap[h->index] == NULL)
3980 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3981
3982 len = ptr - (req->h + h->namelen + 2);
3983 if (len > h->len)
3984 len = h->len;
3985
3986 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3987 t->req_cap[h->index][len]=0;
3988 }
3989 }
3990
3991 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003992
willy tarreau5cbea6f2005-12-17 12:48:26 +01003993 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003994
willy tarreau982249e2005-12-18 00:57:06 +01003995 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003996 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003997 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 +01003998 max = ptr - req->h;
3999 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004000 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004001 trash[len++] = '\n';
4002 write(1, trash, len);
4003 }
willy tarreau0f7af912005-12-17 12:21:26 +01004004
willy tarreau25c4ea52005-12-18 00:49:49 +01004005
4006 /* remove "connection: " if needed */
4007 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4008 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
4009 delete_header = 1;
4010 }
4011
willy tarreau5cbea6f2005-12-17 12:48:26 +01004012 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004013 if (!delete_header && t->proxy->req_exp != NULL
4014 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004015 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004016 char term;
4017
4018 term = *ptr;
4019 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004020 exp = t->proxy->req_exp;
4021 do {
4022 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
4023 switch (exp->action) {
4024 case ACT_ALLOW:
4025 if (!(t->flags & SN_CLDENY))
4026 t->flags |= SN_CLALLOW;
4027 break;
4028 case ACT_REPLACE:
4029 if (!(t->flags & SN_CLDENY)) {
4030 int len = exp_replace(trash, req->h, exp->replace, pmatch);
4031 ptr += buffer_replace2(req, req->h, ptr, trash, len);
4032 }
4033 break;
4034 case ACT_REMOVE:
4035 if (!(t->flags & SN_CLDENY))
4036 delete_header = 1;
4037 break;
4038 case ACT_DENY:
4039 if (!(t->flags & SN_CLALLOW))
4040 t->flags |= SN_CLDENY;
4041 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004042 case ACT_PASS: /* we simply don't deny this one */
4043 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004044 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004045 break;
willy tarreau0f7af912005-12-17 12:21:26 +01004046 }
willy tarreaue39cd132005-12-17 13:00:18 +01004047 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004048 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01004049 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004050
willy tarreau240afa62005-12-17 13:14:35 +01004051 /* Now look for cookies. Conforming to RFC2109, we have to support
4052 * attributes whose name begin with a '$', and associate them with
4053 * the right cookie, if we want to delete this cookie.
4054 * So there are 3 cases for each cookie read :
4055 * 1) it's a special attribute, beginning with a '$' : ignore it.
4056 * 2) it's a server id cookie that we *MAY* want to delete : save
4057 * some pointers on it (last semi-colon, beginning of cookie...)
4058 * 3) it's an application cookie : we *MAY* have to delete a previous
4059 * "special" cookie.
4060 * At the end of loop, if a "special" cookie remains, we may have to
4061 * remove it. If no application cookie persists in the header, we
4062 * *MUST* delete it
4063 */
willy tarreau12350152005-12-18 01:03:27 +01004064 if (!delete_header &&
4065 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01004066 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01004067 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004068 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01004069 char *del_colon, *del_cookie, *colon;
4070 int app_cookies;
4071
willy tarreau5cbea6f2005-12-17 12:48:26 +01004072 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01004073 colon = p1;
4074 /* del_cookie == NULL => nothing to be deleted */
4075 del_colon = del_cookie = NULL;
4076 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004077
4078 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01004079 /* skip spaces and colons, but keep an eye on these ones */
4080 while (p1 < ptr) {
4081 if (*p1 == ';' || *p1 == ',')
4082 colon = p1;
4083 else if (!isspace((int)*p1))
4084 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004085 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01004086 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004087
4088 if (p1 == ptr)
4089 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004090
4091 /* p1 is at the beginning of the cookie name */
4092 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004093 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004094 p2++;
4095
4096 if (p2 == ptr)
4097 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004098
4099 p3 = p2 + 1; /* skips the '=' sign */
4100 if (p3 == ptr)
4101 break;
4102
willy tarreau240afa62005-12-17 13:14:35 +01004103 p4 = p3;
4104 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004105 p4++;
4106
4107 /* here, we have the cookie name between p1 and p2,
4108 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004109 * we can process it :
4110 *
4111 * Cookie: NAME=VALUE;
4112 * | || || |
4113 * | || || +--> p4
4114 * | || |+-------> p3
4115 * | || +--------> p2
4116 * | |+------------> p1
4117 * | +-------------> colon
4118 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004119 */
4120
willy tarreau240afa62005-12-17 13:14:35 +01004121 if (*p1 == '$') {
4122 /* skip this one */
4123 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004124 else {
4125 /* first, let's see if we want to capture it */
4126 if (t->proxy->capture_name != NULL &&
4127 t->logs.cli_cookie == NULL &&
4128 (p4 - p1 >= t->proxy->capture_namelen) &&
4129 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4130 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004131
willy tarreau8337c6b2005-12-17 13:41:01 +01004132 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4133 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004134 } else {
4135 if (log_len > t->proxy->capture_len)
4136 log_len = t->proxy->capture_len;
4137 memcpy(t->logs.cli_cookie, p1, log_len);
4138 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004139 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004140 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004141
4142 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4143 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4144 /* Cool... it's the right one */
4145 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004146 char *delim;
4147
4148 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4149 * have the server ID betweek p3 and delim, and the original cookie between
4150 * delim+1 and p4. Otherwise, delim==p4 :
4151 *
4152 * Cookie: NAME=SRV~VALUE;
4153 * | || || | |
4154 * | || || | +--> p4
4155 * | || || +--------> delim
4156 * | || |+-----------> p3
4157 * | || +------------> p2
4158 * | |+----------------> p1
4159 * | +-----------------> colon
4160 * +------------------------> req->h
4161 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004162
willy tarreau0174f312005-12-18 01:02:42 +01004163 if (t->proxy->options & PR_O_COOK_PFX) {
4164 for (delim = p3; delim < p4; delim++)
4165 if (*delim == COOKIE_DELIM)
4166 break;
4167 }
4168 else
4169 delim = p4;
4170
4171
4172 /* Here, we'll look for the first running server which supports the cookie.
4173 * This allows to share a same cookie between several servers, for example
4174 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004175 * However, to prevent clients from sticking to cookie-less backup server
4176 * when they have incidentely learned an empty cookie, we simply ignore
4177 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004178 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004179 if (delim == p3)
4180 srv = NULL;
4181
willy tarreau0174f312005-12-18 01:02:42 +01004182 while (srv) {
4183 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4184 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4185 /* we found the server and it's usable */
4186 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004187 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004188 t->srv = srv;
4189 break;
willy tarreau12350152005-12-18 01:03:27 +01004190 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004191 /* we found a server, but it's down */
4192 t->flags &= ~SN_CK_MASK;
4193 t->flags |= SN_CK_DOWN;
4194 }
4195 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004196 srv = srv->next;
4197 }
4198
willy tarreau0174f312005-12-18 01:02:42 +01004199 if (!srv && !(t->flags & SN_CK_DOWN)) {
4200 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004201 t->flags &= ~SN_CK_MASK;
4202 t->flags |= SN_CK_INVALID;
4203 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004204
willy tarreau0174f312005-12-18 01:02:42 +01004205 /* depending on the cookie mode, we may have to either :
4206 * - delete the complete cookie if we're in insert+indirect mode, so that
4207 * the server never sees it ;
4208 * - remove the server id from the cookie value, and tag the cookie as an
4209 * application cookie so that it does not get accidentely removed later,
4210 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004211 */
willy tarreau0174f312005-12-18 01:02:42 +01004212 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4213 buffer_replace2(req, p3, delim + 1, NULL, 0);
4214 p4 -= (delim + 1 - p3);
4215 ptr -= (delim + 1 - p3);
4216 del_cookie = del_colon = NULL;
4217 app_cookies++; /* protect the header from deletion */
4218 }
4219 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004220 (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 +01004221 del_cookie = p1;
4222 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004223 }
willy tarreau12350152005-12-18 01:03:27 +01004224 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004225 /* now we know that we must keep this cookie since it's
4226 * not ours. But if we wanted to delete our cookie
4227 * earlier, we cannot remove the complete header, but we
4228 * can remove the previous block itself.
4229 */
4230 app_cookies++;
4231
4232 if (del_cookie != NULL) {
4233 buffer_replace2(req, del_cookie, p1, NULL, 0);
4234 p4 -= (p1 - del_cookie);
4235 ptr -= (p1 - del_cookie);
4236 del_cookie = del_colon = NULL;
4237 }
willy tarreau240afa62005-12-17 13:14:35 +01004238 }
willy tarreau12350152005-12-18 01:03:27 +01004239
4240 if ((t->proxy->appsession_name != NULL) &&
4241 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4242 /* first, let's see if the cookie is our appcookie*/
4243
4244 /* Cool... it's the right one */
4245
4246 asession_temp = &local_asession;
4247
4248 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4249 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4250 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4251 return 0;
4252 }
4253
4254 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4255 asession_temp->sessid[t->proxy->appsession_len] = 0;
4256 asession_temp->serverid = NULL;
4257
4258 /* only do insert, if lookup fails */
4259 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4260 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4261 Alert("Not enough memory process_cli():asession:calloc().\n");
4262 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4263 return 0;
4264 }
4265
4266 asession_temp->sessid = local_asession.sessid;
4267 asession_temp->serverid = local_asession.serverid;
4268 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4269 }
4270 else{
4271 /* free wasted memory */
4272 pool_free_to(apools.sessid, local_asession.sessid);
4273 }
4274
4275 if (asession_temp->serverid == NULL) {
4276 Alert("Found Application Session without matching server.\n");
4277 } else {
4278 struct server *srv = t->proxy->srv;
4279 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004280 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004281 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4282 /* we found the server and it's usable */
4283 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004284 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004285 t->srv = srv;
4286 break;
4287 } else {
4288 t->flags &= ~SN_CK_MASK;
4289 t->flags |= SN_CK_DOWN;
4290 }
4291 }
4292 srv = srv->next;
4293 }/* end while(srv) */
4294 }/* end else if server == NULL */
4295
4296 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004297 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004298 }
willy tarreau240afa62005-12-17 13:14:35 +01004299
willy tarreau5cbea6f2005-12-17 12:48:26 +01004300 /* we'll have to look for another cookie ... */
4301 p1 = p4;
4302 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004303
4304 /* There's no more cookie on this line.
4305 * We may have marked the last one(s) for deletion.
4306 * We must do this now in two ways :
4307 * - if there is no app cookie, we simply delete the header ;
4308 * - if there are app cookies, we must delete the end of the
4309 * string properly, including the colon/semi-colon before
4310 * the cookie name.
4311 */
4312 if (del_cookie != NULL) {
4313 if (app_cookies) {
4314 buffer_replace2(req, del_colon, ptr, NULL, 0);
4315 /* WARNING! <ptr> becomes invalid for now. If some code
4316 * below needs to rely on it before the end of the global
4317 * header loop, we need to correct it with this code :
willy tarreau240afa62005-12-17 13:14:35 +01004318 */
willy tarreau9e138862006-05-14 23:06:28 +02004319 ptr = del_colon;
willy tarreau240afa62005-12-17 13:14:35 +01004320 }
4321 else
4322 delete_header = 1;
4323 }
4324 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004325
4326 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004327 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004328 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau9e138862006-05-14 23:06:28 +02004329 /* WARNING: ptr is not valid anymore, since the header may have
4330 * been deleted or truncated ! */
4331 } else {
4332 /* try to catch the first line as the request */
4333 if (t->req_line.len < 0) {
4334 t->req_line.str = req->h;
4335 t->req_line.len = ptr - req->h;
4336 }
4337
4338 /* We might also need the 'Authorization: ' header */
4339 if (t->auth_hdr.len < 0 &&
4340 t->proxy->uri_auth != NULL &&
4341 ptr > req->h + 15 &&
4342 !strncasecmp("Authorization: ", req->h, 15)) {
4343 t->auth_hdr.str = req->h;
4344 t->auth_hdr.len = ptr - req->h;
4345 }
willy tarreau0f7af912005-12-17 12:21:26 +01004346 }
willy tarreau240afa62005-12-17 13:14:35 +01004347
willy tarreau5cbea6f2005-12-17 12:48:26 +01004348 req->h = req->lr;
4349 } /* while (req->lr < req->r) */
4350
4351 /* end of header processing (even if incomplete) */
4352
willy tarreauef900ab2005-12-17 12:52:52 +01004353 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4354 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4355 * full. We cannot loop here since event_cli_read will disable it only if
4356 * req->l == rlim-data
4357 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004358 FD_SET(t->cli_fd, StaticReadEvent);
4359 if (t->proxy->clitimeout)
4360 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4361 else
4362 tv_eternity(&t->crexpire);
4363 }
4364
willy tarreaue39cd132005-12-17 13:00:18 +01004365 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004366 * won't be able to free more later, so the session will never terminate.
4367 */
willy tarreaue39cd132005-12-17 13:00:18 +01004368 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004369 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004370 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004371 if (!(t->flags & SN_ERR_MASK))
4372 t->flags |= SN_ERR_PRXCOND;
4373 if (!(t->flags & SN_FINST_MASK))
4374 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004375 return 1;
4376 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004377 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004378 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004379 tv_eternity(&t->crexpire);
4380 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004381 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004382 if (!(t->flags & SN_ERR_MASK))
4383 t->flags |= SN_ERR_CLICL;
4384 if (!(t->flags & SN_FINST_MASK))
4385 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004386 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004387 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004388 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4389
4390 /* read timeout : give up with an error message.
4391 */
4392 t->logs.status = 408;
4393 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004394 if (!(t->flags & SN_ERR_MASK))
4395 t->flags |= SN_ERR_CLITO;
4396 if (!(t->flags & SN_FINST_MASK))
4397 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004398 return 1;
4399 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004400
4401 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004402 }
4403 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004404 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004405 /* FIXME: this error handling is partly buggy because we always report
4406 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4407 * or HEADER phase. BTW, it's not logical to expire the client while
4408 * we're waiting for the server to connect.
4409 */
willy tarreau0f7af912005-12-17 12:21:26 +01004410 /* read or write error */
4411 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004412 tv_eternity(&t->crexpire);
4413 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004414 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004415 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004416 if (!(t->flags & SN_ERR_MASK))
4417 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004418 if (!(t->flags & SN_FINST_MASK)) {
4419 if (t->pend_pos)
4420 t->flags |= SN_FINST_Q;
4421 else if (s == SV_STCONN)
4422 t->flags |= SN_FINST_C;
4423 else
4424 t->flags |= SN_FINST_D;
4425 }
willy tarreau0f7af912005-12-17 12:21:26 +01004426 return 1;
4427 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004428 /* last read, or end of server write */
4429 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004430 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004431 tv_eternity(&t->crexpire);
4432 shutdown(t->cli_fd, SHUT_RD);
4433 t->cli_state = CL_STSHUTR;
4434 return 1;
4435 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004436 /* last server read and buffer empty */
4437 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004438 FD_CLR(t->cli_fd, StaticWriteEvent);
4439 tv_eternity(&t->cwexpire);
4440 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004441 /* We must ensure that the read part is still alive when switching
4442 * to shutw */
4443 FD_SET(t->cli_fd, StaticReadEvent);
4444 if (t->proxy->clitimeout)
4445 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004446 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004447 //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 +01004448 return 1;
4449 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004450 /* read timeout */
4451 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4452 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004453 tv_eternity(&t->crexpire);
4454 shutdown(t->cli_fd, SHUT_RD);
4455 t->cli_state = CL_STSHUTR;
4456 if (!(t->flags & SN_ERR_MASK))
4457 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004458 if (!(t->flags & SN_FINST_MASK)) {
4459 if (t->pend_pos)
4460 t->flags |= SN_FINST_Q;
4461 else if (s == SV_STCONN)
4462 t->flags |= SN_FINST_C;
4463 else
4464 t->flags |= SN_FINST_D;
4465 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004466 return 1;
4467 }
4468 /* write timeout */
4469 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4470 FD_CLR(t->cli_fd, StaticWriteEvent);
4471 tv_eternity(&t->cwexpire);
4472 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004473 /* We must ensure that the read part is still alive when switching
4474 * to shutw */
4475 FD_SET(t->cli_fd, StaticReadEvent);
4476 if (t->proxy->clitimeout)
4477 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4478
willy tarreau036e1ce2005-12-17 13:46:33 +01004479 t->cli_state = CL_STSHUTW;
4480 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004481 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004482 if (!(t->flags & SN_FINST_MASK)) {
4483 if (t->pend_pos)
4484 t->flags |= SN_FINST_Q;
4485 else if (s == SV_STCONN)
4486 t->flags |= SN_FINST_C;
4487 else
4488 t->flags |= SN_FINST_D;
4489 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004490 return 1;
4491 }
willy tarreau0f7af912005-12-17 12:21:26 +01004492
willy tarreauc58fc692005-12-17 14:13:08 +01004493 if (req->l >= req->rlim - req->data) {
4494 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004495 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004496 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004497 FD_CLR(t->cli_fd, StaticReadEvent);
4498 tv_eternity(&t->crexpire);
4499 }
4500 }
4501 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004502 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004503 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4504 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004505 if (!t->proxy->clitimeout ||
4506 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4507 /* If the client has no timeout, or if the server not ready yet, and we
4508 * know for sure that it can expire, then it's cleaner to disable the
4509 * timeout on the client side so that too low values cannot make the
4510 * sessions abort too early.
4511 */
willy tarreau0f7af912005-12-17 12:21:26 +01004512 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004513 else
4514 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004515 }
4516 }
4517
4518 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004519 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004520 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4521 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4522 tv_eternity(&t->cwexpire);
4523 }
4524 }
4525 else { /* buffer not empty */
4526 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4527 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004528 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004529 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004530 /* FIXME: to prevent the client from expiring read timeouts during writes,
4531 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004532 t->crexpire = t->cwexpire;
4533 }
willy tarreau0f7af912005-12-17 12:21:26 +01004534 else
4535 tv_eternity(&t->cwexpire);
4536 }
4537 }
4538 return 0; /* other cases change nothing */
4539 }
4540 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004541 if (t->res_cw == RES_ERROR) {
4542 tv_eternity(&t->cwexpire);
4543 fd_delete(t->cli_fd);
4544 t->cli_state = CL_STCLOSE;
4545 if (!(t->flags & SN_ERR_MASK))
4546 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004547 if (!(t->flags & SN_FINST_MASK)) {
4548 if (t->pend_pos)
4549 t->flags |= SN_FINST_Q;
4550 else if (s == SV_STCONN)
4551 t->flags |= SN_FINST_C;
4552 else
4553 t->flags |= SN_FINST_D;
4554 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004555 return 1;
4556 }
4557 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004558 tv_eternity(&t->cwexpire);
4559 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004560 t->cli_state = CL_STCLOSE;
4561 return 1;
4562 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004563 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4564 tv_eternity(&t->cwexpire);
4565 fd_delete(t->cli_fd);
4566 t->cli_state = CL_STCLOSE;
4567 if (!(t->flags & SN_ERR_MASK))
4568 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004569 if (!(t->flags & SN_FINST_MASK)) {
4570 if (t->pend_pos)
4571 t->flags |= SN_FINST_Q;
4572 else if (s == SV_STCONN)
4573 t->flags |= SN_FINST_C;
4574 else
4575 t->flags |= SN_FINST_D;
4576 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004577 return 1;
4578 }
willy tarreau0f7af912005-12-17 12:21:26 +01004579 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004580 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004581 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4582 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4583 tv_eternity(&t->cwexpire);
4584 }
4585 }
4586 else { /* buffer not empty */
4587 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4588 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004589 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004590 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004591 /* FIXME: to prevent the client from expiring read timeouts during writes,
4592 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004593 t->crexpire = t->cwexpire;
4594 }
willy tarreau0f7af912005-12-17 12:21:26 +01004595 else
4596 tv_eternity(&t->cwexpire);
4597 }
4598 }
4599 return 0;
4600 }
4601 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004602 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004603 tv_eternity(&t->crexpire);
4604 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004605 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004606 if (!(t->flags & SN_ERR_MASK))
4607 t->flags |= SN_ERR_CLICL;
willy tarreau078c79a2006-05-13 12:23:58 +02004608 if (!(t->flags & SN_FINST_MASK)) {
4609 if (t->pend_pos)
4610 t->flags |= SN_FINST_Q;
4611 else if (s == SV_STCONN)
4612 t->flags |= SN_FINST_C;
4613 else
4614 t->flags |= SN_FINST_D;
4615 }
willy tarreau0f7af912005-12-17 12:21:26 +01004616 return 1;
4617 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004618 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4619 tv_eternity(&t->crexpire);
4620 fd_delete(t->cli_fd);
4621 t->cli_state = CL_STCLOSE;
4622 return 1;
4623 }
4624 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4625 tv_eternity(&t->crexpire);
4626 fd_delete(t->cli_fd);
4627 t->cli_state = CL_STCLOSE;
4628 if (!(t->flags & SN_ERR_MASK))
4629 t->flags |= SN_ERR_CLITO;
willy tarreau078c79a2006-05-13 12:23:58 +02004630 if (!(t->flags & SN_FINST_MASK)) {
4631 if (t->pend_pos)
4632 t->flags |= SN_FINST_Q;
4633 else if (s == SV_STCONN)
4634 t->flags |= SN_FINST_C;
4635 else
4636 t->flags |= SN_FINST_D;
4637 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004638 return 1;
4639 }
willy tarreauef900ab2005-12-17 12:52:52 +01004640 else if (req->l >= req->rlim - req->data) {
4641 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004642
4643 /* FIXME-20050705: is it possible for a client to maintain a session
4644 * after the timeout by sending more data after it receives a close ?
4645 */
4646
willy tarreau0f7af912005-12-17 12:21:26 +01004647 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004648 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004649 FD_CLR(t->cli_fd, StaticReadEvent);
4650 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004651 //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 +01004652 }
4653 }
4654 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004655 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004656 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4657 FD_SET(t->cli_fd, StaticReadEvent);
4658 if (t->proxy->clitimeout)
4659 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4660 else
4661 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004662 //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 +01004663 }
4664 }
4665 return 0;
4666 }
4667 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004668 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004669 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004670 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 +01004671 write(1, trash, len);
4672 }
4673 return 0;
4674 }
4675 return 0;
4676}
4677
willy tarreaudfece232006-05-02 00:19:57 +02004678/* This function turns the server state into the SV_STCLOSE, and sets
4679 * indicators accordingly. Note that if <status> is 0, no message is
4680 * returned.
4681 */
4682void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4683 t->srv_state = SV_STCLOSE;
4684 if (status > 0) {
4685 t->logs.status = status;
4686 if (t->proxy->mode == PR_MODE_HTTP)
4687 client_return(t, msglen, msg);
4688 }
4689 if (!(t->flags & SN_ERR_MASK))
4690 t->flags |= err;
4691 if (!(t->flags & SN_FINST_MASK))
4692 t->flags |= finst;
4693}
4694
4695/*
4696 * This function checks the retry count during the connect() job.
4697 * It updates the session's srv_state and retries, so that the caller knows
4698 * what it has to do. It uses the last connection error to set the log when
4699 * it expires. It returns 1 when it has expired, and 0 otherwise.
4700 */
4701int srv_count_retry_down(struct session *t, int conn_err) {
4702 /* we are in front of a retryable error */
4703 t->conn_retries--;
4704 if (t->conn_retries < 0) {
4705 /* if not retryable anymore, let's abort */
4706 tv_eternity(&t->cnexpire);
4707 srv_close_with_err(t, conn_err, SN_FINST_C,
4708 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4709
4710 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004711 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004712 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004713 if (may_dequeue_tasks(t->srv, t->proxy))
4714 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004715 return 1;
4716 }
4717 return 0;
4718}
willy tarreau0f7af912005-12-17 12:21:26 +01004719
4720/*
willy tarreaudfece232006-05-02 00:19:57 +02004721 * This function performs the retryable part of the connect() job.
4722 * It updates the session's srv_state and retries, so that the caller knows
4723 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4724 * it needs to redispatch.
4725 */
4726int srv_retryable_connect(struct session *t) {
4727 int conn_err;
4728
4729 /* This loop ensures that we stop before the last retry in case of a
4730 * redispatchable server.
4731 */
4732 do {
4733 /* initiate a connection to the server */
4734 conn_err = connect_server(t);
4735 switch (conn_err) {
4736
4737 case SN_ERR_NONE:
4738 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4739 t->srv_state = SV_STCONN;
4740 return 1;
4741
4742 case SN_ERR_INTERNAL:
4743 tv_eternity(&t->cnexpire);
4744 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4745 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4746 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004747 if (may_dequeue_tasks(t->srv, t->proxy))
4748 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004749 return 1;
4750 }
4751 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02004752 if (srv_count_retry_down(t, conn_err)) {
4753 /* let's try to offer this slot to anybody */
4754 if (may_dequeue_tasks(t->srv, t->proxy))
4755 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004756 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02004757 }
willy tarreaudfece232006-05-02 00:19:57 +02004758 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4759
4760 /* We're on our last chance, and the REDISP option was specified.
4761 * We will ignore cookie and force to balance or use the dispatcher.
4762 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004763 /* let's try to offer this slot to anybody */
4764 if (may_dequeue_tasks(t->srv, t->proxy))
4765 task_wakeup(&rq, t->srv->queue_mgt);
4766
willy tarreaudfece232006-05-02 00:19:57 +02004767 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4768 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4769 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4770 t->flags &= ~SN_CK_MASK;
4771 t->flags |= SN_CK_DOWN;
4772 }
4773 return 0;
4774}
4775
4776/* This function performs the "redispatch" part of a connection attempt. It
4777 * will assign a server if required, queue the connection if required, and
4778 * handle errors that might arise at this level. It can change the server
4779 * state. It will return 1 if it encounters an error, switches the server
4780 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4781 * that the connection is ready to use.
4782 */
4783
4784int srv_redispatch_connect(struct session *t) {
4785 int conn_err;
4786
4787 /* We know that we don't have any connection pending, so we will
4788 * try to get a new one, and wait in this state if it's queued
4789 */
4790 conn_err = assign_server_and_queue(t);
4791 switch (conn_err) {
4792 case SRV_STATUS_OK:
4793 break;
4794
4795 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02004796 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02004797 tv_eternity(&t->cnexpire);
4798 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4799 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaudfece232006-05-02 00:19:57 +02004800 return 1;
4801
4802 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02004803 /* FIXME-20060503 : we should use the queue timeout instead */
4804 if (t->proxy->contimeout)
4805 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
4806 else
4807 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004808 t->srv_state = SV_STIDLE;
4809 /* do nothing else and do not wake any other session up */
4810 return 1;
4811
4812 case SRV_STATUS_FULL:
4813 case SRV_STATUS_INTERNAL:
4814 default:
4815 tv_eternity(&t->cnexpire);
4816 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4817 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4818 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004819 if (may_dequeue_tasks(t->srv, t->proxy))
4820 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004821 return 1;
4822 }
4823 /* if we get here, it's because we got SRV_STATUS_OK, which also
4824 * means that the connection has not been queued.
4825 */
4826 return 0;
4827}
4828
4829
4830/*
willy tarreau0f7af912005-12-17 12:21:26 +01004831 * manages the server FSM and its socket. It returns 1 if a state has changed
4832 * (and a resync may be needed), 0 else.
4833 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004834int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004835 int s = t->srv_state;
4836 int c = t->cli_state;
4837 struct buffer *req = t->req;
4838 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004839 appsess *asession_temp = NULL;
4840 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004841 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004842
willy tarreau750a4722005-12-17 13:21:24 +01004843#ifdef DEBUG_FULL
4844 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4845#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004846 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4847 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4848 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4849 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004850 if (s == SV_STIDLE) {
4851 if (c == CL_STHEADERS)
4852 return 0; /* stay in idle, waiting for data to reach the client side */
4853 else if (c == CL_STCLOSE ||
4854 c == CL_STSHUTW ||
4855 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4856 tv_eternity(&t->cnexpire);
willy tarreau424e04a2006-05-13 16:08:47 +02004857 if (t->pend_pos)
4858 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreau078c79a2006-05-13 12:23:58 +02004859 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 +02004860
willy tarreau0f7af912005-12-17 12:21:26 +01004861 return 1;
4862 }
willy tarreaudfece232006-05-02 00:19:57 +02004863 else {
4864 /* Right now, we will need to create a connection to the server.
4865 * We might already have tried, and got a connection pending, in
4866 * which case we will not do anything till it's pending. It's up
4867 * to any other session to release it and wake us up again.
4868 */
willy tarreau45526ed2006-05-03 20:11:50 +02004869 if (t->pend_pos) {
4870 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
4871 return 0;
4872 else {
4873 /* we've been waiting too long here */
4874 tv_eternity(&t->cnexpire);
willy tarreau078c79a2006-05-13 12:23:58 +02004875 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
4876 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
willy tarreau45526ed2006-05-03 20:11:50 +02004877 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4878 return 1;
4879 }
4880 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004881
willy tarreaudfece232006-05-02 00:19:57 +02004882 do {
4883 /* first, get a connection */
4884 if (srv_redispatch_connect(t))
4885 return t->srv_state != SV_STIDLE;
4886
4887 /* try to (re-)connect to the server, and fail if we expire the
4888 * number of retries.
4889 */
willy tarreauf32f5242006-05-02 22:54:52 +02004890 if (srv_retryable_connect(t)) {
4891 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004892 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02004893 }
willy tarreaudfece232006-05-02 00:19:57 +02004894
4895 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004896 }
4897 }
4898 else if (s == SV_STCONN) { /* connection in progress */
4899 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004900 //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 +01004901 return 0; /* nothing changed */
4902 }
4903 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004904 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004905 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004906
willy tarreau0f7af912005-12-17 12:21:26 +01004907 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004908 if (t->srv)
4909 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004910
4911 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004912 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4913 else
willy tarreaudfece232006-05-02 00:19:57 +02004914 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004915
willy tarreaudfece232006-05-02 00:19:57 +02004916 /* ensure that we have enough retries left */
4917 if (srv_count_retry_down(t, conn_err))
4918 return 1;
4919
4920 do {
4921 /* Now we will try to either reconnect to the same server or
4922 * connect to another server. If the connection gets queued
4923 * because all servers are saturated, then we will go back to
4924 * the SV_STIDLE state.
4925 */
willy tarreauf32f5242006-05-02 22:54:52 +02004926 if (srv_retryable_connect(t)) {
4927 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004928 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02004929 }
willy tarreaudfece232006-05-02 00:19:57 +02004930
4931 /* we need to redispatch the connection to another server */
4932 if (srv_redispatch_connect(t))
4933 return t->srv_state != SV_STCONN;
4934 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004935 }
4936 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004937 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004938
willy tarreau0f7af912005-12-17 12:21:26 +01004939 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004940 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004941 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004942 tv_eternity(&t->swexpire);
4943 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004944 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004945 if (t->proxy->srvtimeout) {
4946 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004947 /* FIXME: to prevent the server from expiring read timeouts during writes,
4948 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004949 t->srexpire = t->swexpire;
4950 }
4951 else
4952 tv_eternity(&t->swexpire);
4953 }
willy tarreau0f7af912005-12-17 12:21:26 +01004954
4955 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4956 FD_SET(t->srv_fd, StaticReadEvent);
4957 if (t->proxy->srvtimeout)
4958 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4959 else
4960 tv_eternity(&t->srexpire);
4961
4962 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004963 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004964 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004965
4966 /* if the user wants to log as soon as possible, without counting
4967 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004968 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004969 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4970 sess_log(t);
4971 }
willy tarreau0f7af912005-12-17 12:21:26 +01004972 }
willy tarreauef900ab2005-12-17 12:52:52 +01004973 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004974 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004975 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004976 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4977 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004978 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004979 return 1;
4980 }
4981 }
4982 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004983 /* now parse the partial (or complete) headers */
4984 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4985 char *ptr;
4986 int delete_header;
4987
4988 ptr = rep->lr;
4989
4990 /* look for the end of the current header */
4991 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4992 ptr++;
4993
4994 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004995 int line, len;
4996
4997 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004998
4999 /* first, we'll block if security checks have caught nasty things */
5000 if (t->flags & SN_CACHEABLE) {
5001 if ((t->flags & SN_CACHE_COOK) &&
5002 (t->flags & SN_SCK_ANY) &&
5003 (t->proxy->options & PR_O_CHK_CACHE)) {
5004
5005 /* we're in presence of a cacheable response containing
5006 * a set-cookie header. We'll block it as requested by
5007 * the 'checkcache' option, and send an alert.
5008 */
5009 tv_eternity(&t->srexpire);
5010 tv_eternity(&t->swexpire);
5011 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005012 if (t->srv)
5013 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01005014 t->srv_state = SV_STCLOSE;
5015 t->logs.status = 502;
5016 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5017 if (!(t->flags & SN_ERR_MASK))
5018 t->flags |= SN_ERR_PRXCOND;
5019 if (!(t->flags & SN_FINST_MASK))
5020 t->flags |= SN_FINST_H;
5021
5022 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5023 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
5024
willy tarreaudfece232006-05-02 00:19:57 +02005025 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005026 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005027 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005028 if (may_dequeue_tasks(t->srv, t->proxy))
5029 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005030
willy tarreau97f58572005-12-18 00:53:44 +01005031 return 1;
5032 }
5033 }
5034
willy tarreau982249e2005-12-18 00:57:06 +01005035 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
5036 if (t->flags & SN_SVDENY) {
5037 tv_eternity(&t->srexpire);
5038 tv_eternity(&t->swexpire);
5039 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005040 if (t->srv)
5041 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01005042 t->srv_state = SV_STCLOSE;
5043 t->logs.status = 502;
5044 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
5045 if (!(t->flags & SN_ERR_MASK))
5046 t->flags |= SN_ERR_PRXCOND;
5047 if (!(t->flags & SN_FINST_MASK))
5048 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005049 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005050 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005051 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005052 if (may_dequeue_tasks(t->srv, t->proxy))
5053 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005054
willy tarreau982249e2005-12-18 00:57:06 +01005055 return 1;
5056 }
5057
willy tarreau5cbea6f2005-12-17 12:48:26 +01005058 /* we'll have something else to do here : add new headers ... */
5059
willy tarreaucd878942005-12-17 13:27:43 +01005060 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
5061 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005062 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01005063 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02005064 * requests and this one isn't. Note that servers which don't have cookies
5065 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005066 */
willy tarreau750a4722005-12-17 13:21:24 +01005067 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01005068 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02005069 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01005070
willy tarreau036e1ce2005-12-17 13:46:33 +01005071 t->flags |= SN_SCK_INSERTED;
5072
willy tarreau750a4722005-12-17 13:21:24 +01005073 /* Here, we will tell an eventual cache on the client side that we don't
5074 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
5075 * Some caches understand the correct form: 'no-cache="set-cookie"', but
5076 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
5077 */
willy tarreau240afa62005-12-17 13:14:35 +01005078 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01005079 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
5080 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01005081
5082 if (rep->data + rep->l < rep->h)
5083 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
5084 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01005085 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005086 }
5087
5088 /* headers to be added */
5089 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01005090 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
5091 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005092 }
5093
willy tarreau25c4ea52005-12-18 00:49:49 +01005094 /* add a "connection: close" line if needed */
5095 if (t->proxy->options & PR_O_HTTP_CLOSE)
5096 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
5097
willy tarreau5cbea6f2005-12-17 12:48:26 +01005098 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01005099 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01005100 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01005101
Willy TARREAU767ba712006-03-01 22:40:50 +01005102 /* client connection already closed or option 'httpclose' required :
5103 * we close the server's outgoing connection right now.
5104 */
5105 if ((req->l == 0) &&
5106 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
5107 FD_CLR(t->srv_fd, StaticWriteEvent);
5108 tv_eternity(&t->swexpire);
5109
5110 /* We must ensure that the read part is still alive when switching
5111 * to shutw */
5112 FD_SET(t->srv_fd, StaticReadEvent);
5113 if (t->proxy->srvtimeout)
5114 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5115
5116 shutdown(t->srv_fd, SHUT_WR);
5117 t->srv_state = SV_STSHUTW;
5118 }
5119
willy tarreau25c4ea52005-12-18 00:49:49 +01005120 /* if the user wants to log as soon as possible, without counting
5121 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01005122 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01005123 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
5124 t->logs.bytes = rep->h - rep->data;
5125 sess_log(t);
5126 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005127 break;
5128 }
5129
5130 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
5131 if (ptr > rep->r - 2) {
5132 /* this is a partial header, let's wait for more to come */
5133 rep->lr = ptr;
5134 break;
5135 }
5136
5137 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
5138 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
5139
5140 /* now we know that *ptr is either \r or \n,
5141 * and that there are at least 1 char after it.
5142 */
5143 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
5144 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
5145 else
5146 rep->lr = ptr + 2; /* \r\n or \n\r */
5147
5148 /*
5149 * now we know that we have a full header ; we can do whatever
5150 * we want with these pointers :
5151 * rep->h = beginning of header
5152 * ptr = end of header (first \r or \n)
5153 * rep->lr = beginning of next line (next rep->h)
5154 * rep->r = end of data (not used at this stage)
5155 */
5156
willy tarreaua1598082005-12-17 13:08:06 +01005157
willy tarreau982249e2005-12-18 00:57:06 +01005158 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005159 t->logs.logwait &= ~LW_RESP;
5160 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005161 switch (t->logs.status) {
5162 case 200:
5163 case 203:
5164 case 206:
5165 case 300:
5166 case 301:
5167 case 410:
5168 /* RFC2616 @13.4:
5169 * "A response received with a status code of
5170 * 200, 203, 206, 300, 301 or 410 MAY be stored
5171 * by a cache (...) unless a cache-control
5172 * directive prohibits caching."
5173 *
5174 * RFC2616 @9.5: POST method :
5175 * "Responses to this method are not cacheable,
5176 * unless the response includes appropriate
5177 * Cache-Control or Expires header fields."
5178 */
5179 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5180 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5181 break;
5182 default:
5183 break;
5184 }
willy tarreau4302f492005-12-18 01:00:37 +01005185 }
5186 else if (t->logs.logwait & LW_RSPHDR) {
5187 struct cap_hdr *h;
5188 int len;
5189 for (h = t->proxy->rsp_cap; h; h = h->next) {
5190 if ((h->namelen + 2 <= ptr - rep->h) &&
5191 (rep->h[h->namelen] == ':') &&
5192 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5193
5194 if (t->rsp_cap[h->index] == NULL)
5195 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5196
5197 len = ptr - (rep->h + h->namelen + 2);
5198 if (len > h->len)
5199 len = h->len;
5200
5201 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5202 t->rsp_cap[h->index][len]=0;
5203 }
5204 }
5205
willy tarreaua1598082005-12-17 13:08:06 +01005206 }
5207
willy tarreau5cbea6f2005-12-17 12:48:26 +01005208 delete_header = 0;
5209
willy tarreau982249e2005-12-18 00:57:06 +01005210 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005211 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005212 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 +01005213 max = ptr - rep->h;
5214 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005215 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005216 trash[len++] = '\n';
5217 write(1, trash, len);
5218 }
5219
willy tarreau25c4ea52005-12-18 00:49:49 +01005220 /* remove "connection: " if needed */
5221 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5222 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5223 delete_header = 1;
5224 }
5225
willy tarreau5cbea6f2005-12-17 12:48:26 +01005226 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005227 if (!delete_header && t->proxy->rsp_exp != NULL
5228 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005229 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005230 char term;
5231
5232 term = *ptr;
5233 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005234 exp = t->proxy->rsp_exp;
5235 do {
5236 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5237 switch (exp->action) {
5238 case ACT_ALLOW:
5239 if (!(t->flags & SN_SVDENY))
5240 t->flags |= SN_SVALLOW;
5241 break;
5242 case ACT_REPLACE:
5243 if (!(t->flags & SN_SVDENY)) {
5244 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5245 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5246 }
5247 break;
5248 case ACT_REMOVE:
5249 if (!(t->flags & SN_SVDENY))
5250 delete_header = 1;
5251 break;
5252 case ACT_DENY:
5253 if (!(t->flags & SN_SVALLOW))
5254 t->flags |= SN_SVDENY;
5255 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005256 case ACT_PASS: /* we simply don't deny this one */
5257 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005258 }
5259 break;
5260 }
willy tarreaue39cd132005-12-17 13:00:18 +01005261 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005262 *ptr = term; /* restore the string terminator */
5263 }
5264
willy tarreau97f58572005-12-18 00:53:44 +01005265 /* check for cache-control: or pragma: headers */
5266 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5267 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5268 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5269 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5270 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005271 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005272 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5273 else {
5274 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005275 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005276 t->flags &= ~SN_CACHE_COOK;
5277 }
5278 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005279 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005280 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005281 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005282 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5283 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005284 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005285 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005286 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5287 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5288 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5289 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5290 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5291 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005292 }
5293 }
5294 }
5295
willy tarreau5cbea6f2005-12-17 12:48:26 +01005296 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005297 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005298 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005299 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005300 char *p1, *p2, *p3, *p4;
5301
willy tarreau97f58572005-12-18 00:53:44 +01005302 t->flags |= SN_SCK_ANY;
5303
willy tarreau5cbea6f2005-12-17 12:48:26 +01005304 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5305
5306 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005307 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005308 p1++;
5309
5310 if (p1 == ptr || *p1 == ';') /* end of cookie */
5311 break;
5312
5313 /* p1 is at the beginning of the cookie name */
5314 p2 = p1;
5315
5316 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5317 p2++;
5318
5319 if (p2 == ptr || *p2 == ';') /* next cookie */
5320 break;
5321
5322 p3 = p2 + 1; /* skips the '=' sign */
5323 if (p3 == ptr)
5324 break;
5325
5326 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005327 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005328 p4++;
5329
5330 /* here, we have the cookie name between p1 and p2,
5331 * and its value between p3 and p4.
5332 * we can process it.
5333 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005334
5335 /* first, let's see if we want to capture it */
5336 if (t->proxy->capture_name != NULL &&
5337 t->logs.srv_cookie == NULL &&
5338 (p4 - p1 >= t->proxy->capture_namelen) &&
5339 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5340 int log_len = p4 - p1;
5341
5342 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5343 Alert("HTTP logging : out of memory.\n");
5344 }
5345
5346 if (log_len > t->proxy->capture_len)
5347 log_len = t->proxy->capture_len;
5348 memcpy(t->logs.srv_cookie, p1, log_len);
5349 t->logs.srv_cookie[log_len] = 0;
5350 }
5351
5352 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5353 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005354 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005355 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005356
5357 /* If the cookie is in insert mode on a known server, we'll delete
5358 * this occurrence because we'll insert another one later.
5359 * We'll delete it too if the "indirect" option is set and we're in
5360 * a direct access. */
5361 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005362 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005363 /* this header must be deleted */
5364 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005365 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005366 }
5367 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5368 /* replace bytes p3->p4 with the cookie name associated
5369 * with this server since we know it.
5370 */
5371 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005372 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005373 }
willy tarreau0174f312005-12-18 01:02:42 +01005374 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5375 /* insert the cookie name associated with this server
5376 * before existing cookie, and insert a delimitor between them..
5377 */
5378 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5379 p3[t->srv->cklen] = COOKIE_DELIM;
5380 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5381 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005382 break;
5383 }
willy tarreau12350152005-12-18 01:03:27 +01005384
5385 /* first, let's see if the cookie is our appcookie*/
5386 if ((t->proxy->appsession_name != NULL) &&
5387 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5388
5389 /* Cool... it's the right one */
5390
willy tarreaub952e1d2005-12-18 01:31:20 +01005391 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005392 asession_temp = &local_asession;
5393
willy tarreaub952e1d2005-12-18 01:31:20 +01005394 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005395 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5396 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5397 }
5398 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5399 asession_temp->sessid[t->proxy->appsession_len] = 0;
5400 asession_temp->serverid = NULL;
5401
5402 /* only do insert, if lookup fails */
5403 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5404 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5405 Alert("Not enought Memory process_srv():asession:calloc().\n");
5406 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5407 return 0;
5408 }
5409 asession_temp->sessid = local_asession.sessid;
5410 asession_temp->serverid = local_asession.serverid;
5411 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005412 }/* end if (chtbl_lookup()) */
5413 else {
willy tarreau12350152005-12-18 01:03:27 +01005414 /* free wasted memory */
5415 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005416 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005417
willy tarreaub952e1d2005-12-18 01:31:20 +01005418 if (asession_temp->serverid == NULL) {
5419 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005420 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5421 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5422 }
5423 asession_temp->serverid[0] = '\0';
5424 }
5425
willy tarreaub952e1d2005-12-18 01:31:20 +01005426 if (asession_temp->serverid[0] == '\0')
5427 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005428
5429 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5430
5431#if defined(DEBUG_HASH)
5432 print_table(&(t->proxy->htbl_proxy));
5433#endif
5434 break;
5435 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005436 else {
5437 // fprintf(stderr,"Ignoring unknown cookie : ");
5438 // write(2, p1, p2-p1);
5439 // fprintf(stderr," = ");
5440 // write(2, p3, p4-p3);
5441 // fprintf(stderr,"\n");
5442 }
5443 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5444 } /* we're now at the end of the cookie value */
5445 } /* end of cookie processing */
5446
willy tarreau97f58572005-12-18 00:53:44 +01005447 /* check for any set-cookie in case we check for cacheability */
5448 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5449 (t->proxy->options & PR_O_CHK_CACHE) &&
5450 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5451 t->flags |= SN_SCK_ANY;
5452 }
5453
willy tarreau5cbea6f2005-12-17 12:48:26 +01005454 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005455 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005456 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005457
willy tarreau5cbea6f2005-12-17 12:48:26 +01005458 rep->h = rep->lr;
5459 } /* while (rep->lr < rep->r) */
5460
5461 /* end of header processing (even if incomplete) */
5462
willy tarreauef900ab2005-12-17 12:52:52 +01005463 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5464 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5465 * full. We cannot loop here since event_srv_read will disable it only if
5466 * rep->l == rlim-data
5467 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005468 FD_SET(t->srv_fd, StaticReadEvent);
5469 if (t->proxy->srvtimeout)
5470 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5471 else
5472 tv_eternity(&t->srexpire);
5473 }
willy tarreau0f7af912005-12-17 12:21:26 +01005474
willy tarreau8337c6b2005-12-17 13:41:01 +01005475 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005476 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005477 tv_eternity(&t->srexpire);
5478 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005479 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005480 if (t->srv)
5481 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005482 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005483 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005484 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005485 if (!(t->flags & SN_ERR_MASK))
5486 t->flags |= SN_ERR_SRVCL;
5487 if (!(t->flags & SN_FINST_MASK))
5488 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005489 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005490 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005491 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005492 if (may_dequeue_tasks(t->srv, t->proxy))
5493 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005494
willy tarreau0f7af912005-12-17 12:21:26 +01005495 return 1;
5496 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005497 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005498 * since we are in header mode, if there's no space left for headers, we
5499 * won't be able to free more later, so the session will never terminate.
5500 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005501 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 +01005502 FD_CLR(t->srv_fd, StaticReadEvent);
5503 tv_eternity(&t->srexpire);
5504 shutdown(t->srv_fd, SHUT_RD);
5505 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005506 //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 +01005507 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005508 }
5509 /* read timeout : return a 504 to the client.
5510 */
5511 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5512 tv_eternity(&t->srexpire);
5513 tv_eternity(&t->swexpire);
5514 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005515 if (t->srv)
5516 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005517 t->srv_state = SV_STCLOSE;
5518 t->logs.status = 504;
5519 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005520 if (!(t->flags & SN_ERR_MASK))
5521 t->flags |= SN_ERR_SRVTO;
5522 if (!(t->flags & SN_FINST_MASK))
5523 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005524 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005525 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005526 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005527 if (may_dequeue_tasks(t->srv, t->proxy))
5528 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005529
willy tarreau8337c6b2005-12-17 13:41:01 +01005530 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005531 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005532 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005533 /* FIXME!!! here, we don't want to switch to SHUTW if the
5534 * client shuts read too early, because we may still have
5535 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005536 * The side-effect is that if the client completely closes its
5537 * connection during SV_STHEADER, the connection to the server
5538 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005539 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005540 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005541 FD_CLR(t->srv_fd, StaticWriteEvent);
5542 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005543
5544 /* We must ensure that the read part is still alive when switching
5545 * to shutw */
5546 FD_SET(t->srv_fd, StaticReadEvent);
5547 if (t->proxy->srvtimeout)
5548 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5549
willy tarreau0f7af912005-12-17 12:21:26 +01005550 shutdown(t->srv_fd, SHUT_WR);
5551 t->srv_state = SV_STSHUTW;
5552 return 1;
5553 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005554 /* write timeout */
5555 /* FIXME!!! here, we don't want to switch to SHUTW if the
5556 * client shuts read too early, because we may still have
5557 * some work to do on the headers.
5558 */
5559 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5560 FD_CLR(t->srv_fd, StaticWriteEvent);
5561 tv_eternity(&t->swexpire);
5562 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005563 /* We must ensure that the read part is still alive when switching
5564 * to shutw */
5565 FD_SET(t->srv_fd, StaticReadEvent);
5566 if (t->proxy->srvtimeout)
5567 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5568
5569 /* We must ensure that the read part is still alive when switching
5570 * to shutw */
5571 FD_SET(t->srv_fd, StaticReadEvent);
5572 if (t->proxy->srvtimeout)
5573 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5574
willy tarreau036e1ce2005-12-17 13:46:33 +01005575 t->srv_state = SV_STSHUTW;
5576 if (!(t->flags & SN_ERR_MASK))
5577 t->flags |= SN_ERR_SRVTO;
5578 if (!(t->flags & SN_FINST_MASK))
5579 t->flags |= SN_FINST_H;
5580 return 1;
5581 }
willy tarreau0f7af912005-12-17 12:21:26 +01005582
5583 if (req->l == 0) {
5584 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5585 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5586 tv_eternity(&t->swexpire);
5587 }
5588 }
5589 else { /* client buffer not empty */
5590 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5591 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005592 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005593 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005594 /* FIXME: to prevent the server from expiring read timeouts during writes,
5595 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005596 t->srexpire = t->swexpire;
5597 }
willy tarreau0f7af912005-12-17 12:21:26 +01005598 else
5599 tv_eternity(&t->swexpire);
5600 }
5601 }
5602
willy tarreau5cbea6f2005-12-17 12:48:26 +01005603 /* be nice with the client side which would like to send a complete header
5604 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5605 * would read all remaining data at once ! The client should not write past rep->lr
5606 * when the server is in header state.
5607 */
5608 //return header_processed;
5609 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005610 }
5611 else if (s == SV_STDATA) {
5612 /* read or write error */
5613 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005614 tv_eternity(&t->srexpire);
5615 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005616 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005617 if (t->srv)
5618 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005619 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005620 if (!(t->flags & SN_ERR_MASK))
5621 t->flags |= SN_ERR_SRVCL;
5622 if (!(t->flags & SN_FINST_MASK))
5623 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005624 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005625 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005626 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005627 if (may_dequeue_tasks(t->srv, t->proxy))
5628 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005629
willy tarreau0f7af912005-12-17 12:21:26 +01005630 return 1;
5631 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005632 /* last read, or end of client write */
5633 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005634 FD_CLR(t->srv_fd, StaticReadEvent);
5635 tv_eternity(&t->srexpire);
5636 shutdown(t->srv_fd, SHUT_RD);
5637 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005638 //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 +01005639 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005640 }
5641 /* end of client read and no more data to send */
5642 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5643 FD_CLR(t->srv_fd, StaticWriteEvent);
5644 tv_eternity(&t->swexpire);
5645 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005646 /* We must ensure that the read part is still alive when switching
5647 * to shutw */
5648 FD_SET(t->srv_fd, StaticReadEvent);
5649 if (t->proxy->srvtimeout)
5650 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5651
willy tarreaua41a8b42005-12-17 14:02:24 +01005652 t->srv_state = SV_STSHUTW;
5653 return 1;
5654 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005655 /* read timeout */
5656 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5657 FD_CLR(t->srv_fd, StaticReadEvent);
5658 tv_eternity(&t->srexpire);
5659 shutdown(t->srv_fd, SHUT_RD);
5660 t->srv_state = SV_STSHUTR;
5661 if (!(t->flags & SN_ERR_MASK))
5662 t->flags |= SN_ERR_SRVTO;
5663 if (!(t->flags & SN_FINST_MASK))
5664 t->flags |= SN_FINST_D;
5665 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005666 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005667 /* write timeout */
5668 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005669 FD_CLR(t->srv_fd, StaticWriteEvent);
5670 tv_eternity(&t->swexpire);
5671 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005672 /* We must ensure that the read part is still alive when switching
5673 * to shutw */
5674 FD_SET(t->srv_fd, StaticReadEvent);
5675 if (t->proxy->srvtimeout)
5676 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005677 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005678 if (!(t->flags & SN_ERR_MASK))
5679 t->flags |= SN_ERR_SRVTO;
5680 if (!(t->flags & SN_FINST_MASK))
5681 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005682 return 1;
5683 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005684
5685 /* recompute request time-outs */
5686 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005687 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5688 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5689 tv_eternity(&t->swexpire);
5690 }
5691 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005692 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005693 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5694 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005695 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005696 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005697 /* FIXME: to prevent the server from expiring read timeouts during writes,
5698 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005699 t->srexpire = t->swexpire;
5700 }
willy tarreau0f7af912005-12-17 12:21:26 +01005701 else
5702 tv_eternity(&t->swexpire);
5703 }
5704 }
5705
willy tarreaub1ff9db2005-12-17 13:51:03 +01005706 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005707 if (rep->l == BUFSIZE) { /* no room to read more data */
5708 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5709 FD_CLR(t->srv_fd, StaticReadEvent);
5710 tv_eternity(&t->srexpire);
5711 }
5712 }
5713 else {
5714 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5715 FD_SET(t->srv_fd, StaticReadEvent);
5716 if (t->proxy->srvtimeout)
5717 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5718 else
5719 tv_eternity(&t->srexpire);
5720 }
5721 }
5722
5723 return 0; /* other cases change nothing */
5724 }
5725 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005726 if (t->res_sw == RES_ERROR) {
5727 //FD_CLR(t->srv_fd, StaticWriteEvent);
5728 tv_eternity(&t->swexpire);
5729 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005730 if (t->srv)
5731 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005732 //close(t->srv_fd);
5733 t->srv_state = SV_STCLOSE;
5734 if (!(t->flags & SN_ERR_MASK))
5735 t->flags |= SN_ERR_SRVCL;
5736 if (!(t->flags & SN_FINST_MASK))
5737 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005738 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005739 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005740 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005741 if (may_dequeue_tasks(t->srv, t->proxy))
5742 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005743
willy tarreau036e1ce2005-12-17 13:46:33 +01005744 return 1;
5745 }
5746 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005747 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005748 tv_eternity(&t->swexpire);
5749 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005750 if (t->srv)
5751 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005752 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005753 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005754 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005755 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005756 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005757 if (may_dequeue_tasks(t->srv, t->proxy))
5758 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005759
willy tarreau0f7af912005-12-17 12:21:26 +01005760 return 1;
5761 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005762 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5763 //FD_CLR(t->srv_fd, StaticWriteEvent);
5764 tv_eternity(&t->swexpire);
5765 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005766 if (t->srv)
5767 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005768 //close(t->srv_fd);
5769 t->srv_state = SV_STCLOSE;
5770 if (!(t->flags & SN_ERR_MASK))
5771 t->flags |= SN_ERR_SRVTO;
5772 if (!(t->flags & SN_FINST_MASK))
5773 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005774 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005775 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005776 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005777 if (may_dequeue_tasks(t->srv, t->proxy))
5778 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005779
willy tarreau036e1ce2005-12-17 13:46:33 +01005780 return 1;
5781 }
willy tarreau0f7af912005-12-17 12:21:26 +01005782 else if (req->l == 0) {
5783 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5784 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5785 tv_eternity(&t->swexpire);
5786 }
5787 }
5788 else { /* buffer not empty */
5789 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5790 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005791 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005792 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005793 /* FIXME: to prevent the server from expiring read timeouts during writes,
5794 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005795 t->srexpire = t->swexpire;
5796 }
willy tarreau0f7af912005-12-17 12:21:26 +01005797 else
5798 tv_eternity(&t->swexpire);
5799 }
5800 }
5801 return 0;
5802 }
5803 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005804 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005805 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005806 tv_eternity(&t->srexpire);
5807 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005808 if (t->srv)
5809 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005810 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005811 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005812 if (!(t->flags & SN_ERR_MASK))
5813 t->flags |= SN_ERR_SRVCL;
5814 if (!(t->flags & SN_FINST_MASK))
5815 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005816 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005817 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005818 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005819 if (may_dequeue_tasks(t->srv, t->proxy))
5820 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005821
willy tarreau0f7af912005-12-17 12:21:26 +01005822 return 1;
5823 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005824 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5825 //FD_CLR(t->srv_fd, StaticReadEvent);
5826 tv_eternity(&t->srexpire);
5827 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005828 if (t->srv)
5829 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005830 //close(t->srv_fd);
5831 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005832 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005833 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005834 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005835 if (may_dequeue_tasks(t->srv, t->proxy))
5836 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005837
willy tarreau036e1ce2005-12-17 13:46:33 +01005838 return 1;
5839 }
5840 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5841 //FD_CLR(t->srv_fd, StaticReadEvent);
5842 tv_eternity(&t->srexpire);
5843 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005844 if (t->srv)
5845 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005846 //close(t->srv_fd);
5847 t->srv_state = SV_STCLOSE;
5848 if (!(t->flags & SN_ERR_MASK))
5849 t->flags |= SN_ERR_SRVTO;
5850 if (!(t->flags & SN_FINST_MASK))
5851 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005852 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005853 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005854 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005855 if (may_dequeue_tasks(t->srv, t->proxy))
5856 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005857
willy tarreau036e1ce2005-12-17 13:46:33 +01005858 return 1;
5859 }
willy tarreau0f7af912005-12-17 12:21:26 +01005860 else if (rep->l == BUFSIZE) { /* no room to read more data */
5861 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5862 FD_CLR(t->srv_fd, StaticReadEvent);
5863 tv_eternity(&t->srexpire);
5864 }
5865 }
5866 else {
5867 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5868 FD_SET(t->srv_fd, StaticReadEvent);
5869 if (t->proxy->srvtimeout)
5870 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5871 else
5872 tv_eternity(&t->srexpire);
5873 }
5874 }
5875 return 0;
5876 }
5877 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005878 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005879 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005880 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 +01005881 write(1, trash, len);
5882 }
5883 return 0;
5884 }
5885 return 0;
5886}
5887
5888
willy tarreau5cbea6f2005-12-17 12:48:26 +01005889/* Processes the client and server jobs of a session task, then
5890 * puts it back to the wait queue in a clean state, or
5891 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005892 * the time the task accepts to wait, or TIME_ETERNITY for
5893 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005894 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005895int process_session(struct task *t) {
5896 struct session *s = t->context;
5897 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005898
willy tarreau5cbea6f2005-12-17 12:48:26 +01005899 do {
5900 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005901 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005902 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005903 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005904 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005905 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005906 } while (fsm_resync);
5907
5908 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005909 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005910 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005911
willy tarreau5cbea6f2005-12-17 12:48:26 +01005912 tv_min(&min1, &s->crexpire, &s->cwexpire);
5913 tv_min(&min2, &s->srexpire, &s->swexpire);
5914 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005915 tv_min(&t->expire, &min1, &min2);
5916
5917 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005918 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005919
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005920#ifdef DEBUG_FULL
5921 /* DEBUG code : this should never ever happen, otherwise it indicates
5922 * that a task still has something to do and will provoke a quick loop.
5923 */
5924 if (tv_remain2(&now, &t->expire) <= 0)
5925 exit(100);
5926#endif
5927
willy tarreaub952e1d2005-12-18 01:31:20 +01005928 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005929 }
5930
willy tarreau5cbea6f2005-12-17 12:48:26 +01005931 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005932 actconn--;
5933
willy tarreau982249e2005-12-18 00:57:06 +01005934 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005935 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005936 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 +01005937 write(1, trash, len);
5938 }
5939
willy tarreau750a4722005-12-17 13:21:24 +01005940 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005941 if (s->rep != NULL)
5942 s->logs.bytes = s->rep->total;
5943
willy tarreau9fe663a2005-12-17 13:02:59 +01005944 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005945 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005946 sess_log(s);
5947
willy tarreau0f7af912005-12-17 12:21:26 +01005948 /* the task MUST not be in the run queue anymore */
5949 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005950 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005951 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005952 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005953}
5954
5955
willy tarreau2812edc2006-05-04 12:09:37 +02005956/* Sets server <s> down, notifies by all available means, recounts the
5957 * remaining servers on the proxy and transfers queued sessions whenever
5958 * possible to other servers.
5959 */
5960void set_server_down(struct server *s) {
5961 struct pendconn *pc, *pc_bck, *pc_end;
5962 struct session *sess;
5963 int xferred;
5964
5965 s->state &= ~SRV_RUNNING;
5966
5967 if (s->health == s->rise) {
5968 recount_servers(s->proxy);
5969 recalc_server_map(s->proxy);
5970
5971 /* we might have sessions queued on this server and waiting for
5972 * a connection. Those which are redispatchable will be queued
5973 * to another server or to the proxy itself.
5974 */
5975 xferred = 0;
5976 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
5977 sess = pc->sess;
5978 if ((sess->proxy->options & PR_O_REDISP)) {
5979 /* The REDISP option was specified. We will ignore
5980 * cookie and force to balance or use the dispatcher.
5981 */
5982 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5983 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
5984 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
5985 sess->flags &= ~SN_CK_MASK;
5986 sess->flags |= SN_CK_DOWN;
5987 }
5988 pendconn_free(pc);
5989 task_wakeup(&rq, sess->task);
5990 xferred++;
5991 }
5992 }
5993
5994 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
5995 " %d sessions active, %d requeued, %d remaining in queue.\n",
5996 s->state & SRV_BACKUP ? "Backup " : "",
5997 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5998 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
5999 s->cur_sess, xferred, s->nbpend);
6000
willy tarreaubc2eda62006-05-04 15:16:23 +02006001 Warning("%s", trash);
6002 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02006003
6004 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
6005 Alert("Proxy %s has no server available !\n", s->proxy->id);
6006 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
6007 }
6008 }
6009 s->health = 0; /* failure */
6010}
6011
6012
willy tarreau5cbea6f2005-12-17 12:48:26 +01006013
6014/*
6015 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01006016 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01006017 */
6018int process_chk(struct task *t) {
6019 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01006020 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01006021 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006022
willy tarreauef900ab2005-12-17 12:52:52 +01006023 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006024
willy tarreau25424f82006-03-19 19:37:48 +01006025 new_chk:
6026 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006027 if (fd < 0) { /* no check currently running */
6028 //fprintf(stderr, "process_chk: 2\n");
6029 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
6030 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006031 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006032 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006033
6034 /* we don't send any health-checks when the proxy is stopped or when
6035 * the server should not be checked.
6036 */
6037 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01006038 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6039 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01006040 task_queue(t); /* restore t to its place in the task list */
6041 return tv_remain2(&now, &t->expire);
6042 }
6043
willy tarreau5cbea6f2005-12-17 12:48:26 +01006044 /* we'll initiate a new check */
6045 s->result = 0; /* no result yet */
6046 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006047 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01006048 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
6049 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
6050 //fprintf(stderr, "process_chk: 3\n");
6051
willy tarreaua41a8b42005-12-17 14:02:24 +01006052 /* we'll connect to the check port on the server */
6053 sa = s->addr;
6054 sa.sin_port = htons(s->check_port);
6055
willy tarreau0174f312005-12-18 01:02:42 +01006056 /* allow specific binding :
6057 * - server-specific at first
6058 * - proxy-specific next
6059 */
6060 if (s->state & SRV_BIND_SRC) {
6061 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6062 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
6063 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
6064 s->proxy->id, s->id);
6065 s->result = -1;
6066 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006067 }
willy tarreau0174f312005-12-18 01:02:42 +01006068 else if (s->proxy->options & PR_O_BIND_SRC) {
6069 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
6070 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
6071 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
6072 s->proxy->id);
6073 s->result = -1;
6074 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006075 }
willy tarreau0174f312005-12-18 01:02:42 +01006076
6077 if (!s->result) {
6078 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
6079 /* OK, connection in progress or established */
6080
6081 //fprintf(stderr, "process_chk: 4\n");
6082
6083 s->curfd = fd; /* that's how we know a test is in progress ;-) */
6084 fdtab[fd].owner = t;
6085 fdtab[fd].read = &event_srv_chk_r;
6086 fdtab[fd].write = &event_srv_chk_w;
6087 fdtab[fd].state = FD_STCONN; /* connection in progress */
6088 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01006089#ifdef DEBUG_FULL
6090 assert (!FD_ISSET(fd, StaticReadEvent));
6091#endif
willy tarreau0174f312005-12-18 01:02:42 +01006092 fd_insert(fd);
6093 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
6094 tv_delayfrom(&t->expire, &now, s->inter);
6095 task_queue(t); /* restore t to its place in the task list */
6096 return tv_remain(&now, &t->expire);
6097 }
6098 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
6099 s->result = -1; /* a real error */
6100 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006101 }
6102 }
willy tarreau08dedbe2005-12-18 01:13:48 +01006103 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006104 }
6105
6106 if (!s->result) { /* nothing done */
6107 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01006108 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6109 tv_delayfrom(&t->expire, &t->expire, s->inter);
6110 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006111 }
6112
6113 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01006114 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006115 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006116 else
6117 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006118
6119 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01006120 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01006121 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6122 tv_delayfrom(&t->expire, &t->expire, s->inter);
6123 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006124 }
6125 else {
6126 //fprintf(stderr, "process_chk: 8\n");
6127 /* there was a test running */
6128 if (s->result > 0) { /* good server detected */
6129 //fprintf(stderr, "process_chk: 9\n");
6130 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01006131 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02006132 s->state |= SRV_RUNNING;
6133
willy tarreau535ae7a2005-12-17 12:58:00 +01006134 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02006135 int xferred;
6136
willy tarreau62084d42006-03-24 18:57:41 +01006137 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02006138 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02006139
6140 /* check if we can handle some connections queued at the proxy. We
6141 * will take as many as we can handle.
6142 */
6143 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
6144 struct session *sess;
6145 struct pendconn *p;
6146
6147 p = pendconn_from_px(s->proxy);
6148 if (!p)
6149 break;
6150 p->sess->srv = s;
6151 sess = p->sess;
6152 pendconn_free(p);
6153 task_wakeup(&rq, sess->task);
6154 }
6155
6156 sprintf(trash,
6157 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6158 " %d sessions requeued, %d total in queue.\n",
6159 s->state & SRV_BACKUP ? "Backup " : "",
6160 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6161 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6162 xferred, s->nbpend);
6163
6164 Warning("%s", trash);
6165 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006166 }
willy tarreauef900ab2005-12-17 12:52:52 +01006167
willy tarreaue47c8d72005-12-17 12:55:52 +01006168 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006169 }
willy tarreauef900ab2005-12-17 12:52:52 +01006170 s->curfd = -1; /* no check running anymore */
6171 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006172 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006173 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6174 tv_delayfrom(&t->expire, &t->expire, s->inter);
6175 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006176 }
6177 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6178 //fprintf(stderr, "process_chk: 10\n");
6179 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01006180 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006181 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006182 else
6183 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006184 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006185 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006186 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006187 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6188 tv_delayfrom(&t->expire, &t->expire, s->inter);
6189 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006190 }
6191 /* if result is 0 and there's no timeout, we have to wait again */
6192 }
6193 //fprintf(stderr, "process_chk: 11\n");
6194 s->result = 0;
6195 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006196 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006197}
6198
6199
willy tarreau5cbea6f2005-12-17 12:48:26 +01006200
willy tarreau59a6cc22006-05-12 01:29:08 +02006201/*
6202 * Manages a server's connection queue. If woken up, will try to dequeue as
6203 * many pending sessions as possible, and wake them up. The task has nothing
6204 * else to do, so it always returns TIME_ETERNITY.
6205 */
6206int process_srv_queue(struct task *t) {
6207 struct server *s = (struct server*)t->context;
6208 struct proxy *p = s->proxy;
6209 int xferred;
6210
6211 /* First, check if we can handle some connections queued at the proxy. We
6212 * will take as many as we can handle.
6213 */
6214 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6215 struct session *sess;
6216
6217 sess = pendconn_get_next_sess(s, p);
6218 if (sess == NULL)
6219 break;
6220 task_wakeup(&rq, sess->task);
6221 }
6222
6223 return TIME_ETERNITY;
6224}
6225
willy tarreau0f7af912005-12-17 12:21:26 +01006226#if STATTIME > 0
6227int stats(void);
6228#endif
6229
6230/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006231 * This does 4 things :
6232 * - wake up all expired tasks
6233 * - call all runnable tasks
6234 * - call maintain_proxies() to enable/disable the listeners
6235 * - return the delay till next event in ms, -1 = wait indefinitely
6236 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6237 *
willy tarreau0f7af912005-12-17 12:21:26 +01006238 */
6239
willy tarreau1c2ad212005-12-18 01:11:29 +01006240int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006241 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006242 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006243 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006244
willy tarreaub952e1d2005-12-18 01:31:20 +01006245 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006246
willy tarreau1c2ad212005-12-18 01:11:29 +01006247 /* look for expired tasks and add them to the run queue.
6248 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006249 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6250 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006251 tnext = t->next;
6252 if (t->state & TASK_RUNNING)
6253 continue;
6254
willy tarreaub952e1d2005-12-18 01:31:20 +01006255 if (tv_iseternity(&t->expire))
6256 continue;
6257
willy tarreau1c2ad212005-12-18 01:11:29 +01006258 /* wakeup expired entries. It doesn't matter if they are
6259 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006260 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006261 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006262 task_wakeup(&rq, t);
6263 }
6264 else {
6265 /* first non-runnable task. Use its expiration date as an upper bound */
6266 int temp_time = tv_remain(&now, &t->expire);
6267 if (temp_time)
6268 next_time = temp_time;
6269 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006270 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006271 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006272
willy tarreau1c2ad212005-12-18 01:11:29 +01006273 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006274 * since we only use the run queue's head. Note that any task can be
6275 * woken up by any other task and it will be processed immediately
6276 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006277 */
willy tarreau7feab592006-04-22 15:13:16 +02006278 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006279 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006280
willy tarreau1c2ad212005-12-18 01:11:29 +01006281 task_sleep(&rq, t);
6282 temp_time = t->process(t);
6283 next_time = MINTIME(temp_time, next_time);
6284 }
6285
6286 /* maintain all proxies in a consistent state. This should quickly become a task */
6287 time2 = maintain_proxies();
6288 return MINTIME(time2, next_time);
6289}
6290
6291
6292#if defined(ENABLE_EPOLL)
6293
6294/*
6295 * Main epoll() loop.
6296 */
6297
6298/* does 3 actions :
6299 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6300 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6301 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6302 *
6303 * returns 0 if initialization failed, !0 otherwise.
6304 */
6305
6306int epoll_loop(int action) {
6307 int next_time;
6308 int status;
6309 int fd;
6310
6311 int fds, count;
6312 int pr, pw, sr, sw;
6313 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6314 struct epoll_event ev;
6315
6316 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006317 static struct epoll_event *epoll_events = NULL;
6318 static int epoll_fd;
6319
6320 if (action == POLL_LOOP_ACTION_INIT) {
6321 epoll_fd = epoll_create(global.maxsock + 1);
6322 if (epoll_fd < 0)
6323 return 0;
6324 else {
6325 epoll_events = (struct epoll_event*)
6326 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6327 PrevReadEvent = (fd_set *)
6328 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6329 PrevWriteEvent = (fd_set *)
6330 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006331 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006332 return 1;
6333 }
6334 else if (action == POLL_LOOP_ACTION_CLEAN) {
6335 if (PrevWriteEvent) free(PrevWriteEvent);
6336 if (PrevReadEvent) free(PrevReadEvent);
6337 if (epoll_events) free(epoll_events);
6338 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006339 epoll_fd = 0;
6340 return 1;
6341 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006342
willy tarreau1c2ad212005-12-18 01:11:29 +01006343 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006344
willy tarreau1c2ad212005-12-18 01:11:29 +01006345 tv_now(&now);
6346
6347 while (1) {
6348 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006349
6350 /* stop when there's no connection left and we don't allow them anymore */
6351 if (!actconn && listeners == 0)
6352 break;
6353
willy tarreau0f7af912005-12-17 12:21:26 +01006354#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006355 {
6356 int time2;
6357 time2 = stats();
6358 next_time = MINTIME(time2, next_time);
6359 }
willy tarreau0f7af912005-12-17 12:21:26 +01006360#endif
6361
willy tarreau1c2ad212005-12-18 01:11:29 +01006362 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6363
6364 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6365 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6366
6367 if ((ro^rn) | (wo^wn)) {
6368 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6369#define FDSETS_ARE_INT_ALIGNED
6370#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006371
willy tarreauad90a0c2005-12-18 01:09:15 +01006372#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6373#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006374 pr = (ro >> count) & 1;
6375 pw = (wo >> count) & 1;
6376 sr = (rn >> count) & 1;
6377 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006378#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006379 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6380 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6381 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6382 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006383#endif
6384#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006385 pr = FD_ISSET(fd, PrevReadEvent);
6386 pw = FD_ISSET(fd, PrevWriteEvent);
6387 sr = FD_ISSET(fd, StaticReadEvent);
6388 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006389#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006390 if (!((sr^pr) | (sw^pw)))
6391 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006392
willy tarreau1c2ad212005-12-18 01:11:29 +01006393 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6394 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006395
willy tarreaub952e1d2005-12-18 01:31:20 +01006396#ifdef EPOLL_CTL_MOD_WORKAROUND
6397 /* I encountered a rarely reproducible problem with
6398 * EPOLL_CTL_MOD where a modified FD (systematically
6399 * the one in epoll_events[0], fd#7) would sometimes
6400 * be set EPOLL_OUT while asked for a read ! This is
6401 * with the 2.4 epoll patch. The workaround is to
6402 * delete then recreate in case of modification.
6403 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6404 * nor RHEL kernels.
6405 */
6406
6407 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6408 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6409
6410 if ((sr | sw))
6411 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6412#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006413 if ((pr | pw)) {
6414 /* the file-descriptor already exists... */
6415 if ((sr | sw)) {
6416 /* ...and it will still exist */
6417 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6418 // perror("epoll_ctl(MOD)");
6419 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006420 }
6421 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006422 /* ...and it will be removed */
6423 if (fdtab[fd].state != FD_STCLOSE &&
6424 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6425 // perror("epoll_ctl(DEL)");
6426 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006427 }
6428 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006429 } else {
6430 /* the file-descriptor did not exist, let's add it */
6431 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6432 // perror("epoll_ctl(ADD)");
6433 // exit(1);
6434 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006435 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006436#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006437 }
6438 ((int*)PrevReadEvent)[fds] = rn;
6439 ((int*)PrevWriteEvent)[fds] = wn;
6440 }
6441 }
6442
6443 /* now let's wait for events */
6444 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6445 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006446
willy tarreau1c2ad212005-12-18 01:11:29 +01006447 for (count = 0; count < status; count++) {
6448 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006449
6450 if (FD_ISSET(fd, StaticReadEvent)) {
6451 if (fdtab[fd].state == FD_STCLOSE)
6452 continue;
6453 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6454 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006455 }
willy tarreau05be12b2006-03-19 19:35:00 +01006456
6457 if (FD_ISSET(fd, StaticWriteEvent)) {
6458 if (fdtab[fd].state == FD_STCLOSE)
6459 continue;
6460 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6461 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006462 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006463 }
6464 }
6465 return 1;
6466}
6467#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006468
willy tarreauad90a0c2005-12-18 01:09:15 +01006469
willy tarreau5cbea6f2005-12-17 12:48:26 +01006470
willy tarreau1c2ad212005-12-18 01:11:29 +01006471#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006472
willy tarreau1c2ad212005-12-18 01:11:29 +01006473/*
6474 * Main poll() loop.
6475 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006476
willy tarreau1c2ad212005-12-18 01:11:29 +01006477/* does 3 actions :
6478 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6479 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6480 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6481 *
6482 * returns 0 if initialization failed, !0 otherwise.
6483 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006484
willy tarreau1c2ad212005-12-18 01:11:29 +01006485int poll_loop(int action) {
6486 int next_time;
6487 int status;
6488 int fd, nbfd;
6489
6490 int fds, count;
6491 int sr, sw;
6492 unsigned rn, wn; /* read new, write new */
6493
6494 /* private data */
6495 static struct pollfd *poll_events = NULL;
6496
6497 if (action == POLL_LOOP_ACTION_INIT) {
6498 poll_events = (struct pollfd*)
6499 calloc(1, sizeof(struct pollfd) * global.maxsock);
6500 return 1;
6501 }
6502 else if (action == POLL_LOOP_ACTION_CLEAN) {
6503 if (poll_events)
6504 free(poll_events);
6505 return 1;
6506 }
6507
6508 /* OK, it's POLL_LOOP_ACTION_RUN */
6509
6510 tv_now(&now);
6511
6512 while (1) {
6513 next_time = process_runnable_tasks();
6514
6515 /* stop when there's no connection left and we don't allow them anymore */
6516 if (!actconn && listeners == 0)
6517 break;
6518
6519#if STATTIME > 0
6520 {
6521 int time2;
6522 time2 = stats();
6523 next_time = MINTIME(time2, next_time);
6524 }
6525#endif
6526
6527
6528 nbfd = 0;
6529 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6530
6531 rn = ((int*)StaticReadEvent)[fds];
6532 wn = ((int*)StaticWriteEvent)[fds];
6533
6534 if ((rn|wn)) {
6535 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6536#define FDSETS_ARE_INT_ALIGNED
6537#ifdef FDSETS_ARE_INT_ALIGNED
6538
6539#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6540#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6541 sr = (rn >> count) & 1;
6542 sw = (wn >> count) & 1;
6543#else
6544 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6545 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6546#endif
6547#else
6548 sr = FD_ISSET(fd, StaticReadEvent);
6549 sw = FD_ISSET(fd, StaticWriteEvent);
6550#endif
6551 if ((sr|sw)) {
6552 poll_events[nbfd].fd = fd;
6553 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6554 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006555 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006556 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006557 }
6558 }
6559
6560 /* now let's wait for events */
6561 status = poll(poll_events, nbfd, next_time);
6562 tv_now(&now);
6563
6564 for (count = 0; status > 0 && count < nbfd; count++) {
6565 fd = poll_events[count].fd;
6566
6567 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6568 continue;
6569
6570 /* ok, we found one active fd */
6571 status--;
6572
willy tarreau05be12b2006-03-19 19:35:00 +01006573 if (FD_ISSET(fd, StaticReadEvent)) {
6574 if (fdtab[fd].state == FD_STCLOSE)
6575 continue;
6576 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6577 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006578 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006579
willy tarreau05be12b2006-03-19 19:35:00 +01006580 if (FD_ISSET(fd, StaticWriteEvent)) {
6581 if (fdtab[fd].state == FD_STCLOSE)
6582 continue;
6583 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6584 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006585 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006586 }
6587 }
6588 return 1;
6589}
willy tarreauad90a0c2005-12-18 01:09:15 +01006590#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006591
willy tarreauad90a0c2005-12-18 01:09:15 +01006592
willy tarreauad90a0c2005-12-18 01:09:15 +01006593
willy tarreau1c2ad212005-12-18 01:11:29 +01006594/*
6595 * Main select() loop.
6596 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006597
willy tarreau1c2ad212005-12-18 01:11:29 +01006598/* does 3 actions :
6599 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6600 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6601 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6602 *
6603 * returns 0 if initialization failed, !0 otherwise.
6604 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006605
willy tarreauad90a0c2005-12-18 01:09:15 +01006606
willy tarreau1c2ad212005-12-18 01:11:29 +01006607int select_loop(int action) {
6608 int next_time;
6609 int status;
6610 int fd,i;
6611 struct timeval delta;
6612 int readnotnull, writenotnull;
6613 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006614
willy tarreau1c2ad212005-12-18 01:11:29 +01006615 if (action == POLL_LOOP_ACTION_INIT) {
6616 ReadEvent = (fd_set *)
6617 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6618 WriteEvent = (fd_set *)
6619 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6620 return 1;
6621 }
6622 else if (action == POLL_LOOP_ACTION_CLEAN) {
6623 if (WriteEvent) free(WriteEvent);
6624 if (ReadEvent) free(ReadEvent);
6625 return 1;
6626 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006627
willy tarreau1c2ad212005-12-18 01:11:29 +01006628 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006629
willy tarreau1c2ad212005-12-18 01:11:29 +01006630 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006631
willy tarreau1c2ad212005-12-18 01:11:29 +01006632 while (1) {
6633 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006634
willy tarreau1c2ad212005-12-18 01:11:29 +01006635 /* stop when there's no connection left and we don't allow them anymore */
6636 if (!actconn && listeners == 0)
6637 break;
6638
6639#if STATTIME > 0
6640 {
6641 int time2;
6642 time2 = stats();
6643 next_time = MINTIME(time2, next_time);
6644 }
6645#endif
6646
willy tarreau1c2ad212005-12-18 01:11:29 +01006647 if (next_time > 0) { /* FIXME */
6648 /* Convert to timeval */
6649 /* to avoid eventual select loops due to timer precision */
6650 next_time += SCHEDULER_RESOLUTION;
6651 delta.tv_sec = next_time / 1000;
6652 delta.tv_usec = (next_time % 1000) * 1000;
6653 }
6654 else if (next_time == 0) { /* allow select to return immediately when needed */
6655 delta.tv_sec = delta.tv_usec = 0;
6656 }
6657
6658
6659 /* let's restore fdset state */
6660
6661 readnotnull = 0; writenotnull = 0;
6662 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6663 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6664 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6665 }
6666
6667 // /* just a verification code, needs to be removed for performance */
6668 // for (i=0; i<maxfd; i++) {
6669 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6670 // abort();
6671 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6672 // abort();
6673 //
6674 // }
6675
6676 status = select(maxfd,
6677 readnotnull ? ReadEvent : NULL,
6678 writenotnull ? WriteEvent : NULL,
6679 NULL,
6680 (next_time >= 0) ? &delta : NULL);
6681
6682 /* this is an experiment on the separation of the select work */
6683 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6684 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6685
6686 tv_now(&now);
6687
6688 if (status > 0) { /* must proceed with events */
6689
6690 int fds;
6691 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006692
willy tarreau1c2ad212005-12-18 01:11:29 +01006693 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6694 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6695 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6696
6697 /* if we specify read first, the accepts and zero reads will be
6698 * seen first. Moreover, system buffers will be flushed faster.
6699 */
willy tarreau05be12b2006-03-19 19:35:00 +01006700 if (FD_ISSET(fd, ReadEvent)) {
6701 if (fdtab[fd].state == FD_STCLOSE)
6702 continue;
6703 fdtab[fd].read(fd);
6704 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006705
willy tarreau05be12b2006-03-19 19:35:00 +01006706 if (FD_ISSET(fd, WriteEvent)) {
6707 if (fdtab[fd].state == FD_STCLOSE)
6708 continue;
6709 fdtab[fd].write(fd);
6710 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006711 }
6712 }
6713 else {
6714 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006715 }
willy tarreau0f7af912005-12-17 12:21:26 +01006716 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006717 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006718}
6719
6720
6721#if STATTIME > 0
6722/*
6723 * Display proxy statistics regularly. It is designed to be called from the
6724 * select_loop().
6725 */
6726int stats(void) {
6727 static int lines;
6728 static struct timeval nextevt;
6729 static struct timeval lastevt;
6730 static struct timeval starttime = {0,0};
6731 unsigned long totaltime, deltatime;
6732 int ret;
6733
willy tarreau750a4722005-12-17 13:21:24 +01006734 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006735 deltatime = (tv_diff(&lastevt, &now)?:1);
6736 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006737
willy tarreau9fe663a2005-12-17 13:02:59 +01006738 if (global.mode & MODE_STATS) {
6739 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006740 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006741 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6742 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006743 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006744 actconn, totalconn,
6745 stats_tsk_new, stats_tsk_good,
6746 stats_tsk_left, stats_tsk_right,
6747 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6748 }
6749 }
6750
6751 tv_delayfrom(&nextevt, &now, STATTIME);
6752
6753 lastevt=now;
6754 }
6755 ret = tv_remain(&now, &nextevt);
6756 return ret;
6757}
6758#endif
6759
6760
6761/*
6762 * this function enables proxies when there are enough free sessions,
6763 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006764 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006765 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006766 */
6767static int maintain_proxies(void) {
6768 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006769 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006770 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006771
6772 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006773 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006774
6775 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006776 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006777 while (p) {
6778 if (p->nbconn < p->maxconn) {
6779 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006780 for (l = p->listen; l != NULL; l = l->next) {
6781 FD_SET(l->fd, StaticReadEvent);
6782 }
willy tarreau0f7af912005-12-17 12:21:26 +01006783 p->state = PR_STRUN;
6784 }
6785 }
6786 else {
6787 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006788 for (l = p->listen; l != NULL; l = l->next) {
6789 FD_CLR(l->fd, StaticReadEvent);
6790 }
willy tarreau0f7af912005-12-17 12:21:26 +01006791 p->state = PR_STIDLE;
6792 }
6793 }
6794 p = p->next;
6795 }
6796 }
6797 else { /* block all proxies */
6798 while (p) {
6799 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006800 for (l = p->listen; l != NULL; l = l->next) {
6801 FD_CLR(l->fd, StaticReadEvent);
6802 }
willy tarreau0f7af912005-12-17 12:21:26 +01006803 p->state = PR_STIDLE;
6804 }
6805 p = p->next;
6806 }
6807 }
6808
willy tarreau5cbea6f2005-12-17 12:48:26 +01006809 if (stopping) {
6810 p = proxy;
6811 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006812 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006813 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006814 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006815 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006816 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006817 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006818
willy tarreaua41a8b42005-12-17 14:02:24 +01006819 for (l = p->listen; l != NULL; l = l->next) {
6820 fd_delete(l->fd);
6821 listeners--;
6822 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006823 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006824 }
6825 else {
6826 tleft = MINTIME(t, tleft);
6827 }
6828 }
6829 p = p->next;
6830 }
6831 }
6832 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006833}
6834
6835/*
6836 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006837 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6838 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006839 */
6840static void soft_stop(void) {
6841 struct proxy *p;
6842
6843 stopping = 1;
6844 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006845 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006846 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006847 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006848 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006849 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006850 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006851 }
willy tarreau0f7af912005-12-17 12:21:26 +01006852 p = p->next;
6853 }
6854}
6855
willy tarreaudbd3bef2006-01-20 19:35:18 +01006856static void pause_proxy(struct proxy *p) {
6857 struct listener *l;
6858 for (l = p->listen; l != NULL; l = l->next) {
Willy TARREAU007aa462006-05-14 09:55:23 +02006859 if (shutdown(l->fd, SHUT_RD) == 0) {
6860 FD_CLR(l->fd, StaticReadEvent);
6861 p->state = PR_STPAUSED;
6862 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006863 }
6864}
6865
6866/*
6867 * This function temporarily disables listening so that another new instance
6868 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006869 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006870 * the proxy, or a SIGTTIN can be sent to listen again.
6871 */
6872static void pause_proxies(void) {
Willy TARREAU007aa462006-05-14 09:55:23 +02006873 int err;
willy tarreaudbd3bef2006-01-20 19:35:18 +01006874 struct proxy *p;
6875
Willy TARREAU007aa462006-05-14 09:55:23 +02006876 err = 0;
willy tarreaudbd3bef2006-01-20 19:35:18 +01006877 p = proxy;
6878 tv_now(&now); /* else, the old time before select will be used */
6879 while (p) {
6880 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6881 Warning("Pausing proxy %s.\n", p->id);
6882 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6883 pause_proxy(p);
Willy TARREAU007aa462006-05-14 09:55:23 +02006884 if (p->state != PR_STPAUSED) {
6885 err |= 1;
6886 Warning("Proxy %s failed to enter pause mode.\n", p->id);
6887 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
6888 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006889 }
6890 p = p->next;
6891 }
Willy TARREAU007aa462006-05-14 09:55:23 +02006892 if (err) {
6893 Warning("Some proxies refused to pause, performing soft stop now.\n");
6894 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
6895 soft_stop();
6896 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006897}
6898
6899
6900/*
6901 * This function reactivates listening. This can be used after a call to
6902 * sig_pause(), for example when a new instance has failed starting up.
6903 * It is designed to be called upon reception of a SIGTTIN.
6904 */
6905static void listen_proxies(void) {
6906 struct proxy *p;
6907 struct listener *l;
6908
6909 p = proxy;
6910 tv_now(&now); /* else, the old time before select will be used */
6911 while (p) {
6912 if (p->state == PR_STPAUSED) {
6913 Warning("Enabling proxy %s.\n", p->id);
6914 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6915
6916 for (l = p->listen; l != NULL; l = l->next) {
6917 if (listen(l->fd, p->maxconn) == 0) {
6918 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6919 FD_SET(l->fd, StaticReadEvent);
6920 p->state = PR_STRUN;
6921 }
6922 else
6923 p->state = PR_STIDLE;
6924 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006925 int port;
6926
6927 if (l->addr.ss_family == AF_INET6)
6928 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6929 else
6930 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6931
willy tarreaudbd3bef2006-01-20 19:35:18 +01006932 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006933 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006934 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006935 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006936 /* Another port might have been enabled. Let's stop everything. */
6937 pause_proxy(p);
6938 break;
6939 }
6940 }
6941 }
6942 p = p->next;
6943 }
6944}
6945
6946
willy tarreau0f7af912005-12-17 12:21:26 +01006947/*
6948 * upon SIGUSR1, let's have a soft stop.
6949 */
6950void sig_soft_stop(int sig) {
6951 soft_stop();
6952 signal(sig, SIG_IGN);
6953}
6954
willy tarreaudbd3bef2006-01-20 19:35:18 +01006955/*
6956 * upon SIGTTOU, we pause everything
6957 */
6958void sig_pause(int sig) {
6959 pause_proxies();
6960 signal(sig, sig_pause);
6961}
willy tarreau0f7af912005-12-17 12:21:26 +01006962
willy tarreau8337c6b2005-12-17 13:41:01 +01006963/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006964 * upon SIGTTIN, let's have a soft stop.
6965 */
6966void sig_listen(int sig) {
6967 listen_proxies();
6968 signal(sig, sig_listen);
6969}
6970
6971/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006972 * this function dumps every server's state when the process receives SIGHUP.
6973 */
6974void sig_dump_state(int sig) {
6975 struct proxy *p = proxy;
6976
6977 Warning("SIGHUP received, dumping servers states.\n");
6978 while (p) {
6979 struct server *s = p->srv;
6980
willy tarreau4632c212006-05-02 23:32:51 +02006981 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006982 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02006983 snprintf(trash, sizeof(trash),
6984 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
6985 p->id, s->id,
6986 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
6987 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02006988 Warning("%s\n", trash);
6989 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006990 s = s->next;
6991 }
willy tarreaudd07e972005-12-18 00:48:48 +01006992
willy tarreau62084d42006-03-24 18:57:41 +01006993 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02006994 snprintf(trash, sizeof(trash),
6995 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
6996 p->id,
6997 (p->srv_bck) ? "is running on backup servers" : "has no server available",
6998 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006999 } else {
7000 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02007001 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
7002 " Conn: %d act, %d pend (%d unass), %d tot.",
7003 p->id, p->srv_act, p->srv_bck,
7004 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02007005 }
7006 Warning("%s\n", trash);
7007 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01007008
willy tarreau8337c6b2005-12-17 13:41:01 +01007009 p = p->next;
7010 }
7011 signal(sig, sig_dump_state);
7012}
7013
willy tarreau0f7af912005-12-17 12:21:26 +01007014void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007015 struct task *t, *tnext;
7016 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01007017
willy tarreau5e698ef2006-05-02 14:51:00 +02007018 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
7019 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007020 tnext = t->next;
7021 s = t->context;
7022 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
7023 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
7024 "req=%d, rep=%d, clifd=%d\n",
7025 s, tv_remain(&now, &t->expire),
7026 s->cli_state,
7027 s->srv_state,
7028 FD_ISSET(s->cli_fd, StaticReadEvent),
7029 FD_ISSET(s->cli_fd, StaticWriteEvent),
7030 FD_ISSET(s->srv_fd, StaticReadEvent),
7031 FD_ISSET(s->srv_fd, StaticWriteEvent),
7032 s->req->l, s->rep?s->rep->l:0, s->cli_fd
7033 );
willy tarreau0f7af912005-12-17 12:21:26 +01007034 }
willy tarreau12350152005-12-18 01:03:27 +01007035}
7036
willy tarreau64a3cc32005-12-18 01:13:11 +01007037#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007038static void fast_stop(void)
7039{
7040 struct proxy *p;
7041 p = proxy;
7042 while (p) {
7043 p->grace = 0;
7044 p = p->next;
7045 }
7046 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01007047}
7048
willy tarreau12350152005-12-18 01:03:27 +01007049void sig_int(int sig) {
7050 /* This would normally be a hard stop,
7051 but we want to be sure about deallocation,
7052 and so on, so we do a soft stop with
7053 0 GRACE time
7054 */
7055 fast_stop();
7056 /* If we are killed twice, we decide to die*/
7057 signal(sig, SIG_DFL);
7058}
7059
7060void sig_term(int sig) {
7061 /* This would normally be a hard stop,
7062 but we want to be sure about deallocation,
7063 and so on, so we do a soft stop with
7064 0 GRACE time
7065 */
7066 fast_stop();
7067 /* If we are killed twice, we decide to die*/
7068 signal(sig, SIG_DFL);
7069}
willy tarreau64a3cc32005-12-18 01:13:11 +01007070#endif
willy tarreau12350152005-12-18 01:03:27 +01007071
willy tarreauc1f47532005-12-18 01:08:26 +01007072/* returns the pointer to an error in the replacement string, or NULL if OK */
7073char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01007074 struct hdr_exp *exp;
7075
willy tarreauc1f47532005-12-18 01:08:26 +01007076 if (replace != NULL) {
7077 char *err;
7078 err = check_replace_string(replace);
7079 if (err)
7080 return err;
7081 }
7082
willy tarreaue39cd132005-12-17 13:00:18 +01007083 while (*head != NULL)
7084 head = &(*head)->next;
7085
7086 exp = calloc(1, sizeof(struct hdr_exp));
7087
7088 exp->preg = preg;
7089 exp->replace = replace;
7090 exp->action = action;
7091 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01007092
7093 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007094}
7095
willy tarreau9fe663a2005-12-17 13:02:59 +01007096
willy tarreau0f7af912005-12-17 12:21:26 +01007097/*
willy tarreau9fe663a2005-12-17 13:02:59 +01007098 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01007099 */
willy tarreau9fe663a2005-12-17 13:02:59 +01007100int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01007101
willy tarreau9fe663a2005-12-17 13:02:59 +01007102 if (!strcmp(args[0], "global")) { /* new section */
7103 /* no option, nothing special to do */
7104 return 0;
7105 }
7106 else if (!strcmp(args[0], "daemon")) {
7107 global.mode |= MODE_DAEMON;
7108 }
7109 else if (!strcmp(args[0], "debug")) {
7110 global.mode |= MODE_DEBUG;
7111 }
willy tarreau64a3cc32005-12-18 01:13:11 +01007112 else if (!strcmp(args[0], "noepoll")) {
7113 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
7114 }
7115 else if (!strcmp(args[0], "nopoll")) {
7116 cfg_polling_mechanism &= ~POLL_USE_POLL;
7117 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007118 else if (!strcmp(args[0], "quiet")) {
7119 global.mode |= MODE_QUIET;
7120 }
7121 else if (!strcmp(args[0], "stats")) {
7122 global.mode |= MODE_STATS;
7123 }
7124 else if (!strcmp(args[0], "uid")) {
7125 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007126 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007127 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007128 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007129 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007130 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007131 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007132 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007133 global.uid = atol(args[1]);
7134 }
7135 else if (!strcmp(args[0], "gid")) {
7136 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007137 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007138 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007139 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007140 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007141 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007142 return -1;
7143 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007144 global.gid = atol(args[1]);
7145 }
7146 else if (!strcmp(args[0], "nbproc")) {
7147 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007148 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007149 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007150 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007151 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007152 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007153 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007154 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007155 global.nbproc = atol(args[1]);
7156 }
7157 else if (!strcmp(args[0], "maxconn")) {
7158 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007159 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007160 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007161 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007162 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007163 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007164 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007165 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007166 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007167#ifdef SYSTEM_MAXCONN
7168 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7169 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);
7170 global.maxconn = DEFAULT_MAXCONN;
7171 }
7172#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007173 }
willy tarreaub1285d52005-12-18 01:20:14 +01007174 else if (!strcmp(args[0], "ulimit-n")) {
7175 if (global.rlimit_nofile != 0) {
7176 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7177 return 0;
7178 }
7179 if (*(args[1]) == 0) {
7180 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7181 return -1;
7182 }
7183 global.rlimit_nofile = atol(args[1]);
7184 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007185 else if (!strcmp(args[0], "chroot")) {
7186 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007187 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007188 return 0;
7189 }
7190 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007191 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007192 return -1;
7193 }
7194 global.chroot = strdup(args[1]);
7195 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007196 else if (!strcmp(args[0], "pidfile")) {
7197 if (global.pidfile != NULL) {
7198 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7199 return 0;
7200 }
7201 if (*(args[1]) == 0) {
7202 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7203 return -1;
7204 }
7205 global.pidfile = strdup(args[1]);
7206 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007207 else if (!strcmp(args[0], "log")) { /* syslog server address */
7208 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007209 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007210
7211 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007212 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007213 return -1;
7214 }
7215
7216 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7217 if (!strcmp(log_facilities[facility], args[2]))
7218 break;
7219
7220 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007221 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007222 exit(1);
7223 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007224
7225 level = 7; /* max syslog level = debug */
7226 if (*(args[3])) {
7227 while (level >= 0 && strcmp(log_levels[level], args[3]))
7228 level--;
7229 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007230 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007231 exit(1);
7232 }
7233 }
7234
willy tarreau9fe663a2005-12-17 13:02:59 +01007235 sa = str2sa(args[1]);
7236 if (!sa->sin_port)
7237 sa->sin_port = htons(SYSLOG_PORT);
7238
7239 if (global.logfac1 == -1) {
7240 global.logsrv1 = *sa;
7241 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007242 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007243 }
7244 else if (global.logfac2 == -1) {
7245 global.logsrv2 = *sa;
7246 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007247 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007248 }
7249 else {
7250 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7251 return -1;
7252 }
7253
7254 }
7255 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007256 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007257 return -1;
7258 }
7259 return 0;
7260}
7261
7262
willy tarreaua41a8b42005-12-17 14:02:24 +01007263void init_default_instance() {
7264 memset(&defproxy, 0, sizeof(defproxy));
7265 defproxy.mode = PR_MODE_TCP;
7266 defproxy.state = PR_STNEW;
7267 defproxy.maxconn = cfg_maxpconn;
7268 defproxy.conn_retries = CONN_RETRIES;
7269 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7270}
7271
willy tarreau9fe663a2005-12-17 13:02:59 +01007272/*
7273 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7274 */
7275int cfg_parse_listen(char *file, int linenum, char **args) {
7276 static struct proxy *curproxy = NULL;
7277 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007278 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007279 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007280
7281 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007282 if (!*args[1]) {
7283 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7284 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007285 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007286 return -1;
7287 }
7288
7289 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007290 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007291 return -1;
7292 }
willy tarreaudfece232006-05-02 00:19:57 +02007293
willy tarreau9fe663a2005-12-17 13:02:59 +01007294 curproxy->next = proxy;
7295 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007296 LIST_INIT(&curproxy->pendconns);
7297
willy tarreau9fe663a2005-12-17 13:02:59 +01007298 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007299
7300 /* parse the listener address if any */
7301 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007302 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007303 if (!curproxy->listen)
7304 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007305 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007306 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007307
willy tarreau9fe663a2005-12-17 13:02:59 +01007308 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007309 curproxy->state = defproxy.state;
7310 curproxy->maxconn = defproxy.maxconn;
7311 curproxy->conn_retries = defproxy.conn_retries;
7312 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007313
7314 if (defproxy.check_req)
7315 curproxy->check_req = strdup(defproxy.check_req);
7316 curproxy->check_len = defproxy.check_len;
7317
7318 if (defproxy.cookie_name)
7319 curproxy->cookie_name = strdup(defproxy.cookie_name);
7320 curproxy->cookie_len = defproxy.cookie_len;
7321
7322 if (defproxy.capture_name)
7323 curproxy->capture_name = strdup(defproxy.capture_name);
7324 curproxy->capture_namelen = defproxy.capture_namelen;
7325 curproxy->capture_len = defproxy.capture_len;
7326
7327 if (defproxy.errmsg.msg400)
7328 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7329 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7330
7331 if (defproxy.errmsg.msg403)
7332 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7333 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7334
7335 if (defproxy.errmsg.msg408)
7336 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7337 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7338
7339 if (defproxy.errmsg.msg500)
7340 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7341 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7342
7343 if (defproxy.errmsg.msg502)
7344 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7345 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7346
7347 if (defproxy.errmsg.msg503)
7348 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7349 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7350
7351 if (defproxy.errmsg.msg504)
7352 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7353 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7354
willy tarreaua41a8b42005-12-17 14:02:24 +01007355 curproxy->clitimeout = defproxy.clitimeout;
7356 curproxy->contimeout = defproxy.contimeout;
7357 curproxy->srvtimeout = defproxy.srvtimeout;
7358 curproxy->mode = defproxy.mode;
7359 curproxy->logfac1 = defproxy.logfac1;
7360 curproxy->logsrv1 = defproxy.logsrv1;
7361 curproxy->loglev1 = defproxy.loglev1;
7362 curproxy->logfac2 = defproxy.logfac2;
7363 curproxy->logsrv2 = defproxy.logsrv2;
7364 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007365 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007366 curproxy->grace = defproxy.grace;
7367 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007368 curproxy->mon_net = defproxy.mon_net;
7369 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007370 return 0;
7371 }
7372 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007373 /* some variables may have already been initialized earlier */
7374 if (defproxy.check_req) free(defproxy.check_req);
7375 if (defproxy.cookie_name) free(defproxy.cookie_name);
7376 if (defproxy.capture_name) free(defproxy.capture_name);
7377 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7378 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7379 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7380 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7381 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7382 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7383 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7384
7385 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007386 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007387 return 0;
7388 }
7389 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007390 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007391 return -1;
7392 }
7393
willy tarreaua41a8b42005-12-17 14:02:24 +01007394 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7395 if (curproxy == &defproxy) {
7396 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7397 return -1;
7398 }
7399
7400 if (strchr(args[1], ':') == NULL) {
7401 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7402 file, linenum, args[0]);
7403 return -1;
7404 }
7405 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007406 if (!curproxy->listen)
7407 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007408 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007409 return 0;
7410 }
willy tarreaub1285d52005-12-18 01:20:14 +01007411 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7412 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7413 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7414 file, linenum, args[0]);
7415 return -1;
7416 }
7417 /* flush useless bits */
7418 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7419 return 0;
7420 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007421 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007422 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7423 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7424 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7425 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007426 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007427 return -1;
7428 }
7429 }
7430 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007431 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007432 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007433 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7434 curproxy->state = PR_STNEW;
7435 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007436 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7437 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007438// if (curproxy == &defproxy) {
7439// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7440// return -1;
7441// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007442
willy tarreau9fe663a2005-12-17 13:02:59 +01007443 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007444// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7445// file, linenum);
7446// return 0;
7447 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007448 }
7449
7450 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007451 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7452 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007453 return -1;
7454 }
7455 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007456 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007457
7458 cur_arg = 2;
7459 while (*(args[cur_arg])) {
7460 if (!strcmp(args[cur_arg], "rewrite")) {
7461 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007462 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007463 else if (!strcmp(args[cur_arg], "indirect")) {
7464 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007465 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007466 else if (!strcmp(args[cur_arg], "insert")) {
7467 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007468 }
willy tarreau240afa62005-12-17 13:14:35 +01007469 else if (!strcmp(args[cur_arg], "nocache")) {
7470 curproxy->options |= PR_O_COOK_NOC;
7471 }
willy tarreaucd878942005-12-17 13:27:43 +01007472 else if (!strcmp(args[cur_arg], "postonly")) {
7473 curproxy->options |= PR_O_COOK_POST;
7474 }
willy tarreau0174f312005-12-18 01:02:42 +01007475 else if (!strcmp(args[cur_arg], "prefix")) {
7476 curproxy->options |= PR_O_COOK_PFX;
7477 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007478 else {
willy tarreau0174f312005-12-18 01:02:42 +01007479 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007480 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007481 return -1;
7482 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007483 cur_arg++;
7484 }
willy tarreau0174f312005-12-18 01:02:42 +01007485 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7486 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7487 file, linenum);
7488 return -1;
7489 }
7490
7491 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7492 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007493 file, linenum);
7494 return -1;
7495 }
willy tarreau12350152005-12-18 01:03:27 +01007496 }/* end else if (!strcmp(args[0], "cookie")) */
7497 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7498// if (curproxy == &defproxy) {
7499// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7500// return -1;
7501// }
7502
7503 if (curproxy->appsession_name != NULL) {
7504// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7505// file, linenum);
7506// return 0;
7507 free(curproxy->appsession_name);
7508 }
7509
7510 if (*(args[5]) == 0) {
7511 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7512 file, linenum, args[0]);
7513 return -1;
7514 }
7515 have_appsession = 1;
7516 curproxy->appsession_name = strdup(args[1]);
7517 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7518 curproxy->appsession_len = atoi(args[3]);
7519 curproxy->appsession_timeout = atoi(args[5]);
7520 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7521 if (rc) {
7522 Alert("Error Init Appsession Hashtable.\n");
7523 return -1;
7524 }
7525 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007526 else if (!strcmp(args[0], "capture")) {
7527 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7528 // if (curproxy == &defproxy) {
7529 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7530 // return -1;
7531 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007532
willy tarreau4302f492005-12-18 01:00:37 +01007533 if (curproxy->capture_name != NULL) {
7534 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7535 // file, linenum, args[0]);
7536 // return 0;
7537 free(curproxy->capture_name);
7538 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007539
willy tarreau4302f492005-12-18 01:00:37 +01007540 if (*(args[4]) == 0) {
7541 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7542 file, linenum, args[0]);
7543 return -1;
7544 }
7545 curproxy->capture_name = strdup(args[2]);
7546 curproxy->capture_namelen = strlen(curproxy->capture_name);
7547 curproxy->capture_len = atol(args[4]);
7548 if (curproxy->capture_len >= CAPTURE_LEN) {
7549 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7550 file, linenum, CAPTURE_LEN - 1);
7551 curproxy->capture_len = CAPTURE_LEN - 1;
7552 }
7553 curproxy->to_log |= LW_COOKIE;
7554 }
7555 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7556 struct cap_hdr *hdr;
7557
7558 if (curproxy == &defproxy) {
7559 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7560 return -1;
7561 }
7562
7563 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7564 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7565 file, linenum, args[0], args[1]);
7566 return -1;
7567 }
7568
7569 hdr = calloc(sizeof(struct cap_hdr), 1);
7570 hdr->next = curproxy->req_cap;
7571 hdr->name = strdup(args[3]);
7572 hdr->namelen = strlen(args[3]);
7573 hdr->len = atol(args[5]);
7574 hdr->index = curproxy->nb_req_cap++;
7575 curproxy->req_cap = hdr;
7576 curproxy->to_log |= LW_REQHDR;
7577 }
7578 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7579 struct cap_hdr *hdr;
7580
7581 if (curproxy == &defproxy) {
7582 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7583 return -1;
7584 }
7585
7586 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7587 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7588 file, linenum, args[0], args[1]);
7589 return -1;
7590 }
7591 hdr = calloc(sizeof(struct cap_hdr), 1);
7592 hdr->next = curproxy->rsp_cap;
7593 hdr->name = strdup(args[3]);
7594 hdr->namelen = strlen(args[3]);
7595 hdr->len = atol(args[5]);
7596 hdr->index = curproxy->nb_rsp_cap++;
7597 curproxy->rsp_cap = hdr;
7598 curproxy->to_log |= LW_RSPHDR;
7599 }
7600 else {
7601 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007602 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007603 return -1;
7604 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007605 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007606 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007607 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007608 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007609 return 0;
7610 }
7611 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007612 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7613 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007614 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007615 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007616 curproxy->contimeout = atol(args[1]);
7617 }
7618 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007619 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007620 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7621 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007622 return 0;
7623 }
7624 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007625 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7626 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007627 return -1;
7628 }
7629 curproxy->clitimeout = atol(args[1]);
7630 }
7631 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007632 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007633 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007634 return 0;
7635 }
7636 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007637 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7638 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007639 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007640 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007641 curproxy->srvtimeout = atol(args[1]);
7642 }
7643 else if (!strcmp(args[0], "retries")) { /* connection retries */
7644 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007645 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7646 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007647 return -1;
7648 }
7649 curproxy->conn_retries = atol(args[1]);
7650 }
willy tarreau9e138862006-05-14 23:06:28 +02007651 else if (!strcmp(args[0], "stats")) {
7652 if (*(args[1]) == 0) {
7653 Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth' or 'enable'.\n", file, linenum, args[0]);
7654 return -1;
7655 } else if (!strcmp(args[1], "uri")) {
7656 if (*(args[2]) == 0) {
7657 Alert("parsing [%s:%d] : 'uri' needs an URI prefix.\n", file, linenum);
7658 return -1;
7659 } else if (!stats_set_uri(&curproxy->uri_auth, args[2])) {
7660 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7661 return -1;
7662 }
7663 } else if (!strcmp(args[1], "realm")) {
7664 if (*(args[2]) == 0) {
7665 Alert("parsing [%s:%d] : 'realm' needs an realm name.\n", file, linenum);
7666 return -1;
7667 } else if (!stats_set_realm(&curproxy->uri_auth, args[2])) {
7668 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7669 return -1;
7670 }
7671 } else if (!strcmp(args[1], "auth")) {
7672 if (*(args[2]) == 0) {
7673 Alert("parsing [%s:%d] : 'auth' needs a user:password account.\n", file, linenum);
7674 return -1;
7675 } else if (!stats_add_auth(&curproxy->uri_auth, args[2])) {
7676 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7677 return -1;
7678 }
7679 } else if (!strcmp(args[1], "enable")) {
7680 if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
7681 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7682 return -1;
7683 }
7684 } else {
7685 Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'uri', 'realm', 'auth' or 'enable').\n",
7686 file, linenum, args[0]);
7687 return -1;
7688 }
7689 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007690 else if (!strcmp(args[0], "option")) {
7691 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007692 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007693 return -1;
7694 }
7695 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007696 /* enable reconnections to dispatch */
7697 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007698#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007699 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007700 /* enable transparent proxy connections */
7701 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007702#endif
7703 else if (!strcmp(args[1], "keepalive"))
7704 /* enable keep-alive */
7705 curproxy->options |= PR_O_KEEPALIVE;
7706 else if (!strcmp(args[1], "forwardfor"))
7707 /* insert x-forwarded-for field */
7708 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007709 else if (!strcmp(args[1], "logasap"))
7710 /* log as soon as possible, without waiting for the session to complete */
7711 curproxy->options |= PR_O_LOGASAP;
7712 else if (!strcmp(args[1], "httpclose"))
7713 /* force connection: close in both directions in HTTP mode */
7714 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007715 else if (!strcmp(args[1], "forceclose"))
7716 /* force connection: close in both directions in HTTP mode and enforce end of session */
7717 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007718 else if (!strcmp(args[1], "checkcache"))
7719 /* require examination of cacheability of the 'set-cookie' field */
7720 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007721 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007722 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007723 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007724 else if (!strcmp(args[1], "tcplog"))
7725 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007726 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007727 else if (!strcmp(args[1], "dontlognull")) {
7728 /* don't log empty requests */
7729 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007730 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007731 else if (!strcmp(args[1], "tcpka")) {
7732 /* enable TCP keep-alives on client and server sessions */
7733 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7734 }
7735 else if (!strcmp(args[1], "clitcpka")) {
7736 /* enable TCP keep-alives on client sessions */
7737 curproxy->options |= PR_O_TCP_CLI_KA;
7738 }
7739 else if (!strcmp(args[1], "srvtcpka")) {
7740 /* enable TCP keep-alives on server sessions */
7741 curproxy->options |= PR_O_TCP_SRV_KA;
7742 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007743 else if (!strcmp(args[1], "allbackups")) {
7744 /* Use all backup servers simultaneously */
7745 curproxy->options |= PR_O_USE_ALL_BK;
7746 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007747 else if (!strcmp(args[1], "httpchk")) {
7748 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007749 if (curproxy->check_req != NULL) {
7750 free(curproxy->check_req);
7751 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007752 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007753 if (!*args[2]) { /* no argument */
7754 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7755 curproxy->check_len = strlen(DEF_CHECK_REQ);
7756 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007757 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7758 curproxy->check_req = (char *)malloc(reqlen);
7759 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7760 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007761 } else { /* more arguments : METHOD URI [HTTP_VER] */
7762 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7763 if (*args[4])
7764 reqlen += strlen(args[4]);
7765 else
7766 reqlen += strlen("HTTP/1.0");
7767
7768 curproxy->check_req = (char *)malloc(reqlen);
7769 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7770 "%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 +01007771 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007772 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007773 else if (!strcmp(args[1], "persist")) {
7774 /* persist on using the server specified by the cookie, even when it's down */
7775 curproxy->options |= PR_O_PERSIST;
7776 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007777 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007778 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007779 return -1;
7780 }
7781 return 0;
7782 }
7783 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7784 /* enable reconnections to dispatch */
7785 curproxy->options |= PR_O_REDISP;
7786 }
willy tarreaua1598082005-12-17 13:08:06 +01007787#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007788 else if (!strcmp(args[0], "transparent")) {
7789 /* enable transparent proxy connections */
7790 curproxy->options |= PR_O_TRANSP;
7791 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007792#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007793 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7794 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007795 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007796 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007797 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007798 curproxy->maxconn = atol(args[1]);
7799 }
7800 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7801 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007802 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007803 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007804 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007805 curproxy->grace = atol(args[1]);
7806 }
7807 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007808 if (curproxy == &defproxy) {
7809 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7810 return -1;
7811 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007812 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007813 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007814 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007815 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007816 curproxy->dispatch_addr = *str2sa(args[1]);
7817 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007818 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007819 if (*(args[1])) {
7820 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007821 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007822 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007823 else if (!strcmp(args[1], "source")) {
7824 curproxy->options |= PR_O_BALANCE_SH;
7825 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007826 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007827 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007828 return -1;
7829 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007830 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007831 else /* if no option is set, use round-robin by default */
7832 curproxy->options |= PR_O_BALANCE_RR;
7833 }
7834 else if (!strcmp(args[0], "server")) { /* server address */
7835 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007836 char *rport;
7837 char *raddr;
7838 short realport;
7839 int do_check;
7840
7841 if (curproxy == &defproxy) {
7842 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7843 return -1;
7844 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007845
willy tarreaua41a8b42005-12-17 14:02:24 +01007846 if (!*args[2]) {
7847 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007848 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007849 return -1;
7850 }
7851 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7852 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7853 return -1;
7854 }
willy tarreau0174f312005-12-18 01:02:42 +01007855
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007856 /* the servers are linked backwards first */
7857 newsrv->next = curproxy->srv;
7858 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007859 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007860
willy tarreau18a957c2006-04-12 19:26:23 +02007861 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007862 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007863 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007864 newsrv->id = strdup(args[1]);
7865
7866 /* several ways to check the port component :
7867 * - IP => port=+0, relative
7868 * - IP: => port=+0, relative
7869 * - IP:N => port=N, absolute
7870 * - IP:+N => port=+N, relative
7871 * - IP:-N => port=-N, relative
7872 */
7873 raddr = strdup(args[2]);
7874 rport = strchr(raddr, ':');
7875 if (rport) {
7876 *rport++ = 0;
7877 realport = atol(rport);
7878 if (!isdigit((int)*rport))
7879 newsrv->state |= SRV_MAPPORTS;
7880 } else {
7881 realport = 0;
7882 newsrv->state |= SRV_MAPPORTS;
7883 }
7884
7885 newsrv->addr = *str2sa(raddr);
7886 newsrv->addr.sin_port = htons(realport);
7887 free(raddr);
7888
willy tarreau9fe663a2005-12-17 13:02:59 +01007889 newsrv->curfd = -1; /* no health-check in progress */
7890 newsrv->inter = DEF_CHKINTR;
7891 newsrv->rise = DEF_RISETIME;
7892 newsrv->fall = DEF_FALLTIME;
7893 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7894 cur_arg = 3;
7895 while (*args[cur_arg]) {
7896 if (!strcmp(args[cur_arg], "cookie")) {
7897 newsrv->cookie = strdup(args[cur_arg + 1]);
7898 newsrv->cklen = strlen(args[cur_arg + 1]);
7899 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007900 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007901 else if (!strcmp(args[cur_arg], "rise")) {
7902 newsrv->rise = atol(args[cur_arg + 1]);
7903 newsrv->health = newsrv->rise;
7904 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007905 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007906 else if (!strcmp(args[cur_arg], "fall")) {
7907 newsrv->fall = atol(args[cur_arg + 1]);
7908 cur_arg += 2;
7909 }
7910 else if (!strcmp(args[cur_arg], "inter")) {
7911 newsrv->inter = atol(args[cur_arg + 1]);
7912 cur_arg += 2;
7913 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007914 else if (!strcmp(args[cur_arg], "port")) {
7915 newsrv->check_port = atol(args[cur_arg + 1]);
7916 cur_arg += 2;
7917 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007918 else if (!strcmp(args[cur_arg], "backup")) {
7919 newsrv->state |= SRV_BACKUP;
7920 cur_arg ++;
7921 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007922 else if (!strcmp(args[cur_arg], "weight")) {
7923 int w;
7924 w = atol(args[cur_arg + 1]);
7925 if (w < 1 || w > 256) {
7926 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7927 file, linenum, newsrv->id, w);
7928 return -1;
7929 }
7930 newsrv->uweight = w - 1;
7931 cur_arg += 2;
7932 }
willy tarreau18a957c2006-04-12 19:26:23 +02007933 else if (!strcmp(args[cur_arg], "maxconn")) {
7934 newsrv->maxconn = atol(args[cur_arg + 1]);
7935 cur_arg += 2;
7936 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007937 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007938 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007939 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007940 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007941 }
willy tarreau0174f312005-12-18 01:02:42 +01007942 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7943 if (!*args[cur_arg + 1]) {
7944 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7945 file, linenum, "source");
7946 return -1;
7947 }
7948 newsrv->state |= SRV_BIND_SRC;
7949 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7950 cur_arg += 2;
7951 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007952 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007953 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 +01007954 file, linenum, newsrv->id);
7955 return -1;
7956 }
7957 }
7958
7959 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007960 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7961 newsrv->check_port = realport; /* by default */
7962 if (!newsrv->check_port) {
7963 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 +01007964 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007965 return -1;
7966 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007967 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007968 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007969
willy tarreau62084d42006-03-24 18:57:41 +01007970 if (newsrv->state & SRV_BACKUP)
7971 curproxy->srv_bck++;
7972 else
7973 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007974 }
7975 else if (!strcmp(args[0], "log")) { /* syslog server address */
7976 struct sockaddr_in *sa;
7977 int facility;
7978
7979 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7980 curproxy->logfac1 = global.logfac1;
7981 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007982 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007983 curproxy->logfac2 = global.logfac2;
7984 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007985 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007986 }
7987 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007988 int level;
7989
willy tarreau0f7af912005-12-17 12:21:26 +01007990 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7991 if (!strcmp(log_facilities[facility], args[2]))
7992 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007993
willy tarreau0f7af912005-12-17 12:21:26 +01007994 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007995 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007996 exit(1);
7997 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007998
willy tarreau8337c6b2005-12-17 13:41:01 +01007999 level = 7; /* max syslog level = debug */
8000 if (*(args[3])) {
8001 while (level >= 0 && strcmp(log_levels[level], args[3]))
8002 level--;
8003 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008004 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01008005 exit(1);
8006 }
8007 }
8008
willy tarreau0f7af912005-12-17 12:21:26 +01008009 sa = str2sa(args[1]);
8010 if (!sa->sin_port)
8011 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01008012
willy tarreau0f7af912005-12-17 12:21:26 +01008013 if (curproxy->logfac1 == -1) {
8014 curproxy->logsrv1 = *sa;
8015 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008016 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008017 }
8018 else if (curproxy->logfac2 == -1) {
8019 curproxy->logsrv2 = *sa;
8020 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01008021 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01008022 }
8023 else {
8024 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01008025 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008026 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008027 }
8028 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008029 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01008030 file, linenum);
8031 return -1;
8032 }
8033 }
willy tarreaua1598082005-12-17 13:08:06 +01008034 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01008035 if (!*args[1]) {
8036 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01008037 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01008038 return -1;
8039 }
8040
8041 curproxy->source_addr = *str2sa(args[1]);
8042 curproxy->options |= PR_O_BIND_SRC;
8043 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008044 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
8045 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008046 if (curproxy == &defproxy) {
8047 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8048 return -1;
8049 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008050
8051 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008052 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8053 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008054 return -1;
8055 }
8056
8057 preg = calloc(1, sizeof(regex_t));
8058 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008059 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008060 return -1;
8061 }
8062
willy tarreauc1f47532005-12-18 01:08:26 +01008063 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8064 if (err) {
8065 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8066 file, linenum, *err);
8067 return -1;
8068 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008069 }
8070 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
8071 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008072 if (curproxy == &defproxy) {
8073 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8074 return -1;
8075 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008076
8077 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008078 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008079 return -1;
8080 }
8081
8082 preg = calloc(1, sizeof(regex_t));
8083 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008084 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008085 return -1;
8086 }
8087
8088 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8089 }
8090 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
8091 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008092 if (curproxy == &defproxy) {
8093 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8094 return -1;
8095 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008096
8097 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008098 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008099 return -1;
8100 }
8101
8102 preg = calloc(1, sizeof(regex_t));
8103 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008104 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008105 return -1;
8106 }
8107
8108 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8109 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008110 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
8111 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008112 if (curproxy == &defproxy) {
8113 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8114 return -1;
8115 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008116
8117 if (*(args[1]) == 0) {
8118 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8119 return -1;
8120 }
8121
8122 preg = calloc(1, sizeof(regex_t));
8123 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8124 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8125 return -1;
8126 }
8127
8128 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8129 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008130 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
8131 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008132 if (curproxy == &defproxy) {
8133 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8134 return -1;
8135 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008136
8137 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008138 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008139 return -1;
8140 }
8141
8142 preg = calloc(1, sizeof(regex_t));
8143 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008144 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008145 return -1;
8146 }
8147
8148 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8149 }
8150 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
8151 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008152 if (curproxy == &defproxy) {
8153 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8154 return -1;
8155 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008156
8157 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008158 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8159 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008160 return -1;
8161 }
8162
8163 preg = calloc(1, sizeof(regex_t));
8164 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008165 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008166 return -1;
8167 }
8168
willy tarreauc1f47532005-12-18 01:08:26 +01008169 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
8170 if (err) {
8171 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8172 file, linenum, *err);
8173 return -1;
8174 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008175 }
8176 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
8177 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008178 if (curproxy == &defproxy) {
8179 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8180 return -1;
8181 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008182
8183 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008184 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008185 return -1;
8186 }
8187
8188 preg = calloc(1, sizeof(regex_t));
8189 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008190 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008191 return -1;
8192 }
8193
8194 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
8195 }
8196 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
8197 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008198 if (curproxy == &defproxy) {
8199 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8200 return -1;
8201 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008202
8203 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008204 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008205 return -1;
8206 }
8207
8208 preg = calloc(1, sizeof(regex_t));
8209 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008210 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008211 return -1;
8212 }
8213
8214 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8215 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008216 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8217 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008218 if (curproxy == &defproxy) {
8219 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8220 return -1;
8221 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008222
8223 if (*(args[1]) == 0) {
8224 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8225 return -1;
8226 }
8227
8228 preg = calloc(1, sizeof(regex_t));
8229 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8230 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8231 return -1;
8232 }
8233
8234 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8235 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008236 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8237 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008238 if (curproxy == &defproxy) {
8239 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8240 return -1;
8241 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008242
8243 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008244 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008245 return -1;
8246 }
8247
8248 preg = calloc(1, sizeof(regex_t));
8249 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008250 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008251 return -1;
8252 }
8253
8254 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8255 }
8256 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008257 if (curproxy == &defproxy) {
8258 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8259 return -1;
8260 }
8261
willy tarreau9fe663a2005-12-17 13:02:59 +01008262 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008263 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008264 return 0;
8265 }
8266
8267 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008268 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008269 return -1;
8270 }
8271
willy tarreau4302f492005-12-18 01:00:37 +01008272 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8273 }
8274 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8275 regex_t *preg;
8276
8277 if (*(args[1]) == 0 || *(args[2]) == 0) {
8278 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8279 file, linenum, args[0]);
8280 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008281 }
willy tarreau4302f492005-12-18 01:00:37 +01008282
8283 preg = calloc(1, sizeof(regex_t));
8284 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8285 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8286 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008287 }
willy tarreau4302f492005-12-18 01:00:37 +01008288
willy tarreauc1f47532005-12-18 01:08:26 +01008289 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8290 if (err) {
8291 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8292 file, linenum, *err);
8293 return -1;
8294 }
willy tarreau4302f492005-12-18 01:00:37 +01008295 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008296 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8297 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008298 if (curproxy == &defproxy) {
8299 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8300 return -1;
8301 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008302
8303 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008304 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008305 return -1;
8306 }
willy tarreaue39cd132005-12-17 13:00:18 +01008307
willy tarreau9fe663a2005-12-17 13:02:59 +01008308 preg = calloc(1, sizeof(regex_t));
8309 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008310 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008311 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008312 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008313
willy tarreauc1f47532005-12-18 01:08:26 +01008314 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8315 if (err) {
8316 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8317 file, linenum, *err);
8318 return -1;
8319 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008320 }
willy tarreau982249e2005-12-18 00:57:06 +01008321 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8322 regex_t *preg;
8323 if (curproxy == &defproxy) {
8324 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8325 return -1;
8326 }
8327
8328 if (*(args[1]) == 0) {
8329 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8330 return -1;
8331 }
8332
8333 preg = calloc(1, sizeof(regex_t));
8334 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8335 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8336 return -1;
8337 }
8338
willy tarreauc1f47532005-12-18 01:08:26 +01008339 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8340 if (err) {
8341 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8342 file, linenum, *err);
8343 return -1;
8344 }
willy tarreau982249e2005-12-18 00:57:06 +01008345 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008346 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008347 regex_t *preg;
8348 if (curproxy == &defproxy) {
8349 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8350 return -1;
8351 }
willy tarreaue39cd132005-12-17 13:00:18 +01008352
willy tarreaua41a8b42005-12-17 14:02:24 +01008353 if (*(args[1]) == 0 || *(args[2]) == 0) {
8354 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8355 file, linenum, args[0]);
8356 return -1;
8357 }
willy tarreaue39cd132005-12-17 13:00:18 +01008358
willy tarreaua41a8b42005-12-17 14:02:24 +01008359 preg = calloc(1, sizeof(regex_t));
8360 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8361 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8362 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008363 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008364
willy tarreauc1f47532005-12-18 01:08:26 +01008365 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8366 if (err) {
8367 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8368 file, linenum, *err);
8369 return -1;
8370 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008371 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008372 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8373 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008374 if (curproxy == &defproxy) {
8375 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8376 return -1;
8377 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008378
8379 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008380 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008381 return -1;
8382 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008383
willy tarreau9fe663a2005-12-17 13:02:59 +01008384 preg = calloc(1, sizeof(regex_t));
8385 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008386 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008387 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008388 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008389
willy tarreauc1f47532005-12-18 01:08:26 +01008390 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8391 if (err) {
8392 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8393 file, linenum, *err);
8394 return -1;
8395 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008396 }
willy tarreau982249e2005-12-18 00:57:06 +01008397 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8398 regex_t *preg;
8399 if (curproxy == &defproxy) {
8400 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8401 return -1;
8402 }
8403
8404 if (*(args[1]) == 0) {
8405 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8406 return -1;
8407 }
8408
8409 preg = calloc(1, sizeof(regex_t));
8410 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8411 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8412 return -1;
8413 }
8414
willy tarreauc1f47532005-12-18 01:08:26 +01008415 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8416 if (err) {
8417 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8418 file, linenum, *err);
8419 return -1;
8420 }
willy tarreau982249e2005-12-18 00:57:06 +01008421 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008422 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008423 if (curproxy == &defproxy) {
8424 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8425 return -1;
8426 }
8427
willy tarreau9fe663a2005-12-17 13:02:59 +01008428 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008429 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008430 return 0;
8431 }
8432
8433 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008434 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008435 return -1;
8436 }
8437
8438 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8439 }
willy tarreauc1f47532005-12-18 01:08:26 +01008440 else if (!strcmp(args[0], "errorloc") ||
8441 !strcmp(args[0], "errorloc302") ||
8442 !strcmp(args[0], "errorloc303")) { /* error location */
8443 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008444 char *err;
8445
willy tarreaueedaa9f2005-12-17 14:08:03 +01008446 // if (curproxy == &defproxy) {
8447 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8448 // return -1;
8449 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008450
willy tarreau8337c6b2005-12-17 13:41:01 +01008451 if (*(args[2]) == 0) {
8452 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8453 return -1;
8454 }
8455
8456 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008457 if (!strcmp(args[0], "errorloc303")) {
8458 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8459 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8460 } else {
8461 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8462 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8463 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008464
8465 if (errnum == 400) {
8466 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008467 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008468 free(curproxy->errmsg.msg400);
8469 }
8470 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008471 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008472 }
8473 else if (errnum == 403) {
8474 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008475 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008476 free(curproxy->errmsg.msg403);
8477 }
8478 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008479 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008480 }
8481 else if (errnum == 408) {
8482 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008483 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008484 free(curproxy->errmsg.msg408);
8485 }
8486 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008487 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008488 }
8489 else if (errnum == 500) {
8490 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008491 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008492 free(curproxy->errmsg.msg500);
8493 }
8494 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008495 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008496 }
8497 else if (errnum == 502) {
8498 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008499 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008500 free(curproxy->errmsg.msg502);
8501 }
8502 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008503 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008504 }
8505 else if (errnum == 503) {
8506 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008507 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008508 free(curproxy->errmsg.msg503);
8509 }
8510 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008511 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008512 }
8513 else if (errnum == 504) {
8514 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008515 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008516 free(curproxy->errmsg.msg504);
8517 }
8518 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008519 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008520 }
8521 else {
8522 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8523 free(err);
8524 }
8525 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008526 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008527 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008528 return -1;
8529 }
8530 return 0;
8531}
willy tarreaue39cd132005-12-17 13:00:18 +01008532
willy tarreau5cbea6f2005-12-17 12:48:26 +01008533
willy tarreau9fe663a2005-12-17 13:02:59 +01008534/*
8535 * This function reads and parses the configuration file given in the argument.
8536 * returns 0 if OK, -1 if error.
8537 */
8538int readcfgfile(char *file) {
8539 char thisline[256];
8540 char *line;
8541 FILE *f;
8542 int linenum = 0;
8543 char *end;
8544 char *args[MAX_LINE_ARGS];
8545 int arg;
8546 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008547 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008548 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008549
willy tarreau9fe663a2005-12-17 13:02:59 +01008550 struct proxy *curproxy = NULL;
8551 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008552
willy tarreau9fe663a2005-12-17 13:02:59 +01008553 if ((f=fopen(file,"r")) == NULL)
8554 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008555
willy tarreaueedaa9f2005-12-17 14:08:03 +01008556 init_default_instance();
8557
willy tarreau9fe663a2005-12-17 13:02:59 +01008558 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8559 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008560
willy tarreau9fe663a2005-12-17 13:02:59 +01008561 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008562
willy tarreau9fe663a2005-12-17 13:02:59 +01008563 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008564 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008565 line++;
8566
8567 arg = 0;
8568 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008569
willy tarreau9fe663a2005-12-17 13:02:59 +01008570 while (*line && arg < MAX_LINE_ARGS) {
8571 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8572 * C equivalent value. Other combinations left unchanged (eg: \1).
8573 */
8574 if (*line == '\\') {
8575 int skip = 0;
8576 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8577 *line = line[1];
8578 skip = 1;
8579 }
8580 else if (line[1] == 'r') {
8581 *line = '\r';
8582 skip = 1;
8583 }
8584 else if (line[1] == 'n') {
8585 *line = '\n';
8586 skip = 1;
8587 }
8588 else if (line[1] == 't') {
8589 *line = '\t';
8590 skip = 1;
8591 }
willy tarreauc1f47532005-12-18 01:08:26 +01008592 else if (line[1] == 'x') {
8593 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8594 unsigned char hex1, hex2;
8595 hex1 = toupper(line[2]) - '0';
8596 hex2 = toupper(line[3]) - '0';
8597 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8598 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8599 *line = (hex1<<4) + hex2;
8600 skip = 3;
8601 }
8602 else {
8603 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8604 return -1;
8605 }
8606 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008607 if (skip) {
8608 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8609 end -= skip;
8610 }
8611 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008612 }
willy tarreaua1598082005-12-17 13:08:06 +01008613 else if (*line == '#' || *line == '\n' || *line == '\r') {
8614 /* end of string, end of loop */
8615 *line = 0;
8616 break;
8617 }
willy tarreauc29948c2005-12-17 13:10:27 +01008618 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008619 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008620 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008621 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008622 line++;
8623 args[++arg] = line;
8624 }
8625 else {
8626 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008627 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008628 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008629
willy tarreau9fe663a2005-12-17 13:02:59 +01008630 /* empty line */
8631 if (!**args)
8632 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008633
willy tarreau9fe663a2005-12-17 13:02:59 +01008634 /* zero out remaining args */
8635 while (++arg < MAX_LINE_ARGS) {
8636 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008637 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008638
willy tarreaua41a8b42005-12-17 14:02:24 +01008639 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008640 confsect = CFG_LISTEN;
8641 else if (!strcmp(args[0], "global")) /* global config */
8642 confsect = CFG_GLOBAL;
8643 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008644
willy tarreau9fe663a2005-12-17 13:02:59 +01008645 switch (confsect) {
8646 case CFG_LISTEN:
8647 if (cfg_parse_listen(file, linenum, args) < 0)
8648 return -1;
8649 break;
8650 case CFG_GLOBAL:
8651 if (cfg_parse_global(file, linenum, args) < 0)
8652 return -1;
8653 break;
8654 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008655 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008656 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008657 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008658
8659
willy tarreau0f7af912005-12-17 12:21:26 +01008660 }
8661 fclose(f);
8662
8663 /*
8664 * Now, check for the integrity of all that we have collected.
8665 */
8666
Willy TARREAU3759f982006-03-01 22:44:17 +01008667 /* will be needed further to delay some tasks */
8668 tv_now(&now);
8669
willy tarreau0f7af912005-12-17 12:21:26 +01008670 if ((curproxy = proxy) == NULL) {
8671 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8672 file);
8673 return -1;
8674 }
8675
8676 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008677 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008678 curproxy = curproxy->next;
8679 continue;
8680 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008681
8682 if (curproxy->listen == NULL) {
8683 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);
8684 cfgerr++;
8685 }
8686 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008687 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008688 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008689 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8690 file, curproxy->id);
8691 cfgerr++;
8692 }
8693 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8694 if (curproxy->options & PR_O_TRANSP) {
8695 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8696 file, curproxy->id);
8697 cfgerr++;
8698 }
8699 else if (curproxy->srv == NULL) {
8700 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8701 file, curproxy->id);
8702 cfgerr++;
8703 }
willy tarreaua1598082005-12-17 13:08:06 +01008704 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008705 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8706 file, curproxy->id);
8707 }
8708 }
8709 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008710 if (curproxy->cookie_name != NULL) {
8711 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8712 file, curproxy->id);
8713 }
8714 if ((newsrv = curproxy->srv) != NULL) {
8715 Warning("parsing %s : servers will be ignored for listener %s.\n",
8716 file, curproxy->id);
8717 }
willy tarreaue39cd132005-12-17 13:00:18 +01008718 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008719 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8720 file, curproxy->id);
8721 }
willy tarreaue39cd132005-12-17 13:00:18 +01008722 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008723 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8724 file, curproxy->id);
8725 }
8726 }
8727 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8728 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8729 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8730 file, curproxy->id);
8731 cfgerr++;
8732 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008733 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008734
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008735 /* first, we will invert the servers list order */
8736 newsrv = NULL;
8737 while (curproxy->srv) {
8738 struct server *next;
8739
8740 next = curproxy->srv->next;
8741 curproxy->srv->next = newsrv;
8742 newsrv = curproxy->srv;
8743 if (!next)
8744 break;
8745 curproxy->srv = next;
8746 }
8747
8748 /* now, newsrv == curproxy->srv */
8749 if (newsrv) {
8750 struct server *srv;
8751 int pgcd;
8752 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008753
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008754 /* We will factor the weights to reduce the table,
8755 * using Euclide's largest common divisor algorithm
8756 */
8757 pgcd = newsrv->uweight + 1;
8758 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8759 int t, w;
8760
8761 w = srv->uweight + 1;
8762 while (w) {
8763 t = pgcd % w;
8764 pgcd = w;
8765 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008766 }
willy tarreau0f7af912005-12-17 12:21:26 +01008767 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008768
8769 act = bck = 0;
8770 for (srv = newsrv; srv; srv = srv->next) {
8771 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8772 if (srv->state & SRV_BACKUP)
8773 bck += srv->eweight + 1;
8774 else
8775 act += srv->eweight + 1;
8776 }
8777
8778 /* this is the largest map we will ever need for this servers list */
8779 if (act < bck)
8780 act = bck;
8781
8782 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8783 /* recounts servers and their weights */
8784 recount_servers(curproxy);
8785 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008786 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008787
8788 if (curproxy->options & PR_O_LOGASAP)
8789 curproxy->to_log &= ~LW_BYTES;
8790
willy tarreau8337c6b2005-12-17 13:41:01 +01008791 if (curproxy->errmsg.msg400 == NULL) {
8792 curproxy->errmsg.msg400 = (char *)HTTP_400;
8793 curproxy->errmsg.len400 = strlen(HTTP_400);
8794 }
8795 if (curproxy->errmsg.msg403 == NULL) {
8796 curproxy->errmsg.msg403 = (char *)HTTP_403;
8797 curproxy->errmsg.len403 = strlen(HTTP_403);
8798 }
8799 if (curproxy->errmsg.msg408 == NULL) {
8800 curproxy->errmsg.msg408 = (char *)HTTP_408;
8801 curproxy->errmsg.len408 = strlen(HTTP_408);
8802 }
8803 if (curproxy->errmsg.msg500 == NULL) {
8804 curproxy->errmsg.msg500 = (char *)HTTP_500;
8805 curproxy->errmsg.len500 = strlen(HTTP_500);
8806 }
8807 if (curproxy->errmsg.msg502 == NULL) {
8808 curproxy->errmsg.msg502 = (char *)HTTP_502;
8809 curproxy->errmsg.len502 = strlen(HTTP_502);
8810 }
8811 if (curproxy->errmsg.msg503 == NULL) {
8812 curproxy->errmsg.msg503 = (char *)HTTP_503;
8813 curproxy->errmsg.len503 = strlen(HTTP_503);
8814 }
8815 if (curproxy->errmsg.msg504 == NULL) {
8816 curproxy->errmsg.msg504 = (char *)HTTP_504;
8817 curproxy->errmsg.len504 = strlen(HTTP_504);
8818 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008819
willy tarreau59a6cc22006-05-12 01:29:08 +02008820 /*
8821 * If this server supports a maxconn parameter, it needs a dedicated
8822 * tasks to fill the emptied slots when a connection leaves.
8823 */
8824 newsrv = curproxy->srv;
8825 while (newsrv != NULL) {
8826 if (newsrv->maxconn > 0) {
8827 struct task *t;
8828
8829 if ((t = pool_alloc(task)) == NULL) {
8830 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8831 return -1;
8832 }
8833
8834 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8835 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
8836 t->state = TASK_IDLE;
8837 t->process = process_srv_queue;
8838 t->context = newsrv;
8839 newsrv->queue_mgt = t;
8840
8841 /* never run it unless specifically woken up */
8842 tv_eternity(&t->expire);
8843 task_queue(t);
8844 }
8845 newsrv = newsrv->next;
8846 }
8847
Willy TARREAU3759f982006-03-01 22:44:17 +01008848 /* now we'll start this proxy's health checks if any */
8849 /* 1- count the checkers to run simultaneously */
8850 nbchk = 0;
8851 mininter = 0;
8852 newsrv = curproxy->srv;
8853 while (newsrv != NULL) {
8854 if (newsrv->state & SRV_CHECKED) {
8855 if (!mininter || mininter > newsrv->inter)
8856 mininter = newsrv->inter;
8857 nbchk++;
8858 }
8859 newsrv = newsrv->next;
8860 }
8861
8862 /* 2- start them as far as possible from each others while respecting
8863 * their own intervals. For this, we will start them after their own
8864 * interval added to the min interval divided by the number of servers,
8865 * weighted by the server's position in the list.
8866 */
8867 if (nbchk > 0) {
8868 struct task *t;
8869 int srvpos;
8870
8871 newsrv = curproxy->srv;
8872 srvpos = 0;
8873 while (newsrv != NULL) {
8874 /* should this server be checked ? */
8875 if (newsrv->state & SRV_CHECKED) {
8876 if ((t = pool_alloc(task)) == NULL) {
8877 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8878 return -1;
8879 }
8880
8881 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008882 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008883 t->state = TASK_IDLE;
8884 t->process = process_chk;
8885 t->context = newsrv;
8886
8887 /* check this every ms */
8888 tv_delayfrom(&t->expire, &now,
8889 newsrv->inter + mininter * srvpos / nbchk);
8890 task_queue(t);
8891 //task_wakeup(&rq, t);
8892 srvpos++;
8893 }
8894 newsrv = newsrv->next;
8895 }
8896 }
8897
willy tarreau0f7af912005-12-17 12:21:26 +01008898 curproxy = curproxy->next;
8899 }
8900 if (cfgerr > 0) {
8901 Alert("Errors found in configuration file, aborting.\n");
8902 return -1;
8903 }
8904 else
8905 return 0;
8906}
8907
8908
8909/*
8910 * This function initializes all the necessary variables. It only returns
8911 * if everything is OK. If something fails, it exits.
8912 */
8913void init(int argc, char **argv) {
8914 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008915 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008916 char *old_argv = *argv;
8917 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008918 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008919
8920 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008921 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008922 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008923 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008924 exit(1);
8925 }
8926
willy tarreau746e26b2006-03-25 11:14:35 +01008927#ifdef HAPROXY_MEMMAX
8928 global.rlimit_memmax = HAPROXY_MEMMAX;
8929#endif
8930
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008931 /* initialize the libc's localtime structures once for all so that we
8932 * won't be missing memory if we want to send alerts under OOM conditions.
8933 */
8934 tv_now(&now);
8935 localtime(&now.tv_sec);
8936
willy tarreau4302f492005-12-18 01:00:37 +01008937 /* initialize the log header encoding map : '{|}"#' should be encoded with
8938 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8939 * URL encoding only requires '"', '#' to be encoded as well as non-
8940 * printable characters above.
8941 */
8942 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8943 memset(url_encode_map, 0, sizeof(url_encode_map));
8944 for (i = 0; i < 32; i++) {
8945 FD_SET(i, hdr_encode_map);
8946 FD_SET(i, url_encode_map);
8947 }
8948 for (i = 127; i < 256; i++) {
8949 FD_SET(i, hdr_encode_map);
8950 FD_SET(i, url_encode_map);
8951 }
8952
8953 tmp = "\"#{|}";
8954 while (*tmp) {
8955 FD_SET(*tmp, hdr_encode_map);
8956 tmp++;
8957 }
8958
8959 tmp = "\"#";
8960 while (*tmp) {
8961 FD_SET(*tmp, url_encode_map);
8962 tmp++;
8963 }
8964
willy tarreau64a3cc32005-12-18 01:13:11 +01008965 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8966#if defined(ENABLE_POLL)
8967 cfg_polling_mechanism |= POLL_USE_POLL;
8968#endif
8969#if defined(ENABLE_EPOLL)
8970 cfg_polling_mechanism |= POLL_USE_EPOLL;
8971#endif
8972
willy tarreau0f7af912005-12-17 12:21:26 +01008973 pid = getpid();
8974 progname = *argv;
8975 while ((tmp = strchr(progname, '/')) != NULL)
8976 progname = tmp + 1;
8977
8978 argc--; argv++;
8979 while (argc > 0) {
8980 char *flag;
8981
8982 if (**argv == '-') {
8983 flag = *argv+1;
8984
8985 /* 1 arg */
8986 if (*flag == 'v') {
8987 display_version();
8988 exit(0);
8989 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008990#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008991 else if (*flag == 'd' && flag[1] == 'e')
8992 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008993#endif
8994#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008995 else if (*flag == 'd' && flag[1] == 'p')
8996 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008997#endif
willy tarreau982249e2005-12-18 00:57:06 +01008998 else if (*flag == 'V')
8999 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009000 else if (*flag == 'd' && flag[1] == 'b')
9001 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01009002 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01009003 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01009004 else if (*flag == 'c')
9005 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01009006 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01009007 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01009008 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01009009 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01009010 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
9011 /* list of pids to finish ('f') or terminate ('t') */
9012
9013 if (flag[1] == 'f')
9014 oldpids_sig = SIGUSR1; /* finish then exit */
9015 else
9016 oldpids_sig = SIGTERM; /* terminate immediately */
9017 argv++; argc--;
9018
9019 if (argc > 0) {
9020 oldpids = calloc(argc, sizeof(int));
9021 while (argc > 0) {
9022 oldpids[nb_oldpids] = atol(*argv);
9023 if (oldpids[nb_oldpids] <= 0)
9024 usage(old_argv);
9025 argc--; argv++;
9026 nb_oldpids++;
9027 }
9028 }
9029 }
willy tarreau2c513732006-04-15 19:25:16 +02009030#if STATTIME > 0
9031 else if (*flag == 's')
9032 arg_mode |= MODE_STATS;
9033 else if (*flag == 'l')
9034 arg_mode |= MODE_LOG;
9035#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009036 else { /* >=2 args */
9037 argv++; argc--;
9038 if (argc == 0)
9039 usage(old_argv);
9040
9041 switch (*flag) {
9042 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01009043 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01009044 case 'N' : cfg_maxpconn = atol(*argv); break;
9045 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009046 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01009047 default: usage(old_argv);
9048 }
9049 }
9050 }
9051 else
9052 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01009053 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01009054 }
9055
willy tarreaud0fb4652005-12-18 01:32:04 +01009056 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009057 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
9058 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01009059
willy tarreau0f7af912005-12-17 12:21:26 +01009060 if (!cfg_cfgfile)
9061 usage(old_argv);
9062
9063 gethostname(hostname, MAX_HOSTNAME_LEN);
9064
willy tarreau12350152005-12-18 01:03:27 +01009065 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01009066 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01009067 if (readcfgfile(cfg_cfgfile) < 0) {
9068 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
9069 exit(1);
9070 }
willy tarreau12350152005-12-18 01:03:27 +01009071 if (have_appsession)
9072 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01009073
willy tarreau982249e2005-12-18 00:57:06 +01009074 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01009075 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
9076 exit(0);
9077 }
9078
willy tarreau9fe663a2005-12-17 13:02:59 +01009079 if (cfg_maxconn > 0)
9080 global.maxconn = cfg_maxconn;
9081
willy tarreaufe2c5c12005-12-17 14:14:34 +01009082 if (cfg_pidfile) {
9083 if (global.pidfile)
9084 free(global.pidfile);
9085 global.pidfile = strdup(cfg_pidfile);
9086 }
9087
willy tarreau9fe663a2005-12-17 13:02:59 +01009088 if (global.maxconn == 0)
9089 global.maxconn = DEFAULT_MAXCONN;
9090
Willy TARREAU203b0b62006-03-12 18:00:28 +01009091 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01009092
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009093 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009094 /* command line debug mode inhibits configuration mode */
9095 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9096 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009097 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
9098 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01009099
9100 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
9101 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
9102 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
9103 }
9104
9105 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01009106 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
9107 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01009108 global.nbproc = 1;
9109 }
9110
9111 if (global.nbproc < 1)
9112 global.nbproc = 1;
9113
willy tarreau0f7af912005-12-17 12:21:26 +01009114 StaticReadEvent = (fd_set *)calloc(1,
9115 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009116 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009117 StaticWriteEvent = (fd_set *)calloc(1,
9118 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01009119 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01009120
9121 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01009122 sizeof(struct fdtab) * (global.maxsock));
9123 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01009124 fdtab[i].state = FD_STCLOSE;
9125 }
9126}
9127
9128/*
willy tarreau41310e72006-03-25 18:17:56 +01009129 * this function starts all the proxies. Its return value is composed from
9130 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
9131 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01009132 */
willy tarreau41310e72006-03-25 18:17:56 +01009133int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01009134 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01009135 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01009136 int err = ERR_NONE;
9137 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01009138
9139 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009140 if (curproxy->state != PR_STNEW)
9141 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01009142
willy tarreau41310e72006-03-25 18:17:56 +01009143 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01009144 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01009145 if (listener->fd != -1)
9146 continue; /* already initialized */
9147
9148 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
9149 if (verbose)
9150 Alert("cannot create listening socket for proxy %s. Aborting.\n",
9151 curproxy->id);
9152 err |= ERR_RETRYABLE;
9153 pxerr |= 1;
9154 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009155 }
willy tarreau0f7af912005-12-17 12:21:26 +01009156
willy tarreaua41a8b42005-12-17 14:02:24 +01009157 if (fd >= global.maxsock) {
9158 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
9159 curproxy->id);
9160 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009161 err |= ERR_FATAL;
9162 pxerr |= 1;
9163 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009164 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01009165
willy tarreaua41a8b42005-12-17 14:02:24 +01009166 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
9167 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
9168 (char *) &one, sizeof(one)) == -1)) {
9169 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
9170 curproxy->id);
9171 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009172 err |= ERR_FATAL;
9173 pxerr |= 1;
9174 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01009175 }
willy tarreau0f7af912005-12-17 12:21:26 +01009176
willy tarreaua41a8b42005-12-17 14:02:24 +01009177 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
9178 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
9179 curproxy->id);
9180 }
willy tarreau0f7af912005-12-17 12:21:26 +01009181
willy tarreaua41a8b42005-12-17 14:02:24 +01009182 if (bind(fd,
9183 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01009184 listener->addr.ss_family == AF_INET6 ?
9185 sizeof(struct sockaddr_in6) :
9186 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009187 if (verbose)
9188 Alert("cannot bind socket for proxy %s. Aborting.\n",
9189 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009190 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009191 err |= ERR_RETRYABLE;
9192 pxerr |= 1;
9193 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009194 }
willy tarreau0f7af912005-12-17 12:21:26 +01009195
willy tarreaua41a8b42005-12-17 14:02:24 +01009196 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01009197 if (verbose)
9198 Alert("cannot listen to socket for proxy %s. Aborting.\n",
9199 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01009200 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01009201 err |= ERR_RETRYABLE;
9202 pxerr |= 1;
9203 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009204 }
willy tarreau0f7af912005-12-17 12:21:26 +01009205
willy tarreau41310e72006-03-25 18:17:56 +01009206 /* the socket is ready */
9207 listener->fd = fd;
9208
willy tarreaua41a8b42005-12-17 14:02:24 +01009209 /* the function for the accept() event */
9210 fdtab[fd].read = &event_accept;
9211 fdtab[fd].write = NULL; /* never called */
9212 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009213 fdtab[fd].state = FD_STLISTEN;
9214 FD_SET(fd, StaticReadEvent);
9215 fd_insert(fd);
9216 listeners++;
9217 }
willy tarreau41310e72006-03-25 18:17:56 +01009218
9219 if (!pxerr) {
9220 curproxy->state = PR_STRUN;
9221 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9222 }
willy tarreau0f7af912005-12-17 12:21:26 +01009223 }
willy tarreau41310e72006-03-25 18:17:56 +01009224
9225 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009226}
9227
willy tarreaub952e1d2005-12-18 01:31:20 +01009228int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009229
9230 appsess *temp1,*temp2;
9231 temp1 = (appsess *)key1;
9232 temp2 = (appsess *)key2;
9233
9234 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9235 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9236
9237 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9238}/* end match_str */
9239
willy tarreaub952e1d2005-12-18 01:31:20 +01009240void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009241 appsess *temp1;
9242
9243 //printf("destroy called\n");
9244 temp1 = (appsess *)data;
9245
9246 if (temp1->sessid)
9247 pool_free_to(apools.sessid, temp1->sessid);
9248
9249 if (temp1->serverid)
9250 pool_free_to(apools.serverid, temp1->serverid);
9251
9252 pool_free(appsess, temp1);
9253} /* end destroy */
9254
9255void appsession_cleanup( void )
9256{
9257 struct proxy *p = proxy;
9258
9259 while(p) {
9260 chtbl_destroy(&(p->htbl_proxy));
9261 p = p->next;
9262 }
9263}/* end appsession_cleanup() */
9264
9265void pool_destroy(void **pool)
9266{
9267 void *temp, *next;
9268 next = pool;
9269 while (next) {
9270 temp = next;
9271 next = *(void **)temp;
9272 free(temp);
9273 }
9274}/* end pool_destroy() */
9275
willy tarreaub952e1d2005-12-18 01:31:20 +01009276void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009277 struct proxy *p = proxy;
9278 struct cap_hdr *h,*h_next;
9279 struct server *s,*s_next;
9280 struct listener *l,*l_next;
9281
9282 while (p) {
9283 if (p->id)
9284 free(p->id);
9285
9286 if (p->check_req)
9287 free(p->check_req);
9288
9289 if (p->cookie_name)
9290 free(p->cookie_name);
9291
9292 if (p->capture_name)
9293 free(p->capture_name);
9294
9295 /* only strup if the user have set in config.
9296 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009297 if (p->errmsg.msg400) free(p->errmsg.msg400);
9298 if (p->errmsg.msg403) free(p->errmsg.msg403);
9299 if (p->errmsg.msg408) free(p->errmsg.msg408);
9300 if (p->errmsg.msg500) free(p->errmsg.msg500);
9301 if (p->errmsg.msg502) free(p->errmsg.msg502);
9302 if (p->errmsg.msg503) free(p->errmsg.msg503);
9303 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009304 */
9305 if (p->appsession_name)
9306 free(p->appsession_name);
9307
9308 h = p->req_cap;
9309 while (h) {
9310 h_next = h->next;
9311 if (h->name)
9312 free(h->name);
9313 pool_destroy(h->pool);
9314 free(h);
9315 h = h_next;
9316 }/* end while(h) */
9317
9318 h = p->rsp_cap;
9319 while (h) {
9320 h_next = h->next;
9321 if (h->name)
9322 free(h->name);
9323
9324 pool_destroy(h->pool);
9325 free(h);
9326 h = h_next;
9327 }/* end while(h) */
9328
9329 s = p->srv;
9330 while (s) {
9331 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009332 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009333 free(s->id);
9334
willy tarreaub952e1d2005-12-18 01:31:20 +01009335 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009336 free(s->cookie);
9337
9338 free(s);
9339 s = s_next;
9340 }/* end while(s) */
9341
9342 l = p->listen;
9343 while (l) {
9344 l_next = l->next;
9345 free(l);
9346 l = l_next;
9347 }/* end while(l) */
9348
9349 pool_destroy((void **) p->req_cap_pool);
9350 pool_destroy((void **) p->rsp_cap_pool);
9351 p = p->next;
9352 }/* end while(p) */
9353
9354 if (global.chroot) free(global.chroot);
9355 if (global.pidfile) free(global.pidfile);
9356
willy tarreau12350152005-12-18 01:03:27 +01009357 if (StaticReadEvent) free(StaticReadEvent);
9358 if (StaticWriteEvent) free(StaticWriteEvent);
9359 if (fdtab) free(fdtab);
9360
9361 pool_destroy(pool_session);
9362 pool_destroy(pool_buffer);
9363 pool_destroy(pool_fdtab);
9364 pool_destroy(pool_requri);
9365 pool_destroy(pool_task);
9366 pool_destroy(pool_capture);
9367 pool_destroy(pool_appsess);
9368
9369 if (have_appsession) {
9370 pool_destroy(apools.serverid);
9371 pool_destroy(apools.sessid);
9372 }
9373} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009374
willy tarreau41310e72006-03-25 18:17:56 +01009375/* sends the signal <sig> to all pids found in <oldpids> */
9376static void tell_old_pids(int sig) {
9377 int p;
9378 for (p = 0; p < nb_oldpids; p++)
9379 kill(oldpids[p], sig);
9380}
9381
willy tarreau0f7af912005-12-17 12:21:26 +01009382int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009383 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009384 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009385 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009386 init(argc, argv);
9387
willy tarreau0f7af912005-12-17 12:21:26 +01009388 signal(SIGQUIT, dump);
9389 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009390 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009391#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009392 signal(SIGINT, sig_int);
9393 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009394#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009395
9396 /* on very high loads, a sigpipe sometimes happen just between the
9397 * getsockopt() which tells "it's OK to write", and the following write :-(
9398 */
willy tarreau3242e862005-12-17 12:27:53 +01009399#ifndef MSG_NOSIGNAL
9400 signal(SIGPIPE, SIG_IGN);
9401#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009402
willy tarreau41310e72006-03-25 18:17:56 +01009403 /* We will loop at most 100 times with 10 ms delay each time.
9404 * That's at most 1 second. We only send a signal to old pids
9405 * if we cannot grab at least one port.
9406 */
9407 retry = MAX_START_RETRIES;
9408 err = ERR_NONE;
9409 while (retry >= 0) {
9410 struct timeval w;
9411 err = start_proxies(retry == 0 || nb_oldpids == 0);
9412 if (err != ERR_RETRYABLE)
9413 break;
9414 if (nb_oldpids == 0)
9415 break;
9416
Willy TARREAU007aa462006-05-14 09:55:23 +02009417 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
9418 * listening sockets. So on those platforms, it would be wiser to
9419 * simply send SIGUSR1, which will not be undoable.
9420 */
willy tarreau41310e72006-03-25 18:17:56 +01009421 tell_old_pids(SIGTTOU);
9422 /* give some time to old processes to stop listening */
9423 w.tv_sec = 0;
9424 w.tv_usec = 10*1000;
9425 select(0, NULL, NULL, NULL, &w);
9426 retry--;
9427 }
9428
9429 /* Note: start_proxies() sends an alert when it fails. */
9430 if (err != ERR_NONE) {
9431 if (retry != MAX_START_RETRIES && nb_oldpids)
9432 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009433 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009434 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009435
9436 if (listeners == 0) {
9437 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009438 /* Note: we don't have to send anything to the old pids because we
9439 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009440 exit(1);
9441 }
9442
willy tarreaudbd3bef2006-01-20 19:35:18 +01009443 /* prepare pause/play signals */
9444 signal(SIGTTOU, sig_pause);
9445 signal(SIGTTIN, sig_listen);
9446
Willy TARREAUe3283d12006-03-01 22:15:29 +01009447 if (global.mode & MODE_DAEMON) {
9448 global.mode &= ~MODE_VERBOSE;
9449 global.mode |= MODE_QUIET;
9450 }
9451
willy tarreaud0fb4652005-12-18 01:32:04 +01009452 /* MODE_QUIET can inhibit alerts and warnings below this line */
9453
9454 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009455 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009456 /* detach from the tty */
9457 fclose(stdin); fclose(stdout); fclose(stderr);
9458 close(0); close(1); close(2);
9459 }
willy tarreau0f7af912005-12-17 12:21:26 +01009460
willy tarreaufe2c5c12005-12-17 14:14:34 +01009461 /* open log & pid files before the chroot */
9462 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9463 int pidfd;
9464 unlink(global.pidfile);
9465 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9466 if (pidfd < 0) {
9467 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009468 if (nb_oldpids)
9469 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009470 exit(1);
9471 }
9472 pidfile = fdopen(pidfd, "w");
9473 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009474
9475 /* chroot if needed */
9476 if (global.chroot != NULL) {
9477 if (chroot(global.chroot) == -1) {
9478 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009479 if (nb_oldpids)
9480 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009481 }
9482 chdir("/");
9483 }
9484
willy tarreaub1285d52005-12-18 01:20:14 +01009485 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009486 if (!global.rlimit_nofile)
9487 global.rlimit_nofile = global.maxsock;
9488
willy tarreaub1285d52005-12-18 01:20:14 +01009489 if (global.rlimit_nofile) {
9490 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9491 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9492 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9493 }
willy tarreau746e26b2006-03-25 11:14:35 +01009494 }
9495
9496 if (global.rlimit_memmax) {
9497 limit.rlim_cur = limit.rlim_max =
9498 global.rlimit_memmax * 1048576 / global.nbproc;
9499#ifdef RLIMIT_AS
9500 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9501 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9502 argv[0], global.rlimit_memmax);
9503 }
9504#else
9505 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9506 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9507 argv[0], global.rlimit_memmax);
9508 }
9509#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009510 }
9511
willy tarreau41310e72006-03-25 18:17:56 +01009512 if (nb_oldpids)
9513 tell_old_pids(oldpids_sig);
9514
9515 /* Note that any error at this stage will be fatal because we will not
9516 * be able to restart the old pids.
9517 */
9518
willy tarreau9fe663a2005-12-17 13:02:59 +01009519 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009520 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009521 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9522 exit(1);
9523 }
9524
willy tarreau036e1ce2005-12-17 13:46:33 +01009525 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009526 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9527 exit(1);
9528 }
9529
willy tarreaub1285d52005-12-18 01:20:14 +01009530 /* check ulimits */
9531 limit.rlim_cur = limit.rlim_max = 0;
9532 getrlimit(RLIMIT_NOFILE, &limit);
9533 if (limit.rlim_cur < global.maxsock) {
9534 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",
9535 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9536 }
9537
willy tarreau9fe663a2005-12-17 13:02:59 +01009538 if (global.mode & MODE_DAEMON) {
9539 int ret = 0;
9540 int proc;
9541
9542 /* the father launches the required number of processes */
9543 for (proc = 0; proc < global.nbproc; proc++) {
9544 ret = fork();
9545 if (ret < 0) {
9546 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009547 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009548 exit(1); /* there has been an error */
9549 }
9550 else if (ret == 0) /* child breaks here */
9551 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009552 if (pidfile != NULL) {
9553 fprintf(pidfile, "%d\n", ret);
9554 fflush(pidfile);
9555 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009556 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009557 /* close the pidfile both in children and father */
9558 if (pidfile != NULL)
9559 fclose(pidfile);
9560 free(global.pidfile);
9561
willy tarreau9fe663a2005-12-17 13:02:59 +01009562 if (proc == global.nbproc)
9563 exit(0); /* parent must leave */
9564
willy tarreau750a4722005-12-17 13:21:24 +01009565 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9566 * that we can detach from the TTY. We MUST NOT do it in other cases since
9567 * it would have already be done, and 0-2 would have been affected to listening
9568 * sockets
9569 */
9570 if (!(global.mode & MODE_QUIET)) {
9571 /* detach from the tty */
9572 fclose(stdin); fclose(stdout); fclose(stderr);
9573 close(0); close(1); close(2); /* close all fd's */
9574 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9575 }
willy tarreaua1598082005-12-17 13:08:06 +01009576 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009577 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009578 }
9579
willy tarreau1c2ad212005-12-18 01:11:29 +01009580#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009581 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009582 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9583 epoll_loop(POLL_LOOP_ACTION_RUN);
9584 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009585 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009586 }
9587 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009588 Warning("epoll() is not available. Using poll()/select() instead.\n");
9589 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009590 }
9591 }
9592#endif
9593
9594#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009595 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009596 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9597 poll_loop(POLL_LOOP_ACTION_RUN);
9598 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009599 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009600 }
9601 else {
9602 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009603 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009604 }
9605 }
9606#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009607 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009608 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9609 select_loop(POLL_LOOP_ACTION_RUN);
9610 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009611 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009612 }
9613 }
9614
willy tarreau0f7af912005-12-17 12:21:26 +01009615
willy tarreau12350152005-12-18 01:03:27 +01009616 /* Free all Hash Keys and all Hash elements */
9617 appsession_cleanup();
9618 /* Do some cleanup */
9619 deinit();
9620
willy tarreau0f7af912005-12-17 12:21:26 +01009621 exit(0);
9622}
willy tarreau12350152005-12-18 01:03:27 +01009623
9624#if defined(DEBUG_HASH)
9625static void print_table(const CHTbl *htbl) {
9626
9627 ListElmt *element;
9628 int i;
9629 appsess *asession;
9630
9631 /*****************************************************************************
9632 * *
9633 * Display the chained hash table. *
9634 * *
9635 *****************************************************************************/
9636
9637 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9638
9639 for (i = 0; i < TBLSIZ; i++) {
9640 fprintf(stdout, "Bucket[%03d]\n", i);
9641
9642 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9643 //fprintf(stdout, "%c", *(char *)list_data(element));
9644 asession = (appsess *)list_data(element);
9645 fprintf(stdout, "ELEM :%s:", asession->sessid);
9646 fprintf(stdout, " Server :%s: \n", asession->serverid);
9647 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9648 }
9649
9650 fprintf(stdout, "\n");
9651 }
9652 return;
9653} /* end print_table */
9654#endif
9655
9656static int appsession_init(void)
9657{
9658 static int initialized = 0;
9659 int idlen;
9660 struct server *s;
9661 struct proxy *p = proxy;
9662
9663 if (!initialized) {
9664 if (!appsession_task_init()) {
9665 apools.sessid = NULL;
9666 apools.serverid = NULL;
9667 apools.ser_waste = 0;
9668 apools.ser_use = 0;
9669 apools.ser_msize = sizeof(void *);
9670 apools.ses_waste = 0;
9671 apools.ses_use = 0;
9672 apools.ses_msize = sizeof(void *);
9673 while (p) {
9674 s = p->srv;
9675 if (apools.ses_msize < p->appsession_len)
9676 apools.ses_msize = p->appsession_len;
9677 while (s) {
9678 idlen = strlen(s->id);
9679 if (apools.ser_msize < idlen)
9680 apools.ser_msize = idlen;
9681 s = s->next;
9682 }
9683 p = p->next;
9684 }
9685 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9686 apools.ses_msize ++;
9687 }
9688 else {
9689 fprintf(stderr, "appsession_task_init failed\n");
9690 return -1;
9691 }
9692 initialized ++;
9693 }
9694 return 0;
9695}
9696
9697static int appsession_task_init(void)
9698{
9699 static int initialized = 0;
9700 struct task *t;
9701 if (!initialized) {
9702 if ((t = pool_alloc(task)) == NULL)
9703 return -1;
9704 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009705 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009706 t->state = TASK_IDLE;
9707 t->context = NULL;
9708 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9709 task_queue(t);
9710 t->process = appsession_refresh;
9711 initialized ++;
9712 }
9713 return 0;
9714}
9715
9716static int appsession_refresh(struct task *t) {
9717 struct proxy *p = proxy;
9718 CHTbl *htbl;
9719 ListElmt *element, *last;
9720 int i;
9721 appsess *asession;
9722 void *data;
9723
9724 while (p) {
9725 if (p->appsession_name != NULL) {
9726 htbl = &p->htbl_proxy;
9727 /* if we ever give up the use of TBLSIZ, we need to change this */
9728 for (i = 0; i < TBLSIZ; i++) {
9729 last = NULL;
9730 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9731 asession = (appsess *)list_data(element);
9732 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9733 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9734 int len;
9735 /*
9736 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9737 */
9738 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9739 asession->sessid, asession->serverid?asession->serverid:"(null)");
9740 write(1, trash, len);
9741 }
9742 /* delete the expired element from within the hash table */
9743 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9744 && (htbl->table[i].destroy != NULL)) {
9745 htbl->table[i].destroy(data);
9746 }
9747 if (last == NULL) {/* patient lost his head, get a new one */
9748 element = list_head(&htbl->table[i]);
9749 if (element == NULL) break; /* no heads left, go to next patient */
9750 }
9751 else
9752 element = last;
9753 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9754 else
9755 last = element;
9756 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9757 }
9758 }
9759 p = p->next;
9760 }
9761 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9762 return TBLCHKINT;
9763} /* end appsession_refresh */
9764
willy tarreau18a957c2006-04-12 19:26:23 +02009765
9766/*
9767 * Local variables:
9768 * c-indent-level: 4
9769 * c-basic-offset: 4
9770 * End:
9771 */