blob: 0a935c0a10833f403224ee2a28b0a9d182b3f1b3 [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 tarreau598da412005-12-18 01:07:29 +010088#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010089
willy tarreaubfad5742006-03-23 14:19:11 +010090#ifndef HAPROXY_VERSION
91#define HAPROXY_VERSION "1.2.10.1"
92#endif
93
94#ifndef HAPROXY_DATE
95#define HAPROXY_DATE "2006/03/23"
96#endif
willy tarreau0f7af912005-12-17 12:21:26 +010097
98/* this is for libc5 for example */
99#ifndef TCP_NODELAY
100#define TCP_NODELAY 1
101#endif
102
103#ifndef SHUT_RD
104#define SHUT_RD 0
105#endif
106
107#ifndef SHUT_WR
108#define SHUT_WR 1
109#endif
110
willy tarreau0174f312005-12-18 01:02:42 +0100111/*
112 * BUFSIZE defines the size of a read and write buffer. It is the maximum
113 * amount of bytes which can be stored by the proxy for each session. However,
114 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
115 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
116 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
117 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
118 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
119 */
120#ifndef BUFSIZE
121#define BUFSIZE 16384
122#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100123
124// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100125#ifndef MAXREWRITE
126#define MAXREWRITE (BUFSIZE / 2)
127#endif
128
willy tarreau9fe663a2005-12-17 13:02:59 +0100129#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100130#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100131
willy tarreau5cbea6f2005-12-17 12:48:26 +0100132// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100133#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100134
willy tarreaue39cd132005-12-17 13:00:18 +0100135// max # of added headers per request
136#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100137
138// max # of matches per regexp
139#define MAX_MATCH 10
140
willy tarreau0174f312005-12-18 01:02:42 +0100141// cookie delimitor in "prefix" mode. This character is inserted between the
142// persistence cookie and the original value. The '~' is allowed by RFC2965,
143// and should not be too common in server names.
144#ifndef COOKIE_DELIM
145#define COOKIE_DELIM '~'
146#endif
147
willy tarreau0f7af912005-12-17 12:21:26 +0100148#define CONN_RETRIES 3
149
willy tarreau5cbea6f2005-12-17 12:48:26 +0100150#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100151#define DEF_CHKINTR 2000
152#define DEF_FALLTIME 3
153#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100154#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100155
Willy TARREAU13032e72006-03-12 17:31:45 +0100156/* Default connections limit.
157 *
158 * A system limit can be enforced at build time in order to avoid using haproxy
159 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
160 * absolute limit accepted by the system. If the configuration specifies a
161 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
162 * emitted. The only way to override this limit will be to set it via the
163 * command-line '-n' argument.
164 */
165#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100166#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100167#else
168#define DEFAULT_MAXCONN SYSTEM_MAXCONN
169#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100170
willy tarreau0f7af912005-12-17 12:21:26 +0100171/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
172#define INTBITS 5
173
174/* show stats this every millisecond, 0 to disable */
175#ifndef STATTIME
176#define STATTIME 2000
177#endif
178
willy tarreau5cbea6f2005-12-17 12:48:26 +0100179/* this reduces the number of calls to select() by choosing appropriate
180 * sheduler precision in milliseconds. It should be near the minimum
181 * time that is needed by select() to collect all events. All timeouts
182 * are rounded up by adding this value prior to pass it to select().
183 */
184#define SCHEDULER_RESOLUTION 9
185
willy tarreaub952e1d2005-12-18 01:31:20 +0100186#define TIME_ETERNITY -1
187/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100188#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
189#define SETNOW(a) (*a=now)
190
willy tarreau9da061b2005-12-17 12:29:56 +0100191/****** string-specific macros and functions ******/
192/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
193#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
194
195/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
196#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
197
willy tarreau0174f312005-12-18 01:02:42 +0100198/* returns 1 only if only zero or one bit is set in X, which means that X is a
199 * power of 2, and 0 otherwise */
200#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100201/*
202 * copies at most <size-1> chars from <src> to <dst>. Last char is always
203 * set to 0, unless <size> is 0. The number of chars copied is returned
204 * (excluding the terminating zero).
205 * This code has been optimized for size and speed : on x86, it's 45 bytes
206 * long, uses only registers, and consumes only 4 cycles per char.
207 */
willy tarreau750a4722005-12-17 13:21:24 +0100208int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100209 char *orig = dst;
210 if (size) {
211 while (--size && (*dst = *src)) {
212 src++; dst++;
213 }
214 *dst = 0;
215 }
216 return dst - orig;
217}
willy tarreau9da061b2005-12-17 12:29:56 +0100218
willy tarreau4302f492005-12-18 01:00:37 +0100219/*
220 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
221 * dynamically allocated. In the first case, <__pool> is updated to point to
222 * the next element in the list.
223 */
224#define pool_alloc_from(__pool, __len) ({ \
225 void *__p; \
226 if ((__p = (__pool)) == NULL) \
227 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
228 else { \
229 __pool = *(void **)(__pool); \
230 } \
231 __p; \
232})
233
234/*
235 * Puts a memory area back to the corresponding pool.
236 * Items are chained directly through a pointer that
237 * is written in the beginning of the memory area, so
238 * there's no need for any carrier cell. This implies
239 * that each memory area is at least as big as one
240 * pointer.
241 */
242#define pool_free_to(__pool, __ptr) ({ \
243 *(void **)(__ptr) = (void *)(__pool); \
244 __pool = (void *)(__ptr); \
245})
246
247
willy tarreau0f7af912005-12-17 12:21:26 +0100248#define MEM_OPTIM
249#ifdef MEM_OPTIM
250/*
251 * Returns a pointer to type <type> taken from the
252 * pool <pool_type> or dynamically allocated. In the
253 * first case, <pool_type> is updated to point to the
254 * next element in the list.
255 */
256#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100257 void *__p; \
258 if ((__p = pool_##type) == NULL) \
259 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100260 else { \
261 pool_##type = *(void **)pool_##type; \
262 } \
willy tarreau4302f492005-12-18 01:00:37 +0100263 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100264})
265
266/*
267 * Puts a memory area back to the corresponding pool.
268 * Items are chained directly through a pointer that
269 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100270 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100271 * that each memory area is at least as big as one
272 * pointer.
273 */
274#define pool_free(type, ptr) ({ \
275 *(void **)ptr = (void *)pool_##type; \
276 pool_##type = (void *)ptr; \
277})
278
279#else
280#define pool_alloc(type) (calloc(1,sizeof_##type));
281#define pool_free(type, ptr) (free(ptr));
282#endif /* MEM_OPTIM */
283
willy tarreau5cbea6f2005-12-17 12:48:26 +0100284#define sizeof_task sizeof(struct task)
285#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100286#define sizeof_buffer sizeof(struct buffer)
287#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100288#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100289#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100290#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100291#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100292
willy tarreau5cbea6f2005-12-17 12:48:26 +0100293/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100294#define FD_STCLOSE 0
295#define FD_STLISTEN 1
296#define FD_STCONN 2
297#define FD_STREADY 3
298#define FD_STERROR 4
299
willy tarreau5cbea6f2005-12-17 12:48:26 +0100300/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100301#define TASK_IDLE 0
302#define TASK_RUNNING 1
303
willy tarreau5cbea6f2005-12-17 12:48:26 +0100304/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100305#define PR_STNEW 0
306#define PR_STIDLE 1
307#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100308#define PR_STSTOPPED 3
309#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100310
willy tarreau5cbea6f2005-12-17 12:48:26 +0100311/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100312#define PR_MODE_TCP 0
313#define PR_MODE_HTTP 1
314#define PR_MODE_HEALTH 2
315
willy tarreau1c2ad212005-12-18 01:11:29 +0100316/* possible actions for the *poll() loops */
317#define POLL_LOOP_ACTION_INIT 0
318#define POLL_LOOP_ACTION_RUN 1
319#define POLL_LOOP_ACTION_CLEAN 2
320
willy tarreau64a3cc32005-12-18 01:13:11 +0100321/* poll mechanisms available */
322#define POLL_USE_SELECT (1<<0)
323#define POLL_USE_POLL (1<<1)
324#define POLL_USE_EPOLL (1<<2)
325
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100327#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
328#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
329#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
330#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
331#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
332#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
333#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
334#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100335#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100336#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
337#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
338#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
339#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
340#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
341#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
342#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
343#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
344#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
345#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
346#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100347#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
348#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100349#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100350#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100351
willy tarreaue39cd132005-12-17 13:00:18 +0100352/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100353#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
354#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
355#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
356#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
357#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
358#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100359#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100360
361#define SN_CK_NONE 0x00000000 /* this session had no cookie */
362#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
363#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
364#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
365#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
366#define SN_CK_SHIFT 6 /* bit shift */
367
willy tarreaub1285d52005-12-18 01:20:14 +0100368#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100369#define SN_ERR_CLITO 0x00000100 /* client time-out */
370#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
371#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
372#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
373#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100374#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
375#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100376#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
377#define SN_ERR_SHIFT 8 /* bit shift */
378
379#define SN_FINST_R 0x00001000 /* session ended during client request */
380#define SN_FINST_C 0x00002000 /* session ended during server connect */
381#define SN_FINST_H 0x00003000 /* session ended during server headers */
382#define SN_FINST_D 0x00004000 /* session ended during data phase */
383#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
384#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
385#define SN_FINST_SHIFT 12 /* bit shift */
386
387#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
388#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
389#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
390#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
391#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100392#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100393#define SN_SCK_SHIFT 16 /* bit shift */
394
willy tarreau97f58572005-12-18 00:53:44 +0100395#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
396#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
397#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100398
399/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100400#define CL_STHEADERS 0
401#define CL_STDATA 1
402#define CL_STSHUTR 2
403#define CL_STSHUTW 3
404#define CL_STCLOSE 4
405
willy tarreau5cbea6f2005-12-17 12:48:26 +0100406/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100407#define SV_STIDLE 0
408#define SV_STCONN 1
409#define SV_STHEADERS 2
410#define SV_STDATA 3
411#define SV_STSHUTR 4
412#define SV_STSHUTW 5
413#define SV_STCLOSE 6
414
415/* result of an I/O event */
416#define RES_SILENT 0 /* didn't happen */
417#define RES_DATA 1 /* data were sent or received */
418#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
419#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
420
willy tarreau9fe663a2005-12-17 13:02:59 +0100421/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100422#define MODE_DEBUG 1
423#define MODE_STATS 2
424#define MODE_LOG 4
425#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100426#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100427#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100428#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100429#define MODE_STARTING 128
willy tarreau5cbea6f2005-12-17 12:48:26 +0100430
431/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100432#define SRV_RUNNING 1 /* the server is UP */
433#define SRV_BACKUP 2 /* this server is a backup server */
434#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100435#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100436#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100437
willy tarreaue39cd132005-12-17 13:00:18 +0100438/* what to do when a header matches a regex */
439#define ACT_ALLOW 0 /* allow the request */
440#define ACT_REPLACE 1 /* replace the matching header */
441#define ACT_REMOVE 2 /* remove the matching header */
442#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100443#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100444
willy tarreau9fe663a2005-12-17 13:02:59 +0100445/* configuration sections */
446#define CFG_NONE 0
447#define CFG_GLOBAL 1
448#define CFG_LISTEN 2
449
willy tarreaua1598082005-12-17 13:08:06 +0100450/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100451#define LW_DATE 1 /* date */
452#define LW_CLIP 2 /* CLient IP */
453#define LW_SVIP 4 /* SerVer IP */
454#define LW_SVID 8 /* server ID */
455#define LW_REQ 16 /* http REQuest */
456#define LW_RESP 32 /* http RESPonse */
457#define LW_PXIP 64 /* proxy IP */
458#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100459#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100460#define LW_COOKIE 512 /* captured cookie */
461#define LW_REQHDR 1024 /* request header(s) */
462#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100463
willy tarreau0f7af912005-12-17 12:21:26 +0100464/*********************************************************************/
465
466#define LIST_HEAD(a) ((void *)(&(a)))
467
468/*********************************************************************/
469
willy tarreau4302f492005-12-18 01:00:37 +0100470struct cap_hdr {
471 struct cap_hdr *next;
472 char *name; /* header name, case insensitive */
473 int namelen; /* length of the header name, to speed-up lookups */
474 int len; /* capture length, not including terminal zero */
475 int index; /* index in the output array */
476 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
477};
478
willy tarreau0f7af912005-12-17 12:21:26 +0100479struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100480 struct hdr_exp *next;
481 regex_t *preg; /* expression to look for */
482 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
483 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100484};
485
486struct buffer {
487 unsigned int l; /* data length */
488 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100489 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100490 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100491 char data[BUFSIZE];
492};
493
494struct server {
495 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100496 int state; /* server state (SRV_*) */
497 int cklen; /* the len of the cookie, to speed up checks */
498 char *cookie; /* the id set in the cookie */
499 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100500 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100501 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100502 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100503 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100504 int rise, fall; /* time in iterations */
505 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100506 int result; /* 0 = connect OK, -1 = connect KO */
507 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100508 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100509};
510
willy tarreau5cbea6f2005-12-17 12:48:26 +0100511/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100512struct task {
513 struct task *next, *prev; /* chaining ... */
514 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100515 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100516 int state; /* task state : IDLE or RUNNING */
517 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100518 int (*process)(struct task *t); /* the function which processes the task */
519 void *context; /* the task's context */
520};
521
522/* WARNING: if new fields are added, they must be initialized in event_accept() */
523struct session {
524 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100525 /* application specific below */
526 struct timeval crexpire; /* expiration date for a client read */
527 struct timeval cwexpire; /* expiration date for a client write */
528 struct timeval srexpire; /* expiration date for a server read */
529 struct timeval swexpire; /* expiration date for a server write */
530 struct timeval cnexpire; /* expiration date for a connect */
531 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
532 struct proxy *proxy; /* the proxy this socket belongs to */
533 int cli_fd; /* the client side fd */
534 int srv_fd; /* the server side fd */
535 int cli_state; /* state of the client side */
536 int srv_state; /* state of the server side */
537 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100538 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100539 struct buffer *req; /* request buffer */
540 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100541 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100542 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100543 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100544 char **req_cap; /* array of captured request headers (may be NULL) */
545 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100546 struct {
547 int logwait; /* log fields waiting to be collected : LW_* */
548 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
549 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
550 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
551 long t_data; /* delay before the first data byte from the server ... */
552 unsigned long t_close; /* total session duration */
553 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100554 char *cli_cookie; /* cookie presented by the client, in capture mode */
555 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100556 int status; /* HTTP status from the server, negative if from proxy */
557 long long bytes; /* number of bytes transferred from the server */
558 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100559 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100560};
561
willy tarreaua41a8b42005-12-17 14:02:24 +0100562struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100563 int fd; /* the listen socket */
564 struct sockaddr_storage addr; /* the address we listen to */
565 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100566};
567
568
willy tarreau0f7af912005-12-17 12:21:26 +0100569struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100570 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100571 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 +0100572 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100573 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100574 struct server *srv, *cursrv; /* known servers, current server */
willy tarreau62084d42006-03-24 18:57:41 +0100575 int srv_act, srv_bck; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100576 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100577 int cookie_len; /* strlen(cookie_name), computed only once */
578 char *appsession_name; /* name of the cookie to look for */
579 int appsession_name_len; /* strlen(appsession_name), computed only once */
580 int appsession_len; /* length of the appsession cookie value to be used */
581 int appsession_timeout;
582 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100583 char *capture_name; /* beginning of the name of the cookie to capture */
584 int capture_namelen; /* length of the cookie name to match */
585 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100586 int clitimeout; /* client I/O timeout (in milliseconds) */
587 int srvtimeout; /* server I/O timeout (in milliseconds) */
588 int contimeout; /* connect timeout (in milliseconds) */
589 char *id; /* proxy id */
590 int nbconn; /* # of active sessions */
591 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100592 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100593 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100594 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100595 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100596 struct proxy *next;
597 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100598 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100599 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100600 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100601 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100602 int nb_reqadd, nb_rspadd;
603 struct hdr_exp *req_exp; /* regular expressions for request headers */
604 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100605 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
606 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
607 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
608 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100609 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100610 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100611 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
612 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100613 struct {
614 char *msg400; /* message for error 400 */
615 int len400; /* message length for error 400 */
616 char *msg403; /* message for error 403 */
617 int len403; /* message length for error 403 */
618 char *msg408; /* message for error 408 */
619 int len408; /* message length for error 408 */
620 char *msg500; /* message for error 500 */
621 int len500; /* message length for error 500 */
622 char *msg502; /* message for error 502 */
623 int len502; /* message length for error 502 */
624 char *msg503; /* message for error 503 */
625 int len503; /* message length for error 503 */
626 char *msg504; /* message for error 504 */
627 int len504; /* message length for error 504 */
628 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100629};
630
631/* info about one given fd */
632struct fdtab {
633 int (*read)(int fd); /* read function */
634 int (*write)(int fd); /* write function */
635 struct task *owner; /* the session (or proxy) associated with this fd */
636 int state; /* the state of this fd */
637};
638
639/*********************************************************************/
640
willy tarreaub952e1d2005-12-18 01:31:20 +0100641int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100642int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100643char *cfg_cfgfile = NULL; /* configuration file */
644char *progname = NULL; /* program name */
645int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100646
647/* global options */
648static struct {
649 int uid;
650 int gid;
651 int nbproc;
652 int maxconn;
653 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100654 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100655 int mode;
656 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100657 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100658 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100659 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100660 struct sockaddr_in logsrv1, logsrv2;
661} global = {
662 logfac1 : -1,
663 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100664 loglev1 : 7, /* max syslog level : debug */
665 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100666 /* others NULL OK */
667};
668
willy tarreau0f7af912005-12-17 12:21:26 +0100669/*********************************************************************/
670
willy tarreau1c2ad212005-12-18 01:11:29 +0100671fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100672 *StaticWriteEvent;
673
willy tarreau64a3cc32005-12-18 01:13:11 +0100674int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100675
willy tarreau0f7af912005-12-17 12:21:26 +0100676void **pool_session = NULL,
677 **pool_buffer = NULL,
678 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100679 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100680 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100681 **pool_capture = NULL,
682 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100683
684struct proxy *proxy = NULL; /* list of all existing proxies */
685struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100686struct task *rq = NULL; /* global run queue */
687struct task wait_queue = { /* global wait queue */
688 prev:LIST_HEAD(wait_queue),
689 next:LIST_HEAD(wait_queue)
690};
willy tarreau0f7af912005-12-17 12:21:26 +0100691
willy tarreau0f7af912005-12-17 12:21:26 +0100692static int totalconn = 0; /* total # of terminated sessions */
693static int actconn = 0; /* # of active sessions */
694static int maxfd = 0; /* # of the highest fd + 1 */
695static int listeners = 0; /* # of listeners */
696static int stopping = 0; /* non zero means stopping in progress */
697static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100698static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100699
willy tarreau08dedbe2005-12-18 01:13:48 +0100700#if defined(ENABLE_EPOLL)
701/* FIXME: this is dirty, but at the moment, there's no other solution to remove
702 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
703 * structure with pointers to functions such as init_fd() and close_fd(), plus
704 * a private structure with several pointers to places such as below.
705 */
706
707static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
708#endif
709
willy tarreau0f7af912005-12-17 12:21:26 +0100710static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100711/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100712static char trash[BUFSIZE];
713
willy tarreaudd07e972005-12-18 00:48:48 +0100714const int zero = 0;
715const int one = 1;
716
willy tarreau0f7af912005-12-17 12:21:26 +0100717/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100718 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100719 */
720
721#define MAX_SYSLOG_LEN 1024
722#define NB_LOG_FACILITIES 24
723const char *log_facilities[NB_LOG_FACILITIES] = {
724 "kern", "user", "mail", "daemon",
725 "auth", "syslog", "lpr", "news",
726 "uucp", "cron", "auth2", "ftp",
727 "ntp", "audit", "alert", "cron2",
728 "local0", "local1", "local2", "local3",
729 "local4", "local5", "local6", "local7"
730};
731
732
733#define NB_LOG_LEVELS 8
734const char *log_levels[NB_LOG_LEVELS] = {
735 "emerg", "alert", "crit", "err",
736 "warning", "notice", "info", "debug"
737};
738
739#define SYSLOG_PORT 514
740
741const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
742 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100743
willy tarreaub1285d52005-12-18 01:20:14 +0100744const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100745const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
746const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
747const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
748 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
749 unknown, Set-cookie Rewritten */
750
willy tarreau0f7af912005-12-17 12:21:26 +0100751#define MAX_HOSTNAME_LEN 32
752static char hostname[MAX_HOSTNAME_LEN] = "";
753
willy tarreau8337c6b2005-12-17 13:41:01 +0100754const char *HTTP_302 =
755 "HTTP/1.0 302 Found\r\n"
756 "Cache-Control: no-cache\r\n"
757 "Connection: close\r\n"
758 "Location: "; /* not terminated since it will be concatenated with the URL */
759
willy tarreauc1f47532005-12-18 01:08:26 +0100760/* same as 302 except that the browser MUST retry with the GET method */
761const char *HTTP_303 =
762 "HTTP/1.0 303 See Other\r\n"
763 "Cache-Control: no-cache\r\n"
764 "Connection: close\r\n"
765 "Location: "; /* not terminated since it will be concatenated with the URL */
766
willy tarreaua1598082005-12-17 13:08:06 +0100767const char *HTTP_400 =
768 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100769 "Cache-Control: no-cache\r\n"
770 "Connection: close\r\n"
771 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100772 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100773
willy tarreaua1598082005-12-17 13:08:06 +0100774const char *HTTP_403 =
775 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100776 "Cache-Control: no-cache\r\n"
777 "Connection: close\r\n"
778 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100779 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
780
willy tarreau8337c6b2005-12-17 13:41:01 +0100781const char *HTTP_408 =
782 "HTTP/1.0 408 Request Time-out\r\n"
783 "Cache-Control: no-cache\r\n"
784 "Connection: close\r\n"
785 "\r\n"
786 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
787
willy tarreau750a4722005-12-17 13:21:24 +0100788const char *HTTP_500 =
789 "HTTP/1.0 500 Server Error\r\n"
790 "Cache-Control: no-cache\r\n"
791 "Connection: close\r\n"
792 "\r\n"
793 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100794
795const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100796 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100797 "Cache-Control: no-cache\r\n"
798 "Connection: close\r\n"
799 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100800 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
801
802const char *HTTP_503 =
803 "HTTP/1.0 503 Service Unavailable\r\n"
804 "Cache-Control: no-cache\r\n"
805 "Connection: close\r\n"
806 "\r\n"
807 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
808
809const char *HTTP_504 =
810 "HTTP/1.0 504 Gateway Time-out\r\n"
811 "Cache-Control: no-cache\r\n"
812 "Connection: close\r\n"
813 "\r\n"
814 "<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 +0100815
willy tarreau0f7af912005-12-17 12:21:26 +0100816/*********************************************************************/
817/* statistics ******************************************************/
818/*********************************************************************/
819
willy tarreau750a4722005-12-17 13:21:24 +0100820#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100821static int stats_tsk_lsrch, stats_tsk_rsrch,
822 stats_tsk_good, stats_tsk_right, stats_tsk_left,
823 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100824#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100825
826
827/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100828/* debugging *******************************************************/
829/*********************************************************************/
830#ifdef DEBUG_FULL
831static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
832static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
833#endif
834
835/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100836/* function prototypes *********************************************/
837/*********************************************************************/
838
839int event_accept(int fd);
840int event_cli_read(int fd);
841int event_cli_write(int fd);
842int event_srv_read(int fd);
843int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100844int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100845
willy tarreau12350152005-12-18 01:03:27 +0100846static int appsession_task_init(void);
847static int appsession_init(void);
848static int appsession_refresh(struct task *t);
849
willy tarreau0f7af912005-12-17 12:21:26 +0100850/*********************************************************************/
851/* general purpose functions ***************************************/
852/*********************************************************************/
853
854void display_version() {
855 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100856 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100857}
858
859/*
860 * This function prints the command line usage and exits
861 */
862void usage(char *name) {
863 display_version();
864 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100865 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100866#if STATTIME > 0
867 "sl"
868#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100869 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100870 " -v displays version\n"
871 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100872 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100873#if STATTIME > 0
874 " -s enables statistics output\n"
875 " -l enables long statistics format\n"
876#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100877 " -D goes daemon ; implies -q\n"
878 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100879 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100880 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100881 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100882 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100883#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100884 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100885#endif
886#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100887 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100888#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100889 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100890 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100891 exit(1);
892}
893
894
895/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100896 * Displays the message on stderr with the date and pid. Overrides the quiet
897 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100898 */
899void Alert(char *fmt, ...) {
900 va_list argp;
901 struct timeval tv;
902 struct tm *tm;
903
willy tarreaud0fb4652005-12-18 01:32:04 +0100904 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100905 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100906
willy tarreau5cbea6f2005-12-17 12:48:26 +0100907 gettimeofday(&tv, NULL);
908 tm=localtime(&tv.tv_sec);
909 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100910 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100911 vfprintf(stderr, fmt, argp);
912 fflush(stderr);
913 va_end(argp);
914 }
willy tarreau0f7af912005-12-17 12:21:26 +0100915}
916
917
918/*
919 * Displays the message on stderr with the date and pid.
920 */
921void Warning(char *fmt, ...) {
922 va_list argp;
923 struct timeval tv;
924 struct tm *tm;
925
willy tarreau982249e2005-12-18 00:57:06 +0100926 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100927 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100928
willy tarreau5cbea6f2005-12-17 12:48:26 +0100929 gettimeofday(&tv, NULL);
930 tm=localtime(&tv.tv_sec);
931 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100932 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100933 vfprintf(stderr, fmt, argp);
934 fflush(stderr);
935 va_end(argp);
936 }
937}
938
939/*
940 * Displays the message on <out> only if quiet mode is not set.
941 */
942void qfprintf(FILE *out, char *fmt, ...) {
943 va_list argp;
944
willy tarreau982249e2005-12-18 00:57:06 +0100945 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100946 va_start(argp, fmt);
947 vfprintf(out, fmt, argp);
948 fflush(out);
949 va_end(argp);
950 }
willy tarreau0f7af912005-12-17 12:21:26 +0100951}
952
953
954/*
955 * converts <str> to a struct sockaddr_in* which is locally allocated.
956 * The format is "addr:port", where "addr" can be empty or "*" to indicate
957 * INADDR_ANY.
958 */
959struct sockaddr_in *str2sa(char *str) {
960 static struct sockaddr_in sa;
961 char *c;
962 int port;
963
willy tarreaua1598082005-12-17 13:08:06 +0100964 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100965 str=strdup(str);
966
967 if ((c=strrchr(str,':')) != NULL) {
968 *c++=0;
969 port=atol(c);
970 }
971 else
972 port=0;
973
974 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
975 sa.sin_addr.s_addr = INADDR_ANY;
976 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100977 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100978 struct hostent *he;
979
980 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100981 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100982 }
983 else
984 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
985 }
986 sa.sin_port=htons(port);
987 sa.sin_family=AF_INET;
988
989 free(str);
990 return &sa;
991}
992
willy tarreaub1285d52005-12-18 01:20:14 +0100993/*
994 * converts <str> to a two struct in_addr* which are locally allocated.
995 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
996 * is optionnal and either in the dotted or CIDR notation.
997 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
998 */
999int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1000 char *c;
1001 unsigned long len;
1002
1003 memset(mask, 0, sizeof(*mask));
1004 memset(addr, 0, sizeof(*addr));
1005 str=strdup(str);
1006
1007 if ((c = strrchr(str, '/')) != NULL) {
1008 *c++ = 0;
1009 /* c points to the mask */
1010 if (strchr(c, '.') != NULL) { /* dotted notation */
1011 if (!inet_pton(AF_INET, c, mask))
1012 return 0;
1013 }
1014 else { /* mask length */
1015 char *err;
1016 len = strtol(c, &err, 10);
1017 if (!*c || (err && *err) || (unsigned)len > 32)
1018 return 0;
1019 if (len)
1020 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1021 else
1022 mask->s_addr = 0;
1023 }
1024 }
1025 else {
1026 mask->s_addr = 0xFFFFFFFF;
1027 }
1028 if (!inet_pton(AF_INET, str, addr)) {
1029 struct hostent *he;
1030
1031 if ((he = gethostbyname(str)) == NULL) {
1032 return 0;
1033 }
1034 else
1035 *addr = *(struct in_addr *) *(he->h_addr_list);
1036 }
1037 free(str);
1038 return 1;
1039}
1040
willy tarreau9fe663a2005-12-17 13:02:59 +01001041
1042/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001043 * converts <str> to a list of listeners which are dynamically allocated.
1044 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1045 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1046 * - <port> is a numerical port from 1 to 65535 ;
1047 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1048 * This can be repeated as many times as necessary, separated by a coma.
1049 * The <tail> argument is a pointer to a current list which should be appended
1050 * to the tail of the new list. The pointer to the new list is returned.
1051 */
1052struct listener *str2listener(char *str, struct listener *tail) {
1053 struct listener *l;
1054 char *c, *next, *range, *dupstr;
1055 int port, end;
1056
1057 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001058
willy tarreaua41a8b42005-12-17 14:02:24 +01001059 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001060 struct sockaddr_storage ss;
1061
willy tarreaua41a8b42005-12-17 14:02:24 +01001062 str = next;
1063 /* 1) look for the end of the first address */
1064 if ((next = strrchr(str, ',')) != NULL) {
1065 *next++ = 0;
1066 }
1067
willy tarreau8a86dbf2005-12-18 00:45:59 +01001068 /* 2) look for the addr/port delimiter, it's the last colon. */
1069 if ((range = strrchr(str, ':')) == NULL) {
1070 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001071 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001072 }
1073
1074 *range++ = 0;
1075
1076 if (strrchr(str, ':') != NULL) {
1077 /* IPv6 address contains ':' */
1078 memset(&ss, 0, sizeof(ss));
1079 ss.ss_family = AF_INET6;
1080
1081 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1082 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001083 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001084 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001085 }
1086 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001087 memset(&ss, 0, sizeof(ss));
1088 ss.ss_family = AF_INET;
1089
1090 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1091 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1092 }
1093 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1094 struct hostent *he;
1095
1096 if ((he = gethostbyname(str)) == NULL) {
1097 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001098 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001099 }
1100 else
1101 ((struct sockaddr_in *)&ss)->sin_addr =
1102 *(struct in_addr *) *(he->h_addr_list);
1103 }
1104 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001105
1106 /* 3) look for the port-end delimiter */
1107 if ((c = strchr(range, '-')) != NULL) {
1108 *c++ = 0;
1109 end = atol(c);
1110 }
1111 else {
1112 end = atol(range);
1113 }
1114
willy tarreaud0fb4652005-12-18 01:32:04 +01001115 port = atol(range);
1116
1117 if (port < 1 || port > 65535) {
1118 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1119 goto fail;
1120 }
1121
1122 if (end < 1 || end > 65535) {
1123 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1124 goto fail;
1125 }
1126
1127 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001128 l = (struct listener *)calloc(1, sizeof(struct listener));
1129 l->next = tail;
1130 tail = l;
1131
willy tarreau8a86dbf2005-12-18 00:45:59 +01001132 l->addr = ss;
1133 if (ss.ss_family == AF_INET6)
1134 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1135 else
1136 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1137
willy tarreaua41a8b42005-12-17 14:02:24 +01001138 } /* end for(port) */
1139 } /* end while(next) */
1140 free(dupstr);
1141 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001142 fail:
1143 free(dupstr);
1144 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001145}
1146
willy tarreau4302f492005-12-18 01:00:37 +01001147
1148#define FD_SETS_ARE_BITFIELDS
1149#ifdef FD_SETS_ARE_BITFIELDS
1150/*
1151 * This map is used with all the FD_* macros to check whether a particular bit
1152 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1153 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1154 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1155 * exclusively to the macros.
1156 */
1157fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1158fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1159
1160#else
1161#error "Check if your OS uses bitfields for fd_sets"
1162#endif
1163
1164/* will try to encode the string <string> replacing all characters tagged in
1165 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1166 * prefixed by <escape>, and will store the result between <start> (included
1167 *) and <stop> (excluded), and will always terminate the string with a '\0'
1168 * before <stop>. The position of the '\0' is returned if the conversion
1169 * completes. If bytes are missing between <start> and <stop>, then the
1170 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1171 * cannot even be stored so we return <start> without writing the 0.
1172 * The input string must also be zero-terminated.
1173 */
1174char hextab[16] = "0123456789ABCDEF";
1175char *encode_string(char *start, char *stop,
1176 const char escape, const fd_set *map,
1177 const char *string)
1178{
1179 if (start < stop) {
1180 stop--; /* reserve one byte for the final '\0' */
1181 while (start < stop && *string != 0) {
1182 if (!FD_ISSET((unsigned char)(*string), map))
1183 *start++ = *string;
1184 else {
1185 if (start + 3 >= stop)
1186 break;
1187 *start++ = escape;
1188 *start++ = hextab[(*string >> 4) & 15];
1189 *start++ = hextab[*string & 15];
1190 }
1191 string++;
1192 }
1193 *start = '\0';
1194 }
1195 return start;
1196}
willy tarreaua41a8b42005-12-17 14:02:24 +01001197
1198/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001199 * This function sends a syslog message to both log servers of a proxy,
1200 * or to global log servers if the proxy is NULL.
1201 * It also tries not to waste too much time computing the message header.
1202 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001203 */
1204void send_log(struct proxy *p, int level, char *message, ...) {
1205 static int logfd = -1; /* syslog UDP socket */
1206 static long tvsec = -1; /* to force the string to be initialized */
1207 struct timeval tv;
1208 va_list argp;
1209 static char logmsg[MAX_SYSLOG_LEN];
1210 static char *dataptr = NULL;
1211 int fac_level;
1212 int hdr_len, data_len;
1213 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001214 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001215 int nbloggers = 0;
1216 char *log_ptr;
1217
1218 if (logfd < 0) {
1219 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1220 return;
1221 }
1222
1223 if (level < 0 || progname == NULL || message == NULL)
1224 return;
1225
1226 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001227 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001228 /* this string is rebuild only once a second */
1229 struct tm *tm = localtime(&tv.tv_sec);
1230 tvsec = tv.tv_sec;
1231
willy tarreauc29948c2005-12-17 13:10:27 +01001232 hdr_len = snprintf(logmsg, sizeof(logmsg),
1233 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1234 monthname[tm->tm_mon],
1235 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1236 progname, pid);
1237 /* WARNING: depending upon implementations, snprintf may return
1238 * either -1 or the number of bytes that would be needed to store
1239 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001240 */
willy tarreauc29948c2005-12-17 13:10:27 +01001241 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1242 hdr_len = sizeof(logmsg);
1243
1244 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001245 }
1246
1247 va_start(argp, message);
1248 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001249 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1250 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001251 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001252 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001253
1254 if (p == NULL) {
1255 if (global.logfac1 >= 0) {
1256 sa[nbloggers] = &global.logsrv1;
1257 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001258 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001259 nbloggers++;
1260 }
1261 if (global.logfac2 >= 0) {
1262 sa[nbloggers] = &global.logsrv2;
1263 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001264 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001265 nbloggers++;
1266 }
1267 } else {
1268 if (p->logfac1 >= 0) {
1269 sa[nbloggers] = &p->logsrv1;
1270 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001271 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001272 nbloggers++;
1273 }
1274 if (p->logfac2 >= 0) {
1275 sa[nbloggers] = &p->logsrv2;
1276 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001277 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001278 nbloggers++;
1279 }
1280 }
1281
1282 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001283 /* we can filter the level of the messages that are sent to each logger */
1284 if (level > loglevel[nbloggers])
1285 continue;
1286
willy tarreauc29948c2005-12-17 13:10:27 +01001287 /* For each target, we may have a different facility.
1288 * We can also have a different log level for each message.
1289 * This induces variations in the message header length.
1290 * Since we don't want to recompute it each time, nor copy it every
1291 * time, we only change the facility in the pre-computed header,
1292 * and we change the pointer to the header accordingly.
1293 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001294 fac_level = (facilities[nbloggers] << 3) + level;
1295 log_ptr = logmsg + 3; /* last digit of the log level */
1296 do {
1297 *log_ptr = '0' + fac_level % 10;
1298 fac_level /= 10;
1299 log_ptr--;
1300 } while (fac_level && log_ptr > logmsg);
1301 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001302
willy tarreauc29948c2005-12-17 13:10:27 +01001303 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001304
1305#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001306 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001307 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1308#else
willy tarreauc29948c2005-12-17 13:10:27 +01001309 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001310 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1311#endif
1312 }
willy tarreau0f7af912005-12-17 12:21:26 +01001313}
1314
1315
1316/* sets <tv> to the current time */
1317static inline struct timeval *tv_now(struct timeval *tv) {
1318 if (tv)
1319 gettimeofday(tv, NULL);
1320 return tv;
1321}
1322
1323/*
1324 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1325 */
1326static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1327 if (!tv || !from)
1328 return NULL;
1329 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1330 tv->tv_sec = from->tv_sec + (ms/1000);
1331 while (tv->tv_usec >= 1000000) {
1332 tv->tv_usec -= 1000000;
1333 tv->tv_sec++;
1334 }
1335 return tv;
1336}
1337
1338/*
1339 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001340 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001341 */
1342static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001343 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001344 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001345 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001346 return 1;
1347 else if (tv1->tv_usec < tv2->tv_usec)
1348 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001349 else if (tv1->tv_usec > tv2->tv_usec)
1350 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001351 else
1352 return 0;
1353}
1354
1355/*
1356 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001357 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001358 */
1359unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1360 int cmp;
1361 unsigned long ret;
1362
1363
willy tarreauef900ab2005-12-17 12:52:52 +01001364 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001365 if (!cmp)
1366 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001367 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001368 struct timeval *tmp = tv1;
1369 tv1 = tv2;
1370 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001371 }
willy tarreauef900ab2005-12-17 12:52:52 +01001372 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001373 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001374 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001375 else
willy tarreauef900ab2005-12-17 12:52:52 +01001376 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001377 return (unsigned long) ret;
1378}
1379
1380/*
willy tarreau750a4722005-12-17 13:21:24 +01001381 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001382 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001383 */
1384static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1385 unsigned long ret;
1386
willy tarreau6e682ce2005-12-17 13:26:49 +01001387 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1388 if (tv2->tv_usec > tv1->tv_usec)
1389 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001390 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001391 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001392 return (unsigned long) ret;
1393}
1394
1395/*
willy tarreau0f7af912005-12-17 12:21:26 +01001396 * 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 +01001397 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001398 */
1399static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001400 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001401 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001402 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001403 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001404 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001405 else
1406 return 0;
1407 }
willy tarreau0f7af912005-12-17 12:21:26 +01001408 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001409 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001410 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001411 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001412 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001413 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001414 else
1415 return 0;
1416}
1417
1418/*
1419 * returns the remaining time between tv1=now and event=tv2
1420 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001421 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001422 */
1423static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1424 unsigned long ret;
1425
willy tarreau0f7af912005-12-17 12:21:26 +01001426 if (tv_cmp_ms(tv1, tv2) >= 0)
1427 return 0; /* event elapsed */
1428
willy tarreauef900ab2005-12-17 12:52:52 +01001429 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001430 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001431 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001432 else
willy tarreauef900ab2005-12-17 12:52:52 +01001433 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001434 return (unsigned long) ret;
1435}
1436
1437
1438/*
1439 * zeroes a struct timeval
1440 */
1441
1442static inline struct timeval *tv_eternity(struct timeval *tv) {
1443 tv->tv_sec = tv->tv_usec = 0;
1444 return tv;
1445}
1446
1447/*
1448 * returns 1 if tv is null, else 0
1449 */
1450static inline int tv_iseternity(struct timeval *tv) {
1451 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1452 return 1;
1453 else
1454 return 0;
1455}
1456
1457/*
1458 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1459 * considering that 0 is the eternity.
1460 */
1461static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1462 if (tv_iseternity(tv1))
1463 if (tv_iseternity(tv2))
1464 return 0; /* same */
1465 else
1466 return 1; /* tv1 later than tv2 */
1467 else if (tv_iseternity(tv2))
1468 return -1; /* tv2 later than tv1 */
1469
1470 if (tv1->tv_sec > tv2->tv_sec)
1471 return 1;
1472 else if (tv1->tv_sec < tv2->tv_sec)
1473 return -1;
1474 else if (tv1->tv_usec > tv2->tv_usec)
1475 return 1;
1476 else if (tv1->tv_usec < tv2->tv_usec)
1477 return -1;
1478 else
1479 return 0;
1480}
1481
1482/*
1483 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1484 * considering that 0 is the eternity.
1485 */
1486static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1487 if (tv_iseternity(tv1))
1488 if (tv_iseternity(tv2))
1489 return 0; /* same */
1490 else
1491 return 1; /* tv1 later than tv2 */
1492 else if (tv_iseternity(tv2))
1493 return -1; /* tv2 later than tv1 */
1494
willy tarreauefae1842005-12-17 12:51:03 +01001495 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001496 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001497 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001498 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001499 return -1;
1500 else
1501 return 0;
1502 }
1503 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 tarreau0f7af912005-12-17 12:21:26 +01001505 return 1;
1506 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001507 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001508 return -1;
1509 else
1510 return 0;
1511}
1512
1513/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001514 * returns the remaining time between tv1=now and event=tv2
1515 * if tv2 is passed, 0 is returned.
1516 * Returns TIME_ETERNITY if tv2 is eternity.
1517 */
1518static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1519 unsigned long ret;
1520
1521 if (tv_iseternity(tv2))
1522 return TIME_ETERNITY;
1523
1524 if (tv_cmp_ms(tv1, tv2) >= 0)
1525 return 0; /* event elapsed */
1526
1527 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1528 if (tv2->tv_usec > tv1->tv_usec)
1529 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1530 else
1531 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1532 return (unsigned long) ret;
1533}
1534
1535/*
willy tarreau0f7af912005-12-17 12:21:26 +01001536 * returns the first event between tv1 and tv2 into tvmin.
1537 * a zero tv is ignored. tvmin is returned.
1538 */
1539static inline struct timeval *tv_min(struct timeval *tvmin,
1540 struct timeval *tv1, struct timeval *tv2) {
1541
1542 if (tv_cmp2(tv1, tv2) <= 0)
1543 *tvmin = *tv1;
1544 else
1545 *tvmin = *tv2;
1546
1547 return tvmin;
1548}
1549
1550
1551
1552/***********************************************************/
1553/* fd management ***************************************/
1554/***********************************************************/
1555
1556
1557
willy tarreau5cbea6f2005-12-17 12:48:26 +01001558/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1559 * The file descriptor is also closed.
1560 */
willy tarreau0f7af912005-12-17 12:21:26 +01001561static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001562 FD_CLR(fd, StaticReadEvent);
1563 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001564#if defined(ENABLE_EPOLL)
1565 if (PrevReadEvent) {
1566 FD_CLR(fd, PrevReadEvent);
1567 FD_CLR(fd, PrevWriteEvent);
1568 }
1569#endif
1570
willy tarreau5cbea6f2005-12-17 12:48:26 +01001571 close(fd);
1572 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001573
1574 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1575 maxfd--;
1576}
1577
1578/* recomputes the maxfd limit from the fd */
1579static inline void fd_insert(int fd) {
1580 if (fd+1 > maxfd)
1581 maxfd = fd+1;
1582}
1583
1584/*************************************************************/
1585/* task management ***************************************/
1586/*************************************************************/
1587
willy tarreau5cbea6f2005-12-17 12:48:26 +01001588/* puts the task <t> in run queue <q>, and returns <t> */
1589static inline struct task *task_wakeup(struct task **q, struct task *t) {
1590 if (t->state == TASK_RUNNING)
1591 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001592 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001593 t->rqnext = *q;
1594 t->state = TASK_RUNNING;
1595 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001596 }
1597}
1598
willy tarreau5cbea6f2005-12-17 12:48:26 +01001599/* removes the task <t> from the queue <q>
1600 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001601 * set the run queue to point to the next one, and return it
1602 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001603static inline struct task *task_sleep(struct task **q, struct task *t) {
1604 if (t->state == TASK_RUNNING) {
1605 *q = t->rqnext;
1606 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001607 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001608 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001609}
1610
1611/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001612 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001613 * from the run queue. A pointer to the task itself is returned.
1614 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001615static inline struct task *task_delete(struct task *t) {
1616 t->prev->next = t->next;
1617 t->next->prev = t->prev;
1618 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001619}
1620
1621/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001622 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001623 */
1624static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001625 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001626}
1627
willy tarreau5cbea6f2005-12-17 12:48:26 +01001628/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001629 * may be only moved or left where it was, depending on its timing requirements.
1630 * <task> is returned.
1631 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001632struct task *task_queue(struct task *task) {
1633 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001634 struct task *start_from;
1635
1636 /* first, test if the task was already in a list */
1637 if (task->prev == NULL) {
1638 // start_from = list;
1639 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001640#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001641 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001642#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001643 /* insert the unlinked <task> into the list, searching back from the last entry */
1644 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1645 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001646#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001647 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001648#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001649 }
1650
1651 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1652 // start_from = start_from->next;
1653 // stats_tsk_nsrch++;
1654 // }
1655 }
1656 else if (task->prev == list ||
1657 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1658 start_from = task->next;
1659 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001660#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001661 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001662#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001663 return task; /* it's already in the right place */
1664 }
1665
willy tarreau750a4722005-12-17 13:21:24 +01001666#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001667 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001668#endif
1669
1670 /* if the task is not at the right place, there's little chance that
1671 * it has only shifted a bit, and it will nearly always be queued
1672 * at the end of the list because of constant timeouts
1673 * (observed in real case).
1674 */
1675#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1676 start_from = list->prev; /* assume we'll queue to the end of the list */
1677 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1678 start_from = start_from->prev;
1679#if STATTIME > 0
1680 stats_tsk_lsrch++;
1681#endif
1682 }
1683#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001684 /* insert the unlinked <task> into the list, searching after position <start_from> */
1685 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1686 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001687#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001688 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001689#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001690 }
willy tarreau750a4722005-12-17 13:21:24 +01001691#endif /* WE_REALLY_... */
1692
willy tarreau0f7af912005-12-17 12:21:26 +01001693 /* we need to unlink it now */
1694 task_delete(task);
1695 }
1696 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001697#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001698 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001699#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001700#ifdef LEFT_TO_TOP /* not very good */
1701 start_from = list;
1702 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1703 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001704#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001705 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001706#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001707 }
1708#else
1709 start_from = task->prev->prev; /* valid because of the previous test above */
1710 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1711 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001712#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001713 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001714#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001715 }
1716#endif
1717 /* we need to unlink it now */
1718 task_delete(task);
1719 }
1720 task->prev = start_from;
1721 task->next = start_from->next;
1722 task->next->prev = task;
1723 start_from->next = task;
1724 return task;
1725}
1726
1727
1728/*********************************************************************/
1729/* more specific functions ***************************************/
1730/*********************************************************************/
1731
1732/* some prototypes */
1733static int maintain_proxies(void);
1734
willy tarreaub952e1d2005-12-18 01:31:20 +01001735/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001736 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1737 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001738static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001739#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001740 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1741#else
willy tarreaua1598082005-12-17 13:08:06 +01001742#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001743 return getsockname(fd, (struct sockaddr *)sa, salen);
1744#else
1745 return -1;
1746#endif
1747#endif
1748}
1749
1750/*
1751 * frees the context associated to a session. It must have been removed first.
1752 */
1753static inline void session_free(struct session *s) {
1754 if (s->req)
1755 pool_free(buffer, s->req);
1756 if (s->rep)
1757 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001758
1759 if (s->rsp_cap != NULL) {
1760 struct cap_hdr *h;
1761 for (h = s->proxy->rsp_cap; h; h = h->next) {
1762 if (s->rsp_cap[h->index] != NULL)
1763 pool_free_to(h->pool, s->rsp_cap[h->index]);
1764 }
1765 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1766 }
1767 if (s->req_cap != NULL) {
1768 struct cap_hdr *h;
1769 for (h = s->proxy->req_cap; h; h = h->next) {
1770 if (s->req_cap[h->index] != NULL)
1771 pool_free_to(h->pool, s->req_cap[h->index]);
1772 }
1773 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1774 }
1775
willy tarreaua1598082005-12-17 13:08:06 +01001776 if (s->logs.uri)
1777 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001778 if (s->logs.cli_cookie)
1779 pool_free(capture, s->logs.cli_cookie);
1780 if (s->logs.srv_cookie)
1781 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001782
willy tarreau5cbea6f2005-12-17 12:48:26 +01001783 pool_free(session, s);
1784}
1785
willy tarreau0f7af912005-12-17 12:21:26 +01001786
1787/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001788 * This function recounts the number of usable active and backup servers for
1789 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
1790 */
1791static inline void recount_servers(struct proxy *px) {
1792 struct server *srv;
1793
1794 px->srv_act = 0; px->srv_bck = 0;
1795 for (srv = px->srv; srv != NULL; srv = srv->next) {
1796 if (srv->state & SRV_RUNNING) {
1797 if (srv->state & SRV_BACKUP)
1798 px->srv_bck++;
1799 else
1800 px->srv_act++;
1801 }
1802 }
1803}
1804
1805/*
1806 * This function tries to find a running server for the proxy <px> following
1807 * the round-robin method. Depending on the number of active/backup servers,
1808 * it will either look for active servers, or for backup servers.
1809 * If any server is found, it will be returned and px->cursrv will be updated
1810 * to point to the next server. If no valid server is found, NULL is returned.
willy tarreau8337c6b2005-12-17 13:41:01 +01001811 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001812static inline struct server *get_server_rr(struct proxy *px) {
1813 struct server *srv;
willy tarreau72e583d2006-03-23 11:27:02 +01001814 struct server *end;
willy tarreau8337c6b2005-12-17 13:41:01 +01001815
willy tarreau4c8c2b52006-03-24 19:36:41 +01001816 if (px->srv_act) {
1817 srv = px->cursrv;
willy tarreau72e583d2006-03-23 11:27:02 +01001818 if (srv == NULL)
1819 srv = px->srv;
1820 end = srv;
willy tarreau8337c6b2005-12-17 13:41:01 +01001821 do {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001822 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1823 px->cursrv = srv->next;
willy tarreau8337c6b2005-12-17 13:41:01 +01001824 return srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001825 }
1826
willy tarreau8337c6b2005-12-17 13:41:01 +01001827 srv = srv->next;
willy tarreau72e583d2006-03-23 11:27:02 +01001828 if (srv == NULL)
1829 srv = px->srv;
1830 } while (srv != end);
willy tarreau4c8c2b52006-03-24 19:36:41 +01001831 /* note that theorically we should not get there */
1832 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001833
willy tarreau4c8c2b52006-03-24 19:36:41 +01001834 if (px->srv_bck) {
Willy TARREAU3481c462006-03-01 22:37:57 +01001835 /* By default, we look for the first backup server if all others are
1836 * DOWN. But in some cases, it may be desirable to load-balance across
1837 * all backup servers.
1838 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001839 if (px->options & PR_O_USE_ALL_BK)
1840 srv = px->cursrv;
1841 else
1842 srv = px->srv;
1843
1844 if (srv == NULL)
Willy TARREAU3481c462006-03-01 22:37:57 +01001845 srv = px->srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001846 end = srv;
1847 do {
1848 if (srv->state & SRV_RUNNING) {
1849 px->cursrv = srv->next;
1850 return srv;
1851 }
1852 srv = srv->next;
1853 if (srv == NULL)
1854 srv = px->srv;
1855 } while (srv != end);
1856 /* note that theorically we should not get there */
1857 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001858
willy tarreau4c8c2b52006-03-24 19:36:41 +01001859 /* if we get there, it means there are no available servers at all */
willy tarreau8337c6b2005-12-17 13:41:01 +01001860 return NULL;
1861}
1862
willy tarreau62084d42006-03-24 18:57:41 +01001863
1864/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001865 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001866 * is set, or to the dispatch server if (s->direct) is 0.
1867 * It can return one of :
1868 * - SN_ERR_NONE if everything's OK
1869 * - SN_ERR_SRVTO if there are no more servers
1870 * - SN_ERR_SRVCL if the connection was refused by the server
1871 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1872 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1873 * - SN_ERR_INTERNAL for any other purely internal errors
1874 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001875 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001876int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001877 int fd;
1878
willy tarreau12350152005-12-18 01:03:27 +01001879#ifdef DEBUG_FULL
1880 fprintf(stderr,"connect_server : s=%p\n",s);
1881#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001882
willy tarreaue39cd132005-12-17 13:00:18 +01001883 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001884 s->srv_addr = s->srv->addr;
1885 }
1886 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001887 if (!s->proxy->srv_act && !s->proxy->srv_bck)
1888 return SN_ERR_SRVTO;
1889
willy tarreau5cbea6f2005-12-17 12:48:26 +01001890 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001891 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001892
willy tarreau4c8c2b52006-03-24 19:36:41 +01001893 srv = get_server_rr(s->proxy);
1894 /* srv cannot be NULL */
willy tarreau8337c6b2005-12-17 13:41:01 +01001895 s->srv_addr = srv->addr;
1896 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01001897 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001898 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001899 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001900 }
willy tarreaua1598082005-12-17 13:08:06 +01001901 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001902 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001903 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001904 }
1905 else if (s->proxy->options & PR_O_TRANSP) {
1906 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001907 socklen_t salen = sizeof(s->srv_addr);
1908
willy tarreau5cbea6f2005-12-17 12:48:26 +01001909 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1910 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001911 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001912 }
1913 }
willy tarreau0f7af912005-12-17 12:21:26 +01001914
willy tarreaua41a8b42005-12-17 14:02:24 +01001915 /* if this server remaps proxied ports, we'll use
1916 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001917 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001918 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001919 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001920
willy tarreaub952e1d2005-12-18 01:31:20 +01001921 if (!(s->proxy->options & PR_O_TRANSP) ||
1922 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001923 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1924 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1925 }
1926
willy tarreau0f7af912005-12-17 12:21:26 +01001927 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001928 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001929
1930 if (errno == ENFILE)
1931 send_log(s->proxy, LOG_EMERG,
1932 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1933 s->proxy->id, maxfd);
1934 else if (errno == EMFILE)
1935 send_log(s->proxy, LOG_EMERG,
1936 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1937 s->proxy->id, maxfd);
1938 else if (errno == ENOBUFS || errno == ENOMEM)
1939 send_log(s->proxy, LOG_EMERG,
1940 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1941 s->proxy->id, maxfd);
1942 /* this is a resource error */
1943 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001944 }
1945
willy tarreau9fe663a2005-12-17 13:02:59 +01001946 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001947 /* do not log anything there, it's a normal condition when this option
1948 * is used to serialize connections to a server !
1949 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001950 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1951 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001952 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001953 }
1954
willy tarreau0f7af912005-12-17 12:21:26 +01001955 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1956 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001957 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001958 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001959 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001960 }
1961
willy tarreaub952e1d2005-12-18 01:31:20 +01001962 if (s->proxy->options & PR_O_TCP_SRV_KA)
1963 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1964
willy tarreau0174f312005-12-18 01:02:42 +01001965 /* allow specific binding :
1966 * - server-specific at first
1967 * - proxy-specific next
1968 */
1969 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1970 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1971 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1972 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1973 s->proxy->id, s->srv->id);
1974 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001975 send_log(s->proxy, LOG_EMERG,
1976 "Cannot bind to source address before connect() for server %s/%s.\n",
1977 s->proxy->id, s->srv->id);
1978 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001979 }
1980 }
1981 else if (s->proxy->options & PR_O_BIND_SRC) {
1982 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1983 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1984 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1985 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001986 send_log(s->proxy, LOG_EMERG,
1987 "Cannot bind to source address before connect() for server %s/%s.\n",
1988 s->proxy->id, s->srv->id);
1989 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001990 }
willy tarreaua1598082005-12-17 13:08:06 +01001991 }
1992
willy tarreaub1285d52005-12-18 01:20:14 +01001993 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1994 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1995
1996 if (errno == EAGAIN || errno == EADDRINUSE) {
1997 char *msg;
1998 if (errno == EAGAIN) /* no free ports left, try again later */
1999 msg = "no free ports";
2000 else
2001 msg = "local address already in use";
2002
2003 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002004 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002005 send_log(s->proxy, LOG_EMERG,
2006 "Connect() failed for server %s/%s: %s.\n",
2007 s->proxy->id, s->srv->id, msg);
2008 return SN_ERR_RESOURCE;
2009 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002010 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002011 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002012 return SN_ERR_SRVTO;
2013 } else {
2014 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002015 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002016 close(fd);
2017 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002018 }
2019 }
2020
willy tarreau5cbea6f2005-12-17 12:48:26 +01002021 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002022 fdtab[fd].read = &event_srv_read;
2023 fdtab[fd].write = &event_srv_write;
2024 fdtab[fd].state = FD_STCONN; /* connection in progress */
2025
2026 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002027#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2028 if (PrevReadEvent) {
2029 assert(!(FD_ISSET(fd, PrevReadEvent)));
2030 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2031 }
2032#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002033
2034 fd_insert(fd);
2035
2036 if (s->proxy->contimeout)
2037 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2038 else
2039 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002040 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002041}
2042
2043/*
2044 * this function is called on a read event from a client socket.
2045 * It returns 0.
2046 */
2047int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002048 struct task *t = fdtab[fd].owner;
2049 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002050 struct buffer *b = s->req;
2051 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002052
willy tarreau12350152005-12-18 01:03:27 +01002053#ifdef DEBUG_FULL
2054 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2055#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002056
willy tarreau0f7af912005-12-17 12:21:26 +01002057 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002058#ifdef FILL_BUFFERS
2059 while (1)
2060#else
2061 do
2062#endif
2063 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002064 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2065 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002066 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002067 }
2068 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002069 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002070 }
2071 else {
2072 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002073 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2074 * since it means that the rewrite protection has been removed. This
2075 * implies that the if statement can be removed.
2076 */
2077 if (max > b->rlim - b->data)
2078 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002079 }
2080
2081 if (max == 0) { /* not anymore room to store data */
2082 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002083 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002084 }
2085
willy tarreau3242e862005-12-17 12:27:53 +01002086#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002087 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002088 int skerr;
2089 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002090
willy tarreau5cbea6f2005-12-17 12:48:26 +01002091 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2092 if (skerr)
2093 ret = -1;
2094 else
2095 ret = recv(fd, b->r, max, 0);
2096 }
willy tarreau3242e862005-12-17 12:27:53 +01002097#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002098 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002099#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002100 if (ret > 0) {
2101 b->r += ret;
2102 b->l += ret;
2103 s->res_cr = RES_DATA;
2104
2105 if (b->r == b->data + BUFSIZE) {
2106 b->r = b->data; /* wrap around the buffer */
2107 }
willy tarreaua1598082005-12-17 13:08:06 +01002108
2109 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002110 /* we hope to read more data or to get a close on next round */
2111 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002112 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002113 else if (ret == 0) {
2114 s->res_cr = RES_NULL;
2115 break;
2116 }
2117 else if (errno == EAGAIN) {/* ignore EAGAIN */
2118 break;
2119 }
2120 else {
2121 s->res_cr = RES_ERROR;
2122 fdtab[fd].state = FD_STERROR;
2123 break;
2124 }
2125 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002126#ifndef FILL_BUFFERS
2127 while (0);
2128#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002129 }
2130 else {
2131 s->res_cr = RES_ERROR;
2132 fdtab[fd].state = FD_STERROR;
2133 }
2134
willy tarreau5cbea6f2005-12-17 12:48:26 +01002135 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002136 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002137 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2138 else
2139 tv_eternity(&s->crexpire);
2140
2141 task_wakeup(&rq, t);
2142 }
willy tarreau0f7af912005-12-17 12:21:26 +01002143
willy tarreau0f7af912005-12-17 12:21:26 +01002144 return 0;
2145}
2146
2147
2148/*
2149 * this function is called on a read event from a server socket.
2150 * It returns 0.
2151 */
2152int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002153 struct task *t = fdtab[fd].owner;
2154 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002155 struct buffer *b = s->rep;
2156 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002157
willy tarreau12350152005-12-18 01:03:27 +01002158#ifdef DEBUG_FULL
2159 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2160#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002161
willy tarreau0f7af912005-12-17 12:21:26 +01002162 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002163#ifdef FILL_BUFFERS
2164 while (1)
2165#else
2166 do
2167#endif
2168 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002169 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2170 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002171 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002172 }
2173 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002174 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002175 }
2176 else {
2177 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002178 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2179 * since it means that the rewrite protection has been removed. This
2180 * implies that the if statement can be removed.
2181 */
2182 if (max > b->rlim - b->data)
2183 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002184 }
2185
2186 if (max == 0) { /* not anymore room to store data */
2187 FD_CLR(fd, StaticReadEvent);
2188 break;
2189 }
2190
willy tarreau3242e862005-12-17 12:27:53 +01002191#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002192 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002193 int skerr;
2194 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002195
willy tarreau5cbea6f2005-12-17 12:48:26 +01002196 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2197 if (skerr)
2198 ret = -1;
2199 else
2200 ret = recv(fd, b->r, max, 0);
2201 }
willy tarreau3242e862005-12-17 12:27:53 +01002202#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002203 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002204#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002205 if (ret > 0) {
2206 b->r += ret;
2207 b->l += ret;
2208 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002209
willy tarreau5cbea6f2005-12-17 12:48:26 +01002210 if (b->r == b->data + BUFSIZE) {
2211 b->r = b->data; /* wrap around the buffer */
2212 }
willy tarreaua1598082005-12-17 13:08:06 +01002213
2214 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002215 /* we hope to read more data or to get a close on next round */
2216 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002217 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002218 else if (ret == 0) {
2219 s->res_sr = RES_NULL;
2220 break;
2221 }
2222 else if (errno == EAGAIN) {/* ignore EAGAIN */
2223 break;
2224 }
2225 else {
2226 s->res_sr = RES_ERROR;
2227 fdtab[fd].state = FD_STERROR;
2228 break;
2229 }
2230 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002231#ifndef FILL_BUFFERS
2232 while (0);
2233#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002234 }
2235 else {
2236 s->res_sr = RES_ERROR;
2237 fdtab[fd].state = FD_STERROR;
2238 }
2239
willy tarreau5cbea6f2005-12-17 12:48:26 +01002240 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002241 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002242 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2243 else
2244 tv_eternity(&s->srexpire);
2245
2246 task_wakeup(&rq, t);
2247 }
willy tarreau0f7af912005-12-17 12:21:26 +01002248
willy tarreau0f7af912005-12-17 12:21:26 +01002249 return 0;
2250}
2251
2252/*
2253 * this function is called on a write event from a client socket.
2254 * It returns 0.
2255 */
2256int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002257 struct task *t = fdtab[fd].owner;
2258 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002259 struct buffer *b = s->rep;
2260 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002261
willy tarreau12350152005-12-18 01:03:27 +01002262#ifdef DEBUG_FULL
2263 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2264#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002265
2266 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002267 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002268 // max = BUFSIZE; BUG !!!!
2269 max = 0;
2270 }
2271 else if (b->r > b->w) {
2272 max = b->r - b->w;
2273 }
2274 else
2275 max = b->data + BUFSIZE - b->w;
2276
willy tarreau0f7af912005-12-17 12:21:26 +01002277 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002278 if (max == 0) {
2279 s->res_cw = RES_NULL;
2280 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002281 tv_eternity(&s->cwexpire);
2282 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002283 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002284 }
2285
willy tarreau3242e862005-12-17 12:27:53 +01002286#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002287 {
2288 int skerr;
2289 socklen_t lskerr = sizeof(skerr);
2290
2291 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2292 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002293 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002294 else
willy tarreau3242e862005-12-17 12:27:53 +01002295 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002296 }
willy tarreau3242e862005-12-17 12:27:53 +01002297#else
willy tarreau0f7af912005-12-17 12:21:26 +01002298 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002299#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002300
2301 if (ret > 0) {
2302 b->l -= ret;
2303 b->w += ret;
2304
2305 s->res_cw = RES_DATA;
2306
2307 if (b->w == b->data + BUFSIZE) {
2308 b->w = b->data; /* wrap around the buffer */
2309 }
2310 }
2311 else if (ret == 0) {
2312 /* nothing written, just make as if we were never called */
2313// s->res_cw = RES_NULL;
2314 return 0;
2315 }
2316 else if (errno == EAGAIN) /* ignore EAGAIN */
2317 return 0;
2318 else {
2319 s->res_cw = RES_ERROR;
2320 fdtab[fd].state = FD_STERROR;
2321 }
2322 }
2323 else {
2324 s->res_cw = RES_ERROR;
2325 fdtab[fd].state = FD_STERROR;
2326 }
2327
willy tarreaub1ff9db2005-12-17 13:51:03 +01002328 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002329 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002330 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2331 s->crexpire = s->cwexpire;
2332 }
willy tarreau0f7af912005-12-17 12:21:26 +01002333 else
2334 tv_eternity(&s->cwexpire);
2335
willy tarreau5cbea6f2005-12-17 12:48:26 +01002336 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002337 return 0;
2338}
2339
2340
2341/*
2342 * this function is called on a write event from a server socket.
2343 * It returns 0.
2344 */
2345int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002346 struct task *t = fdtab[fd].owner;
2347 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002348 struct buffer *b = s->req;
2349 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002350
willy tarreau12350152005-12-18 01:03:27 +01002351#ifdef DEBUG_FULL
2352 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2353#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002354
2355 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002356 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002357 // max = BUFSIZE; BUG !!!!
2358 max = 0;
2359 }
2360 else if (b->r > b->w) {
2361 max = b->r - b->w;
2362 }
2363 else
2364 max = b->data + BUFSIZE - b->w;
2365
willy tarreau0f7af912005-12-17 12:21:26 +01002366 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002367 if (max == 0) {
2368 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002369 if (s->srv_state == SV_STCONN) {
2370 int skerr;
2371 socklen_t lskerr = sizeof(skerr);
2372 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2373 if (skerr) {
2374 s->res_sw = RES_ERROR;
2375 fdtab[fd].state = FD_STERROR;
2376 task_wakeup(&rq, t);
2377 tv_eternity(&s->swexpire);
2378 FD_CLR(fd, StaticWriteEvent);
2379 return 0;
2380 }
2381 }
2382
willy tarreau0f7af912005-12-17 12:21:26 +01002383 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002384 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002385 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002386 tv_eternity(&s->swexpire);
2387 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002388 return 0;
2389 }
2390
willy tarreau3242e862005-12-17 12:27:53 +01002391#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002392 {
2393 int skerr;
2394 socklen_t lskerr = sizeof(skerr);
2395 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2396 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002397 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002398 else
willy tarreau3242e862005-12-17 12:27:53 +01002399 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002400 }
willy tarreau3242e862005-12-17 12:27:53 +01002401#else
willy tarreau0f7af912005-12-17 12:21:26 +01002402 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002403#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002404 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002405 if (ret > 0) {
2406 b->l -= ret;
2407 b->w += ret;
2408
2409 s->res_sw = RES_DATA;
2410
2411 if (b->w == b->data + BUFSIZE) {
2412 b->w = b->data; /* wrap around the buffer */
2413 }
2414 }
2415 else if (ret == 0) {
2416 /* nothing written, just make as if we were never called */
2417 // s->res_sw = RES_NULL;
2418 return 0;
2419 }
2420 else if (errno == EAGAIN) /* ignore EAGAIN */
2421 return 0;
2422 else {
2423 s->res_sw = RES_ERROR;
2424 fdtab[fd].state = FD_STERROR;
2425 }
2426 }
2427 else {
2428 s->res_sw = RES_ERROR;
2429 fdtab[fd].state = FD_STERROR;
2430 }
2431
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002432 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2433 * otherwise it could loop indefinitely !
2434 */
2435 if (s->srv_state != SV_STCONN) {
2436 if (s->proxy->srvtimeout) {
2437 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2438 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2439 s->srexpire = s->swexpire;
2440 }
2441 else
2442 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002443 }
willy tarreau0f7af912005-12-17 12:21:26 +01002444
willy tarreau5cbea6f2005-12-17 12:48:26 +01002445 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002446 return 0;
2447}
2448
2449
2450/*
willy tarreaue39cd132005-12-17 13:00:18 +01002451 * returns a message to the client ; the connection is shut down for read,
2452 * and the request is cleared so that no server connection can be initiated.
2453 * The client must be in a valid state for this (HEADER, DATA ...).
2454 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002455 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002456 */
2457void client_retnclose(struct session *s, int len, const char *msg) {
2458 FD_CLR(s->cli_fd, StaticReadEvent);
2459 FD_SET(s->cli_fd, StaticWriteEvent);
2460 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002461 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002462 shutdown(s->cli_fd, SHUT_RD);
2463 s->cli_state = CL_STSHUTR;
2464 strcpy(s->rep->data, msg);
2465 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002466 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002467 s->rep->r += len;
2468 s->req->l = 0;
2469}
2470
2471
2472/*
2473 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002474 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002475 */
2476void client_return(struct session *s, int len, const char *msg) {
2477 strcpy(s->rep->data, msg);
2478 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002479 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002480 s->rep->r += len;
2481 s->req->l = 0;
2482}
2483
willy tarreau9fe663a2005-12-17 13:02:59 +01002484/*
2485 * send a log for the session when we have enough info about it
2486 */
2487void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002488 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002489 struct proxy *p = s->proxy;
2490 int log;
2491 char *uri;
2492 char *pxid;
2493 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002494 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002495
2496 /* This is a first attempt at a better logging system.
2497 * For now, we rely on send_log() to provide the date, although it obviously
2498 * is the date of the log and not of the request, and most fields are not
2499 * computed.
2500 */
2501
willy tarreaua1598082005-12-17 13:08:06 +01002502 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002503
willy tarreau8a86dbf2005-12-18 00:45:59 +01002504 if (s->cli_addr.ss_family == AF_INET)
2505 inet_ntop(AF_INET,
2506 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2507 pn, sizeof(pn));
2508 else
2509 inet_ntop(AF_INET6,
2510 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2511 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002512
willy tarreauc1cae632005-12-17 14:12:23 +01002513 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002514 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002515 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002516
willy tarreauc1cae632005-12-17 14:12:23 +01002517 tm = localtime(&s->logs.tv_accept.tv_sec);
2518 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002519 char tmpline[MAX_SYSLOG_LEN], *h;
2520 int hdr;
2521
2522 h = tmpline;
2523 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2524 *(h++) = ' ';
2525 *(h++) = '{';
2526 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2527 if (hdr)
2528 *(h++) = '|';
2529 if (s->req_cap[hdr] != NULL)
2530 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2531 }
2532 *(h++) = '}';
2533 }
2534
2535 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2536 *(h++) = ' ';
2537 *(h++) = '{';
2538 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2539 if (hdr)
2540 *(h++) = '|';
2541 if (s->rsp_cap[hdr] != NULL)
2542 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2543 }
2544 *(h++) = '}';
2545 }
2546
2547 if (h < tmpline + sizeof(tmpline) - 4) {
2548 *(h++) = ' ';
2549 *(h++) = '"';
2550 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2551 *(h++) = '"';
2552 }
2553 *h = '\0';
2554
willy tarreau0fe39652005-12-18 01:25:24 +01002555 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002556 pn,
2557 (s->cli_addr.ss_family == AF_INET) ?
2558 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2559 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002560 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2561 tm->tm_hour, tm->tm_min, tm->tm_sec,
2562 pxid, srv,
2563 s->logs.t_request,
2564 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2565 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002566 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2567 s->logs.status,
2568 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002569 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2570 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002571 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2572 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2573 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2574 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002575 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002576 }
2577 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002578 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002579 pn,
2580 (s->cli_addr.ss_family == AF_INET) ?
2581 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2582 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002583 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2584 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002585 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002586 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002587 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2588 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002589 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002590 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2591 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002592 }
2593
2594 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002595}
2596
willy tarreaue39cd132005-12-17 13:00:18 +01002597
2598/*
willy tarreau0f7af912005-12-17 12:21:26 +01002599 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002600 * to an accept. It tries to accept as many connections as possible.
2601 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002602 */
2603int event_accept(int fd) {
2604 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002605 struct session *s;
2606 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002607 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002608 int max_accept;
2609
2610 if (global.nbproc > 1)
2611 max_accept = 8; /* let other processes catch some connections too */
2612 else
2613 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002614
willy tarreauc2becdc2006-03-19 19:36:48 +01002615 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002616 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002617 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002618
willy tarreaub1285d52005-12-18 01:20:14 +01002619 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2620 switch (errno) {
2621 case EAGAIN:
2622 case EINTR:
2623 case ECONNABORTED:
2624 return 0; /* nothing more to accept */
2625 case ENFILE:
2626 send_log(p, LOG_EMERG,
2627 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2628 p->id, maxfd);
2629 return 0;
2630 case EMFILE:
2631 send_log(p, LOG_EMERG,
2632 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2633 p->id, maxfd);
2634 return 0;
2635 case ENOBUFS:
2636 case ENOMEM:
2637 send_log(p, LOG_EMERG,
2638 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2639 p->id, maxfd);
2640 return 0;
2641 default:
2642 return 0;
2643 }
2644 }
willy tarreau0f7af912005-12-17 12:21:26 +01002645
willy tarreau5cbea6f2005-12-17 12:48:26 +01002646 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2647 Alert("out of memory in event_accept().\n");
2648 FD_CLR(fd, StaticReadEvent);
2649 p->state = PR_STIDLE;
2650 close(cfd);
2651 return 0;
2652 }
willy tarreau0f7af912005-12-17 12:21:26 +01002653
willy tarreaub1285d52005-12-18 01:20:14 +01002654 /* if this session comes from a known monitoring system, we want to ignore
2655 * it as soon as possible, which means closing it immediately for TCP.
2656 */
2657 s->flags = 0;
2658 if (addr.ss_family == AF_INET &&
2659 p->mon_mask.s_addr &&
2660 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2661 if (p->mode == PR_MODE_TCP) {
2662 close(cfd);
2663 pool_free(session, s);
2664 continue;
2665 }
2666 s->flags |= SN_MONITOR;
2667 }
2668
willy tarreau5cbea6f2005-12-17 12:48:26 +01002669 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2670 Alert("out of memory in event_accept().\n");
2671 FD_CLR(fd, StaticReadEvent);
2672 p->state = PR_STIDLE;
2673 close(cfd);
2674 pool_free(session, s);
2675 return 0;
2676 }
willy tarreau0f7af912005-12-17 12:21:26 +01002677
willy tarreau5cbea6f2005-12-17 12:48:26 +01002678 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002679 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002680 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2681 close(cfd);
2682 pool_free(task, t);
2683 pool_free(session, s);
2684 return 0;
2685 }
willy tarreau0f7af912005-12-17 12:21:26 +01002686
willy tarreau5cbea6f2005-12-17 12:48:26 +01002687 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2688 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2689 (char *) &one, sizeof(one)) == -1)) {
2690 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2691 close(cfd);
2692 pool_free(task, t);
2693 pool_free(session, s);
2694 return 0;
2695 }
willy tarreau0f7af912005-12-17 12:21:26 +01002696
willy tarreaub952e1d2005-12-18 01:31:20 +01002697 if (p->options & PR_O_TCP_CLI_KA)
2698 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2699
willy tarreau9fe663a2005-12-17 13:02:59 +01002700 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2701 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2702 t->state = TASK_IDLE;
2703 t->process = process_session;
2704 t->context = s;
2705
2706 s->task = t;
2707 s->proxy = p;
2708 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2709 s->srv_state = SV_STIDLE;
2710 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002711
willy tarreau9fe663a2005-12-17 13:02:59 +01002712 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2713 s->cli_fd = cfd;
2714 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002715 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002716 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002717
willy tarreaub1285d52005-12-18 01:20:14 +01002718 if (s->flags & SN_MONITOR)
2719 s->logs.logwait = 0;
2720 else
2721 s->logs.logwait = p->to_log;
2722
willy tarreaua1598082005-12-17 13:08:06 +01002723 s->logs.tv_accept = now;
2724 s->logs.t_request = -1;
2725 s->logs.t_connect = -1;
2726 s->logs.t_data = -1;
2727 s->logs.t_close = 0;
2728 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002729 s->logs.cli_cookie = NULL;
2730 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002731 s->logs.status = -1;
2732 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002733
willy tarreau2f6ba652005-12-17 13:57:42 +01002734 s->uniq_id = totalconn;
2735
willy tarreau4302f492005-12-18 01:00:37 +01002736 if (p->nb_req_cap > 0) {
2737 if ((s->req_cap =
2738 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2739 == NULL) { /* no memory */
2740 close(cfd); /* nothing can be done for this fd without memory */
2741 pool_free(task, t);
2742 pool_free(session, s);
2743 return 0;
2744 }
2745 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2746 }
2747 else
2748 s->req_cap = NULL;
2749
2750 if (p->nb_rsp_cap > 0) {
2751 if ((s->rsp_cap =
2752 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2753 == NULL) { /* no memory */
2754 if (s->req_cap != NULL)
2755 pool_free_to(p->req_cap_pool, s->req_cap);
2756 close(cfd); /* nothing can be done for this fd without memory */
2757 pool_free(task, t);
2758 pool_free(session, s);
2759 return 0;
2760 }
2761 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2762 }
2763 else
2764 s->rsp_cap = NULL;
2765
willy tarreau5cbea6f2005-12-17 12:48:26 +01002766 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2767 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002768 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002769 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002770
willy tarreau8a86dbf2005-12-18 00:45:59 +01002771 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002772 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002773 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002774 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002775
willy tarreau9fe663a2005-12-17 13:02:59 +01002776 if (p->to_log) {
2777 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002778 if (s->logs.logwait & LW_CLIP)
2779 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002780 sess_log(s);
2781 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002782 else if (s->cli_addr.ss_family == AF_INET) {
2783 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2784 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2785 sn, sizeof(sn)) &&
2786 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2787 pn, sizeof(pn))) {
2788 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2789 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2790 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2791 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2792 }
2793 }
2794 else {
2795 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2796 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2797 sn, sizeof(sn)) &&
2798 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2799 pn, sizeof(pn))) {
2800 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2801 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2802 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2803 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2804 }
2805 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002806 }
willy tarreau0f7af912005-12-17 12:21:26 +01002807
willy tarreau982249e2005-12-18 00:57:06 +01002808 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002809 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002810 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002811 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002812 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002813 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002814 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002815 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002816
willy tarreau8a86dbf2005-12-18 00:45:59 +01002817 if (s->cli_addr.ss_family == AF_INET) {
2818 char pn[INET_ADDRSTRLEN];
2819 inet_ntop(AF_INET,
2820 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2821 pn, sizeof(pn));
2822
2823 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2824 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2825 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2826 }
2827 else {
2828 char pn[INET6_ADDRSTRLEN];
2829 inet_ntop(AF_INET6,
2830 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2831 pn, sizeof(pn));
2832
2833 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2834 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2835 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2836 }
2837
willy tarreauef900ab2005-12-17 12:52:52 +01002838 write(1, trash, len);
2839 }
willy tarreau0f7af912005-12-17 12:21:26 +01002840
willy tarreau5cbea6f2005-12-17 12:48:26 +01002841 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002842 if (s->rsp_cap != NULL)
2843 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2844 if (s->req_cap != NULL)
2845 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002846 close(cfd); /* nothing can be done for this fd without memory */
2847 pool_free(task, t);
2848 pool_free(session, s);
2849 return 0;
2850 }
willy tarreau4302f492005-12-18 01:00:37 +01002851
willy tarreau5cbea6f2005-12-17 12:48:26 +01002852 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002853 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002854 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2855 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002856 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002857 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002858
willy tarreau5cbea6f2005-12-17 12:48:26 +01002859 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2860 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002861 if (s->rsp_cap != NULL)
2862 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2863 if (s->req_cap != NULL)
2864 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002865 close(cfd); /* nothing can be done for this fd without memory */
2866 pool_free(task, t);
2867 pool_free(session, s);
2868 return 0;
2869 }
2870 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002871 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002872 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 +01002873
willy tarreau5cbea6f2005-12-17 12:48:26 +01002874 fdtab[cfd].read = &event_cli_read;
2875 fdtab[cfd].write = &event_cli_write;
2876 fdtab[cfd].owner = t;
2877 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002878
willy tarreaub1285d52005-12-18 01:20:14 +01002879 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2880 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2881 /* Either we got a request from a monitoring system on an HTTP instance,
2882 * or we're in health check mode with the 'httpchk' option enabled. In
2883 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2884 */
2885 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2886 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2887 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002888 }
2889 else {
2890 FD_SET(cfd, StaticReadEvent);
2891 }
2892
willy tarreaub952e1d2005-12-18 01:31:20 +01002893#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2894 if (PrevReadEvent) {
2895 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2896 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2897 }
2898#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002899 fd_insert(cfd);
2900
2901 tv_eternity(&s->cnexpire);
2902 tv_eternity(&s->srexpire);
2903 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002904 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002905 tv_eternity(&s->cwexpire);
2906
willy tarreaub1285d52005-12-18 01:20:14 +01002907 if (s->proxy->clitimeout) {
2908 if (FD_ISSET(cfd, StaticReadEvent))
2909 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2910 if (FD_ISSET(cfd, StaticWriteEvent))
2911 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2912 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002913
willy tarreaub1285d52005-12-18 01:20:14 +01002914 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002915
2916 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002917
2918 if (p->mode != PR_MODE_HEALTH)
2919 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002920
2921 p->nbconn++;
2922 actconn++;
2923 totalconn++;
2924
willy tarreaub952e1d2005-12-18 01:31:20 +01002925 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002926 } /* end of while (p->nbconn < p->maxconn) */
2927 return 0;
2928}
willy tarreau0f7af912005-12-17 12:21:26 +01002929
willy tarreau0f7af912005-12-17 12:21:26 +01002930
willy tarreau5cbea6f2005-12-17 12:48:26 +01002931/*
2932 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002933 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2934 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002935 * or -1 if an error occured.
2936 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002937int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002938 struct task *t = fdtab[fd].owner;
2939 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002940 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002941 socklen_t lskerr = sizeof(skerr);
2942
willy tarreau05be12b2006-03-19 19:35:00 +01002943 skerr = 1;
2944 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
2945 || (skerr != 0)) {
2946 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002947 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002948 fdtab[fd].state = FD_STERROR;
2949 FD_CLR(fd, StaticWriteEvent);
2950 }
willy tarreaua4a583a2005-12-18 01:39:19 +01002951 else if (s->result != -1) {
2952 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002953 if (s->proxy->options & PR_O_HTTP_CHK) {
2954 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002955 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002956 * so we'll send the request, and won't wake the checker up now.
2957 */
2958#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002959 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002960#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002961 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002962#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002963 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002964 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2965 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2966 return 0;
2967 }
willy tarreau05be12b2006-03-19 19:35:00 +01002968 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002969 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002970 FD_CLR(fd, StaticWriteEvent);
2971 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002972 }
2973 else {
2974 /* good TCP connection is enough */
2975 s->result = 1;
2976 }
2977 }
2978
2979 task_wakeup(&rq, t);
2980 return 0;
2981}
2982
willy tarreau0f7af912005-12-17 12:21:26 +01002983
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002984/*
2985 * This function is used only for server health-checks. It handles
2986 * the server's reply to an HTTP request. It returns 1 if the server replies
2987 * 2xx or 3xx (valid responses), or -1 in other cases.
2988 */
2989int event_srv_chk_r(int fd) {
2990 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002991 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002992 struct task *t = fdtab[fd].owner;
2993 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01002994 int skerr;
2995 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002996
willy tarreaua4a583a2005-12-18 01:39:19 +01002997 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002998
willy tarreau05be12b2006-03-19 19:35:00 +01002999 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3000 if (!skerr) {
3001#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003002 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003003#else
willy tarreau05be12b2006-03-19 19:35:00 +01003004 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3005 * but the connection was closed on the remote end. Fortunately, recv still
3006 * works correctly and we don't need to do the getsockopt() on linux.
3007 */
3008 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003009#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003010
3011 if ((len >= sizeof("HTTP/1.0 000")) &&
3012 !memcmp(reply, "HTTP/1.", 7) &&
3013 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3014 result = 1;
3015 }
3016
3017 if (result == -1)
3018 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003019
3020 if (s->result != -1)
3021 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003022
3023 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003024 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003025 return 0;
3026}
3027
3028
3029/*
3030 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3031 * and moves <end> just after the end of <str>.
3032 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3033 * the shift value (positive or negative) is returned.
3034 * If there's no space left, the move is not done.
3035 *
3036 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003037int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003038 int delta;
3039 int len;
3040
3041 len = strlen(str);
3042 delta = len - (end - pos);
3043
3044 if (delta + b->r >= b->data + BUFSIZE)
3045 return 0; /* no space left */
3046
3047 /* first, protect the end of the buffer */
3048 memmove(end + delta, end, b->data + b->l - end);
3049
3050 /* now, copy str over pos */
3051 memcpy(pos, str,len);
3052
willy tarreau5cbea6f2005-12-17 12:48:26 +01003053 /* we only move data after the displaced zone */
3054 if (b->r > pos) b->r += delta;
3055 if (b->w > pos) b->w += delta;
3056 if (b->h > pos) b->h += delta;
3057 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003058 b->l += delta;
3059
3060 return delta;
3061}
3062
willy tarreau8337c6b2005-12-17 13:41:01 +01003063/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003064 * len is 0.
3065 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003066int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003067 int delta;
3068
3069 delta = len - (end - pos);
3070
3071 if (delta + b->r >= b->data + BUFSIZE)
3072 return 0; /* no space left */
3073
Willy TARREAUe78ae262006-01-08 01:24:12 +01003074 if (b->data + b->l < end)
3075 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3076 return 0;
3077
willy tarreau0f7af912005-12-17 12:21:26 +01003078 /* first, protect the end of the buffer */
3079 memmove(end + delta, end, b->data + b->l - end);
3080
3081 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003082 if (len)
3083 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003084
willy tarreau5cbea6f2005-12-17 12:48:26 +01003085 /* we only move data after the displaced zone */
3086 if (b->r > pos) b->r += delta;
3087 if (b->w > pos) b->w += delta;
3088 if (b->h > pos) b->h += delta;
3089 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003090 b->l += delta;
3091
3092 return delta;
3093}
3094
3095
3096int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3097 char *old_dst = dst;
3098
3099 while (*str) {
3100 if (*str == '\\') {
3101 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003102 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003103 int len, num;
3104
3105 num = *str - '0';
3106 str++;
3107
willy tarreau8a86dbf2005-12-18 00:45:59 +01003108 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003109 len = matches[num].rm_eo - matches[num].rm_so;
3110 memcpy(dst, src + matches[num].rm_so, len);
3111 dst += len;
3112 }
3113
3114 }
3115 else if (*str == 'x') {
3116 unsigned char hex1, hex2;
3117 str++;
3118
willy tarreauc1f47532005-12-18 01:08:26 +01003119 hex1 = toupper(*str++) - '0';
3120 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003121
3122 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3123 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3124 *dst++ = (hex1<<4) + hex2;
3125 }
3126 else
3127 *dst++ = *str++;
3128 }
3129 else
3130 *dst++ = *str++;
3131 }
3132 *dst = 0;
3133 return dst - old_dst;
3134}
3135
willy tarreauc1f47532005-12-18 01:08:26 +01003136static int ishex(char s)
3137{
3138 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3139}
3140
3141/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3142char *check_replace_string(char *str)
3143{
3144 char *err = NULL;
3145 while (*str) {
3146 if (*str == '\\') {
3147 err = str; /* in case of a backslash, we return the pointer to it */
3148 str++;
3149 if (!*str)
3150 return err;
3151 else if (isdigit((int)*str))
3152 err = NULL;
3153 else if (*str == 'x') {
3154 str++;
3155 if (!ishex(*str))
3156 return err;
3157 str++;
3158 if (!ishex(*str))
3159 return err;
3160 err = NULL;
3161 }
3162 else {
3163 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3164 err = NULL;
3165 }
3166 }
3167 str++;
3168 }
3169 return err;
3170}
3171
3172
willy tarreau9fe663a2005-12-17 13:02:59 +01003173
willy tarreau0f7af912005-12-17 12:21:26 +01003174/*
3175 * manages the client FSM and its socket. BTW, it also tries to handle the
3176 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3177 * 0 else.
3178 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003179int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003180 int s = t->srv_state;
3181 int c = t->cli_state;
3182 struct buffer *req = t->req;
3183 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003184 int method_checked = 0;
3185 appsess *asession_temp = NULL;
3186 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003187
willy tarreau750a4722005-12-17 13:21:24 +01003188#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003189 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3190 cli_stnames[c], srv_stnames[s],
3191 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3192 t->crexpire.tv_sec, t->crexpire.tv_usec,
3193 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003194#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003195 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3196 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3197 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3198 //);
3199 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003200 /* now parse the partial (or complete) headers */
3201 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3202 char *ptr;
3203 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003204 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003205
willy tarreau5cbea6f2005-12-17 12:48:26 +01003206 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003207
willy tarreau0f7af912005-12-17 12:21:26 +01003208 /* look for the end of the current header */
3209 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3210 ptr++;
3211
willy tarreau5cbea6f2005-12-17 12:48:26 +01003212 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003213 int line, len;
3214 /* we can only get here after an end of headers */
3215 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003216
willy tarreaue39cd132005-12-17 13:00:18 +01003217 if (t->flags & SN_CLDENY) {
3218 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003219 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003220 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003221 if (!(t->flags & SN_ERR_MASK))
3222 t->flags |= SN_ERR_PRXCOND;
3223 if (!(t->flags & SN_FINST_MASK))
3224 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003225 return 1;
3226 }
3227
willy tarreau5cbea6f2005-12-17 12:48:26 +01003228 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003229 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3230 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003231 }
willy tarreau0f7af912005-12-17 12:21:26 +01003232
willy tarreau9fe663a2005-12-17 13:02:59 +01003233 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003234 if (t->cli_addr.ss_family == AF_INET) {
3235 unsigned char *pn;
3236 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3237 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3238 pn[0], pn[1], pn[2], pn[3]);
3239 buffer_replace2(req, req->h, req->h, trash, len);
3240 }
3241 else if (t->cli_addr.ss_family == AF_INET6) {
3242 char pn[INET6_ADDRSTRLEN];
3243 inet_ntop(AF_INET6,
3244 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3245 pn, sizeof(pn));
3246 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3247 buffer_replace2(req, req->h, req->h, trash, len);
3248 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003249 }
3250
willy tarreau25c4ea52005-12-18 00:49:49 +01003251 /* add a "connection: close" line if needed */
3252 if (t->proxy->options & PR_O_HTTP_CLOSE)
3253 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3254
willy tarreau982249e2005-12-18 00:57:06 +01003255 if (!memcmp(req->data, "POST ", 5)) {
3256 /* this is a POST request, which is not cacheable by default */
3257 t->flags |= SN_POST;
3258 }
willy tarreaucd878942005-12-17 13:27:43 +01003259
willy tarreau5cbea6f2005-12-17 12:48:26 +01003260 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003261 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003262
willy tarreau750a4722005-12-17 13:21:24 +01003263 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003264 /* FIXME: we'll set the client in a wait state while we try to
3265 * connect to the server. Is this really needed ? wouldn't it be
3266 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003267 //FD_CLR(t->cli_fd, StaticReadEvent);
3268 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003269
3270 /* FIXME: if we break here (as up to 1.1.23), having the client
3271 * shutdown its connection can lead to an abort further.
3272 * it's better to either return 1 or even jump directly to the
3273 * data state which will save one schedule.
3274 */
3275 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003276
3277 if (!t->proxy->clitimeout ||
3278 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3279 /* If the client has no timeout, or if the server is not ready yet,
3280 * and we know for sure that it can expire, then it's cleaner to
3281 * disable the timeout on the client side so that too low values
3282 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003283 *
3284 * FIXME-20050705: the server needs a way to re-enable this time-out
3285 * when it switches its state, otherwise a client can stay connected
3286 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003287 */
3288 tv_eternity(&t->crexpire);
3289
willy tarreau197e8ec2005-12-17 14:10:59 +01003290 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003291 }
willy tarreau0f7af912005-12-17 12:21:26 +01003292
Willy TARREAU13032e72006-03-12 17:31:45 +01003293 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3294 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003295 /* this is a partial header, let's wait for more to come */
3296 req->lr = ptr;
3297 break;
3298 }
willy tarreau0f7af912005-12-17 12:21:26 +01003299
willy tarreau5cbea6f2005-12-17 12:48:26 +01003300 /* now we know that *ptr is either \r or \n,
3301 * and that there are at least 1 char after it.
3302 */
3303 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3304 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3305 else
3306 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003307
willy tarreau5cbea6f2005-12-17 12:48:26 +01003308 /*
3309 * now we know that we have a full header ; we can do whatever
3310 * we want with these pointers :
3311 * req->h = beginning of header
3312 * ptr = end of header (first \r or \n)
3313 * req->lr = beginning of next line (next rep->h)
3314 * req->r = end of data (not used at this stage)
3315 */
willy tarreau0f7af912005-12-17 12:21:26 +01003316
willy tarreau12350152005-12-18 01:03:27 +01003317 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3318 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3319 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3320
3321 /* skip ; */
3322 request_line++;
3323
3324 /* look if we have a jsessionid */
3325
3326 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3327
3328 /* skip jsessionid= */
3329 request_line += t->proxy->appsession_name_len + 1;
3330
3331 /* First try if we allready have an appsession */
3332 asession_temp = &local_asession;
3333
3334 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3335 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3336 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3337 return 0;
3338 }
3339
3340 /* Copy the sessionid */
3341 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3342 asession_temp->sessid[t->proxy->appsession_len] = 0;
3343 asession_temp->serverid = NULL;
3344
3345 /* only do insert, if lookup fails */
3346 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3347 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3348 Alert("Not enough memory process_cli():asession:calloc().\n");
3349 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3350 return 0;
3351 }
3352 asession_temp->sessid = local_asession.sessid;
3353 asession_temp->serverid = local_asession.serverid;
3354 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003355 } /* end if (chtbl_lookup()) */
3356 else {
willy tarreau12350152005-12-18 01:03:27 +01003357 /*free wasted memory;*/
3358 pool_free_to(apools.sessid, local_asession.sessid);
3359 }
3360
3361 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3362 asession_temp->request_count++;
3363
3364#if defined(DEBUG_HASH)
3365 print_table(&(t->proxy->htbl_proxy));
3366#endif
3367
3368 if (asession_temp->serverid == NULL) {
3369 Alert("Found Application Session without matching server.\n");
3370 } else {
3371 struct server *srv = t->proxy->srv;
3372 while (srv) {
3373 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3374 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3375 /* we found the server and it's usable */
3376 t->flags &= ~SN_CK_MASK;
3377 t->flags |= SN_CK_VALID | SN_DIRECT;
3378 t->srv = srv;
3379 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003380 } else {
willy tarreau12350152005-12-18 01:03:27 +01003381 t->flags &= ~SN_CK_MASK;
3382 t->flags |= SN_CK_DOWN;
3383 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003384 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003385 srv = srv->next;
3386 }/* end while(srv) */
3387 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003388 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003389 else {
3390 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3391 }
willy tarreau598da412005-12-18 01:07:29 +01003392 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003393 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003394 else{
3395 //printf("No Methode-Header with Session-String\n");
3396 }
3397
willy tarreau8337c6b2005-12-17 13:41:01 +01003398 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003399 /* we have a complete HTTP request that we must log */
3400 int urilen;
3401
willy tarreaua1598082005-12-17 13:08:06 +01003402 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003403 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003404 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003405 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003406 if (!(t->flags & SN_ERR_MASK))
3407 t->flags |= SN_ERR_PRXCOND;
3408 if (!(t->flags & SN_FINST_MASK))
3409 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003410 return 1;
3411 }
3412
3413 urilen = ptr - req->h;
3414 if (urilen >= REQURI_LEN)
3415 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003416 memcpy(t->logs.uri, req->h, urilen);
3417 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003418
willy tarreaua1598082005-12-17 13:08:06 +01003419 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003420 sess_log(t);
3421 }
willy tarreau4302f492005-12-18 01:00:37 +01003422 else if (t->logs.logwait & LW_REQHDR) {
3423 struct cap_hdr *h;
3424 int len;
3425 for (h = t->proxy->req_cap; h; h = h->next) {
3426 if ((h->namelen + 2 <= ptr - req->h) &&
3427 (req->h[h->namelen] == ':') &&
3428 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3429
3430 if (t->req_cap[h->index] == NULL)
3431 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3432
3433 len = ptr - (req->h + h->namelen + 2);
3434 if (len > h->len)
3435 len = h->len;
3436
3437 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3438 t->req_cap[h->index][len]=0;
3439 }
3440 }
3441
3442 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003443
willy tarreau5cbea6f2005-12-17 12:48:26 +01003444 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003445
willy tarreau982249e2005-12-18 00:57:06 +01003446 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003447 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003448 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 +01003449 max = ptr - req->h;
3450 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003451 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003452 trash[len++] = '\n';
3453 write(1, trash, len);
3454 }
willy tarreau0f7af912005-12-17 12:21:26 +01003455
willy tarreau25c4ea52005-12-18 00:49:49 +01003456
3457 /* remove "connection: " if needed */
3458 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3459 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3460 delete_header = 1;
3461 }
3462
willy tarreau5cbea6f2005-12-17 12:48:26 +01003463 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003464 if (!delete_header && t->proxy->req_exp != NULL
3465 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003466 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003467 char term;
3468
3469 term = *ptr;
3470 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003471 exp = t->proxy->req_exp;
3472 do {
3473 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3474 switch (exp->action) {
3475 case ACT_ALLOW:
3476 if (!(t->flags & SN_CLDENY))
3477 t->flags |= SN_CLALLOW;
3478 break;
3479 case ACT_REPLACE:
3480 if (!(t->flags & SN_CLDENY)) {
3481 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3482 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3483 }
3484 break;
3485 case ACT_REMOVE:
3486 if (!(t->flags & SN_CLDENY))
3487 delete_header = 1;
3488 break;
3489 case ACT_DENY:
3490 if (!(t->flags & SN_CLALLOW))
3491 t->flags |= SN_CLDENY;
3492 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003493 case ACT_PASS: /* we simply don't deny this one */
3494 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003495 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003496 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003497 }
willy tarreaue39cd132005-12-17 13:00:18 +01003498 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003499 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003500 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003501
willy tarreau240afa62005-12-17 13:14:35 +01003502 /* Now look for cookies. Conforming to RFC2109, we have to support
3503 * attributes whose name begin with a '$', and associate them with
3504 * the right cookie, if we want to delete this cookie.
3505 * So there are 3 cases for each cookie read :
3506 * 1) it's a special attribute, beginning with a '$' : ignore it.
3507 * 2) it's a server id cookie that we *MAY* want to delete : save
3508 * some pointers on it (last semi-colon, beginning of cookie...)
3509 * 3) it's an application cookie : we *MAY* have to delete a previous
3510 * "special" cookie.
3511 * At the end of loop, if a "special" cookie remains, we may have to
3512 * remove it. If no application cookie persists in the header, we
3513 * *MUST* delete it
3514 */
willy tarreau12350152005-12-18 01:03:27 +01003515 if (!delete_header &&
3516 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003517 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003518 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003519 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003520 char *del_colon, *del_cookie, *colon;
3521 int app_cookies;
3522
willy tarreau5cbea6f2005-12-17 12:48:26 +01003523 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003524 colon = p1;
3525 /* del_cookie == NULL => nothing to be deleted */
3526 del_colon = del_cookie = NULL;
3527 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003528
3529 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003530 /* skip spaces and colons, but keep an eye on these ones */
3531 while (p1 < ptr) {
3532 if (*p1 == ';' || *p1 == ',')
3533 colon = p1;
3534 else if (!isspace((int)*p1))
3535 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003536 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003537 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003538
3539 if (p1 == ptr)
3540 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003541
3542 /* p1 is at the beginning of the cookie name */
3543 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003544 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003545 p2++;
3546
3547 if (p2 == ptr)
3548 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003549
3550 p3 = p2 + 1; /* skips the '=' sign */
3551 if (p3 == ptr)
3552 break;
3553
willy tarreau240afa62005-12-17 13:14:35 +01003554 p4 = p3;
3555 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003556 p4++;
3557
3558 /* here, we have the cookie name between p1 and p2,
3559 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003560 * we can process it :
3561 *
3562 * Cookie: NAME=VALUE;
3563 * | || || |
3564 * | || || +--> p4
3565 * | || |+-------> p3
3566 * | || +--------> p2
3567 * | |+------------> p1
3568 * | +-------------> colon
3569 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003570 */
3571
willy tarreau240afa62005-12-17 13:14:35 +01003572 if (*p1 == '$') {
3573 /* skip this one */
3574 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003575 else {
3576 /* first, let's see if we want to capture it */
3577 if (t->proxy->capture_name != NULL &&
3578 t->logs.cli_cookie == NULL &&
3579 (p4 - p1 >= t->proxy->capture_namelen) &&
3580 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3581 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003582
willy tarreau8337c6b2005-12-17 13:41:01 +01003583 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3584 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003585 } else {
3586 if (log_len > t->proxy->capture_len)
3587 log_len = t->proxy->capture_len;
3588 memcpy(t->logs.cli_cookie, p1, log_len);
3589 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003590 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003591 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003592
3593 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3594 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3595 /* Cool... it's the right one */
3596 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003597 char *delim;
3598
3599 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3600 * have the server ID betweek p3 and delim, and the original cookie between
3601 * delim+1 and p4. Otherwise, delim==p4 :
3602 *
3603 * Cookie: NAME=SRV~VALUE;
3604 * | || || | |
3605 * | || || | +--> p4
3606 * | || || +--------> delim
3607 * | || |+-----------> p3
3608 * | || +------------> p2
3609 * | |+----------------> p1
3610 * | +-----------------> colon
3611 * +------------------------> req->h
3612 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003613
willy tarreau0174f312005-12-18 01:02:42 +01003614 if (t->proxy->options & PR_O_COOK_PFX) {
3615 for (delim = p3; delim < p4; delim++)
3616 if (*delim == COOKIE_DELIM)
3617 break;
3618 }
3619 else
3620 delim = p4;
3621
3622
3623 /* Here, we'll look for the first running server which supports the cookie.
3624 * This allows to share a same cookie between several servers, for example
3625 * to dedicate backup servers to specific servers only.
3626 */
3627 while (srv) {
3628 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3629 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3630 /* we found the server and it's usable */
3631 t->flags &= ~SN_CK_MASK;
3632 t->flags |= SN_CK_VALID | SN_DIRECT;
3633 t->srv = srv;
3634 break;
willy tarreau12350152005-12-18 01:03:27 +01003635 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003636 /* we found a server, but it's down */
3637 t->flags &= ~SN_CK_MASK;
3638 t->flags |= SN_CK_DOWN;
3639 }
3640 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003641 srv = srv->next;
3642 }
3643
willy tarreau0174f312005-12-18 01:02:42 +01003644 if (!srv && !(t->flags & SN_CK_DOWN)) {
3645 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003646 t->flags &= ~SN_CK_MASK;
3647 t->flags |= SN_CK_INVALID;
3648 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003649
willy tarreau0174f312005-12-18 01:02:42 +01003650 /* depending on the cookie mode, we may have to either :
3651 * - delete the complete cookie if we're in insert+indirect mode, so that
3652 * the server never sees it ;
3653 * - remove the server id from the cookie value, and tag the cookie as an
3654 * application cookie so that it does not get accidentely removed later,
3655 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003656 */
willy tarreau0174f312005-12-18 01:02:42 +01003657 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3658 buffer_replace2(req, p3, delim + 1, NULL, 0);
3659 p4 -= (delim + 1 - p3);
3660 ptr -= (delim + 1 - p3);
3661 del_cookie = del_colon = NULL;
3662 app_cookies++; /* protect the header from deletion */
3663 }
3664 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003665 (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 +01003666 del_cookie = p1;
3667 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003668 }
willy tarreau12350152005-12-18 01:03:27 +01003669 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003670 /* now we know that we must keep this cookie since it's
3671 * not ours. But if we wanted to delete our cookie
3672 * earlier, we cannot remove the complete header, but we
3673 * can remove the previous block itself.
3674 */
3675 app_cookies++;
3676
3677 if (del_cookie != NULL) {
3678 buffer_replace2(req, del_cookie, p1, NULL, 0);
3679 p4 -= (p1 - del_cookie);
3680 ptr -= (p1 - del_cookie);
3681 del_cookie = del_colon = NULL;
3682 }
willy tarreau240afa62005-12-17 13:14:35 +01003683 }
willy tarreau12350152005-12-18 01:03:27 +01003684
3685 if ((t->proxy->appsession_name != NULL) &&
3686 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3687 /* first, let's see if the cookie is our appcookie*/
3688
3689 /* Cool... it's the right one */
3690
3691 asession_temp = &local_asession;
3692
3693 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3694 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3695 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3696 return 0;
3697 }
3698
3699 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3700 asession_temp->sessid[t->proxy->appsession_len] = 0;
3701 asession_temp->serverid = NULL;
3702
3703 /* only do insert, if lookup fails */
3704 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3705 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3706 Alert("Not enough memory process_cli():asession:calloc().\n");
3707 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3708 return 0;
3709 }
3710
3711 asession_temp->sessid = local_asession.sessid;
3712 asession_temp->serverid = local_asession.serverid;
3713 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3714 }
3715 else{
3716 /* free wasted memory */
3717 pool_free_to(apools.sessid, local_asession.sessid);
3718 }
3719
3720 if (asession_temp->serverid == NULL) {
3721 Alert("Found Application Session without matching server.\n");
3722 } else {
3723 struct server *srv = t->proxy->srv;
3724 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003725 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003726 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3727 /* we found the server and it's usable */
3728 t->flags &= ~SN_CK_MASK;
3729 t->flags |= SN_CK_VALID | SN_DIRECT;
3730 t->srv = srv;
3731 break;
3732 } else {
3733 t->flags &= ~SN_CK_MASK;
3734 t->flags |= SN_CK_DOWN;
3735 }
3736 }
3737 srv = srv->next;
3738 }/* end while(srv) */
3739 }/* end else if server == NULL */
3740
3741 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003742 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003743 }
willy tarreau240afa62005-12-17 13:14:35 +01003744
willy tarreau5cbea6f2005-12-17 12:48:26 +01003745 /* we'll have to look for another cookie ... */
3746 p1 = p4;
3747 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003748
3749 /* There's no more cookie on this line.
3750 * We may have marked the last one(s) for deletion.
3751 * We must do this now in two ways :
3752 * - if there is no app cookie, we simply delete the header ;
3753 * - if there are app cookies, we must delete the end of the
3754 * string properly, including the colon/semi-colon before
3755 * the cookie name.
3756 */
3757 if (del_cookie != NULL) {
3758 if (app_cookies) {
3759 buffer_replace2(req, del_colon, ptr, NULL, 0);
3760 /* WARNING! <ptr> becomes invalid for now. If some code
3761 * below needs to rely on it before the end of the global
3762 * header loop, we need to correct it with this code :
3763 * ptr = del_colon;
3764 */
3765 }
3766 else
3767 delete_header = 1;
3768 }
3769 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003770
3771 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003772 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003773 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003774 }
willy tarreau240afa62005-12-17 13:14:35 +01003775 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3776
willy tarreau5cbea6f2005-12-17 12:48:26 +01003777 req->h = req->lr;
3778 } /* while (req->lr < req->r) */
3779
3780 /* end of header processing (even if incomplete) */
3781
willy tarreauef900ab2005-12-17 12:52:52 +01003782 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3783 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3784 * full. We cannot loop here since event_cli_read will disable it only if
3785 * req->l == rlim-data
3786 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003787 FD_SET(t->cli_fd, StaticReadEvent);
3788 if (t->proxy->clitimeout)
3789 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3790 else
3791 tv_eternity(&t->crexpire);
3792 }
3793
willy tarreaue39cd132005-12-17 13:00:18 +01003794 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003795 * won't be able to free more later, so the session will never terminate.
3796 */
willy tarreaue39cd132005-12-17 13:00:18 +01003797 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003798 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003799 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003800 if (!(t->flags & SN_ERR_MASK))
3801 t->flags |= SN_ERR_PRXCOND;
3802 if (!(t->flags & SN_FINST_MASK))
3803 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003804 return 1;
3805 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003806 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003807 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003808 tv_eternity(&t->crexpire);
3809 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003810 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003811 if (!(t->flags & SN_ERR_MASK))
3812 t->flags |= SN_ERR_CLICL;
3813 if (!(t->flags & SN_FINST_MASK))
3814 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003815 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003816 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003817 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3818
3819 /* read timeout : give up with an error message.
3820 */
3821 t->logs.status = 408;
3822 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003823 if (!(t->flags & SN_ERR_MASK))
3824 t->flags |= SN_ERR_CLITO;
3825 if (!(t->flags & SN_FINST_MASK))
3826 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003827 return 1;
3828 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003829
3830 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003831 }
3832 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003833 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003834 /* FIXME: this error handling is partly buggy because we always report
3835 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3836 * or HEADER phase. BTW, it's not logical to expire the client while
3837 * we're waiting for the server to connect.
3838 */
willy tarreau0f7af912005-12-17 12:21:26 +01003839 /* read or write error */
3840 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003841 tv_eternity(&t->crexpire);
3842 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003843 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003844 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003845 if (!(t->flags & SN_ERR_MASK))
3846 t->flags |= SN_ERR_CLICL;
3847 if (!(t->flags & SN_FINST_MASK))
3848 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003849 return 1;
3850 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003851 /* last read, or end of server write */
3852 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003853 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003854 tv_eternity(&t->crexpire);
3855 shutdown(t->cli_fd, SHUT_RD);
3856 t->cli_state = CL_STSHUTR;
3857 return 1;
3858 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003859 /* last server read and buffer empty */
3860 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003861 FD_CLR(t->cli_fd, StaticWriteEvent);
3862 tv_eternity(&t->cwexpire);
3863 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003864 /* We must ensure that the read part is still alive when switching
3865 * to shutw */
3866 FD_SET(t->cli_fd, StaticReadEvent);
3867 if (t->proxy->clitimeout)
3868 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003869 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003870 //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 +01003871 return 1;
3872 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003873 /* read timeout */
3874 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3875 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003876 tv_eternity(&t->crexpire);
3877 shutdown(t->cli_fd, SHUT_RD);
3878 t->cli_state = CL_STSHUTR;
3879 if (!(t->flags & SN_ERR_MASK))
3880 t->flags |= SN_ERR_CLITO;
3881 if (!(t->flags & SN_FINST_MASK))
3882 t->flags |= SN_FINST_D;
3883 return 1;
3884 }
3885 /* write timeout */
3886 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3887 FD_CLR(t->cli_fd, StaticWriteEvent);
3888 tv_eternity(&t->cwexpire);
3889 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003890 /* We must ensure that the read part is still alive when switching
3891 * to shutw */
3892 FD_SET(t->cli_fd, StaticReadEvent);
3893 if (t->proxy->clitimeout)
3894 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3895
willy tarreau036e1ce2005-12-17 13:46:33 +01003896 t->cli_state = CL_STSHUTW;
3897 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003898 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003899 if (!(t->flags & SN_FINST_MASK))
3900 t->flags |= SN_FINST_D;
3901 return 1;
3902 }
willy tarreau0f7af912005-12-17 12:21:26 +01003903
willy tarreauc58fc692005-12-17 14:13:08 +01003904 if (req->l >= req->rlim - req->data) {
3905 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003906 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003907 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003908 FD_CLR(t->cli_fd, StaticReadEvent);
3909 tv_eternity(&t->crexpire);
3910 }
3911 }
3912 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003913 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003914 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3915 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003916 if (!t->proxy->clitimeout ||
3917 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3918 /* If the client has no timeout, or if the server not ready yet, and we
3919 * know for sure that it can expire, then it's cleaner to disable the
3920 * timeout on the client side so that too low values cannot make the
3921 * sessions abort too early.
3922 */
willy tarreau0f7af912005-12-17 12:21:26 +01003923 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003924 else
3925 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003926 }
3927 }
3928
3929 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003930 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003931 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3932 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3933 tv_eternity(&t->cwexpire);
3934 }
3935 }
3936 else { /* buffer not empty */
3937 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3938 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003939 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003940 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003941 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3942 t->crexpire = t->cwexpire;
3943 }
willy tarreau0f7af912005-12-17 12:21:26 +01003944 else
3945 tv_eternity(&t->cwexpire);
3946 }
3947 }
3948 return 0; /* other cases change nothing */
3949 }
3950 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003951 if (t->res_cw == RES_ERROR) {
3952 tv_eternity(&t->cwexpire);
3953 fd_delete(t->cli_fd);
3954 t->cli_state = CL_STCLOSE;
3955 if (!(t->flags & SN_ERR_MASK))
3956 t->flags |= SN_ERR_CLICL;
3957 if (!(t->flags & SN_FINST_MASK))
3958 t->flags |= SN_FINST_D;
3959 return 1;
3960 }
3961 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003962 tv_eternity(&t->cwexpire);
3963 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003964 t->cli_state = CL_STCLOSE;
3965 return 1;
3966 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003967 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3968 tv_eternity(&t->cwexpire);
3969 fd_delete(t->cli_fd);
3970 t->cli_state = CL_STCLOSE;
3971 if (!(t->flags & SN_ERR_MASK))
3972 t->flags |= SN_ERR_CLITO;
3973 if (!(t->flags & SN_FINST_MASK))
3974 t->flags |= SN_FINST_D;
3975 return 1;
3976 }
willy tarreau0f7af912005-12-17 12:21:26 +01003977 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003978 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003979 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3980 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3981 tv_eternity(&t->cwexpire);
3982 }
3983 }
3984 else { /* buffer not empty */
3985 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3986 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003987 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003988 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003989 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3990 t->crexpire = t->cwexpire;
3991 }
willy tarreau0f7af912005-12-17 12:21:26 +01003992 else
3993 tv_eternity(&t->cwexpire);
3994 }
3995 }
3996 return 0;
3997 }
3998 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003999 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004000 tv_eternity(&t->crexpire);
4001 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004002 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004003 if (!(t->flags & SN_ERR_MASK))
4004 t->flags |= SN_ERR_CLICL;
4005 if (!(t->flags & SN_FINST_MASK))
4006 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004007 return 1;
4008 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004009 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4010 tv_eternity(&t->crexpire);
4011 fd_delete(t->cli_fd);
4012 t->cli_state = CL_STCLOSE;
4013 return 1;
4014 }
4015 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4016 tv_eternity(&t->crexpire);
4017 fd_delete(t->cli_fd);
4018 t->cli_state = CL_STCLOSE;
4019 if (!(t->flags & SN_ERR_MASK))
4020 t->flags |= SN_ERR_CLITO;
4021 if (!(t->flags & SN_FINST_MASK))
4022 t->flags |= SN_FINST_D;
4023 return 1;
4024 }
willy tarreauef900ab2005-12-17 12:52:52 +01004025 else if (req->l >= req->rlim - req->data) {
4026 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004027
4028 /* FIXME-20050705: is it possible for a client to maintain a session
4029 * after the timeout by sending more data after it receives a close ?
4030 */
4031
willy tarreau0f7af912005-12-17 12:21:26 +01004032 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004033 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004034 FD_CLR(t->cli_fd, StaticReadEvent);
4035 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004036 //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 +01004037 }
4038 }
4039 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004040 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004041 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4042 FD_SET(t->cli_fd, StaticReadEvent);
4043 if (t->proxy->clitimeout)
4044 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4045 else
4046 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004047 //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 +01004048 }
4049 }
4050 return 0;
4051 }
4052 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004053 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004054 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004055 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 +01004056 write(1, trash, len);
4057 }
4058 return 0;
4059 }
4060 return 0;
4061}
4062
4063
4064/*
4065 * manages the server FSM and its socket. It returns 1 if a state has changed
4066 * (and a resync may be needed), 0 else.
4067 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004068int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004069 int s = t->srv_state;
4070 int c = t->cli_state;
4071 struct buffer *req = t->req;
4072 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004073 appsess *asession_temp = NULL;
4074 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004075 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004076
willy tarreau750a4722005-12-17 13:21:24 +01004077#ifdef DEBUG_FULL
4078 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4079#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004080 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4081 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4082 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4083 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004084 if (s == SV_STIDLE) {
4085 if (c == CL_STHEADERS)
4086 return 0; /* stay in idle, waiting for data to reach the client side */
4087 else if (c == CL_STCLOSE ||
4088 c == CL_STSHUTW ||
4089 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4090 tv_eternity(&t->cnexpire);
4091 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004092 if (!(t->flags & SN_ERR_MASK))
4093 t->flags |= SN_ERR_CLICL;
4094 if (!(t->flags & SN_FINST_MASK))
4095 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004096 return 1;
4097 }
4098 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004099 /* initiate a connection to the server */
4100 conn_err = connect_server(t);
4101 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004102 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4103 t->srv_state = SV_STCONN;
4104 }
4105 else { /* try again */
4106 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004107 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004108 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004109 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004110 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4111 t->flags &= ~SN_CK_MASK;
4112 t->flags |= SN_CK_DOWN;
4113 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004114 }
4115
willy tarreaub1285d52005-12-18 01:20:14 +01004116 conn_err = connect_server(t);
4117 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004118 t->srv_state = SV_STCONN;
4119 break;
4120 }
4121 }
4122 if (t->conn_retries < 0) {
4123 /* if conn_retries < 0 or other error, let's abort */
4124 tv_eternity(&t->cnexpire);
4125 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004126 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004127 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004128 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004129 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004130 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004131 if (!(t->flags & SN_FINST_MASK))
4132 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004133 }
4134 }
4135 return 1;
4136 }
4137 }
4138 else if (s == SV_STCONN) { /* connection in progress */
4139 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004140 //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 +01004141 return 0; /* nothing changed */
4142 }
4143 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4144 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4145 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004146 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004147 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004148 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004149 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004150 if (t->conn_retries >= 0) {
4151 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004152 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004153 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004154 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4155 t->flags &= ~SN_CK_MASK;
4156 t->flags |= SN_CK_DOWN;
4157 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004158 }
willy tarreaub1285d52005-12-18 01:20:14 +01004159 conn_err = connect_server(t);
4160 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004161 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004162 }
willy tarreaub1285d52005-12-18 01:20:14 +01004163 else if (t->res_sw == RES_SILENT)
4164 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4165 else
4166 conn_err = SN_ERR_SRVCL; // it was a connect error.
4167
willy tarreau0f7af912005-12-17 12:21:26 +01004168 /* if conn_retries < 0 or other error, let's abort */
4169 tv_eternity(&t->cnexpire);
4170 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004171 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004172 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004173 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004174 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004175 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004176 if (!(t->flags & SN_FINST_MASK))
4177 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004178 return 1;
4179 }
4180 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004181 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004182
willy tarreau0f7af912005-12-17 12:21:26 +01004183 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004184 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004185 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004186 tv_eternity(&t->swexpire);
4187 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004188 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004189 if (t->proxy->srvtimeout) {
4190 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4191 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4192 t->srexpire = t->swexpire;
4193 }
4194 else
4195 tv_eternity(&t->swexpire);
4196 }
willy tarreau0f7af912005-12-17 12:21:26 +01004197
4198 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4199 FD_SET(t->srv_fd, StaticReadEvent);
4200 if (t->proxy->srvtimeout)
4201 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4202 else
4203 tv_eternity(&t->srexpire);
4204
4205 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004206 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004207
4208 /* if the user wants to log as soon as possible, without counting
4209 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004210 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004211 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4212 sess_log(t);
4213 }
willy tarreau0f7af912005-12-17 12:21:26 +01004214 }
willy tarreauef900ab2005-12-17 12:52:52 +01004215 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004216 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004217 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4218 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004219 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004220 return 1;
4221 }
4222 }
4223 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004224 /* now parse the partial (or complete) headers */
4225 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4226 char *ptr;
4227 int delete_header;
4228
4229 ptr = rep->lr;
4230
4231 /* look for the end of the current header */
4232 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4233 ptr++;
4234
4235 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004236 int line, len;
4237
4238 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004239
4240 /* first, we'll block if security checks have caught nasty things */
4241 if (t->flags & SN_CACHEABLE) {
4242 if ((t->flags & SN_CACHE_COOK) &&
4243 (t->flags & SN_SCK_ANY) &&
4244 (t->proxy->options & PR_O_CHK_CACHE)) {
4245
4246 /* we're in presence of a cacheable response containing
4247 * a set-cookie header. We'll block it as requested by
4248 * the 'checkcache' option, and send an alert.
4249 */
4250 tv_eternity(&t->srexpire);
4251 tv_eternity(&t->swexpire);
4252 fd_delete(t->srv_fd);
4253 t->srv_state = SV_STCLOSE;
4254 t->logs.status = 502;
4255 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4256 if (!(t->flags & SN_ERR_MASK))
4257 t->flags |= SN_ERR_PRXCOND;
4258 if (!(t->flags & SN_FINST_MASK))
4259 t->flags |= SN_FINST_H;
4260
4261 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4262 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4263
4264 return 1;
4265 }
4266 }
4267
willy tarreau982249e2005-12-18 00:57:06 +01004268 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4269 if (t->flags & SN_SVDENY) {
4270 tv_eternity(&t->srexpire);
4271 tv_eternity(&t->swexpire);
4272 fd_delete(t->srv_fd);
4273 t->srv_state = SV_STCLOSE;
4274 t->logs.status = 502;
4275 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4276 if (!(t->flags & SN_ERR_MASK))
4277 t->flags |= SN_ERR_PRXCOND;
4278 if (!(t->flags & SN_FINST_MASK))
4279 t->flags |= SN_FINST_H;
4280 return 1;
4281 }
4282
willy tarreau5cbea6f2005-12-17 12:48:26 +01004283 /* we'll have something else to do here : add new headers ... */
4284
willy tarreaucd878942005-12-17 13:27:43 +01004285 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4286 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004287 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004288 * insert a set-cookie here, except if we want to insert only on POST
4289 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004290 */
willy tarreau750a4722005-12-17 13:21:24 +01004291 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004292 t->proxy->cookie_name,
4293 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004294
willy tarreau036e1ce2005-12-17 13:46:33 +01004295 t->flags |= SN_SCK_INSERTED;
4296
willy tarreau750a4722005-12-17 13:21:24 +01004297 /* Here, we will tell an eventual cache on the client side that we don't
4298 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4299 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4300 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4301 */
willy tarreau240afa62005-12-17 13:14:35 +01004302 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004303 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4304 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004305
4306 if (rep->data + rep->l < rep->h)
4307 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4308 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004309 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004310 }
4311
4312 /* headers to be added */
4313 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004314 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4315 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004316 }
4317
willy tarreau25c4ea52005-12-18 00:49:49 +01004318 /* add a "connection: close" line if needed */
4319 if (t->proxy->options & PR_O_HTTP_CLOSE)
4320 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4321
willy tarreau5cbea6f2005-12-17 12:48:26 +01004322 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004323 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004324 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004325
Willy TARREAU767ba712006-03-01 22:40:50 +01004326 /* client connection already closed or option 'httpclose' required :
4327 * we close the server's outgoing connection right now.
4328 */
4329 if ((req->l == 0) &&
4330 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4331 FD_CLR(t->srv_fd, StaticWriteEvent);
4332 tv_eternity(&t->swexpire);
4333
4334 /* We must ensure that the read part is still alive when switching
4335 * to shutw */
4336 FD_SET(t->srv_fd, StaticReadEvent);
4337 if (t->proxy->srvtimeout)
4338 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4339
4340 shutdown(t->srv_fd, SHUT_WR);
4341 t->srv_state = SV_STSHUTW;
4342 }
4343
willy tarreau25c4ea52005-12-18 00:49:49 +01004344 /* if the user wants to log as soon as possible, without counting
4345 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004346 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004347 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4348 t->logs.bytes = rep->h - rep->data;
4349 sess_log(t);
4350 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004351 break;
4352 }
4353
4354 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4355 if (ptr > rep->r - 2) {
4356 /* this is a partial header, let's wait for more to come */
4357 rep->lr = ptr;
4358 break;
4359 }
4360
4361 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4362 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4363
4364 /* now we know that *ptr is either \r or \n,
4365 * and that there are at least 1 char after it.
4366 */
4367 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4368 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4369 else
4370 rep->lr = ptr + 2; /* \r\n or \n\r */
4371
4372 /*
4373 * now we know that we have a full header ; we can do whatever
4374 * we want with these pointers :
4375 * rep->h = beginning of header
4376 * ptr = end of header (first \r or \n)
4377 * rep->lr = beginning of next line (next rep->h)
4378 * rep->r = end of data (not used at this stage)
4379 */
4380
willy tarreaua1598082005-12-17 13:08:06 +01004381
willy tarreau982249e2005-12-18 00:57:06 +01004382 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004383 t->logs.logwait &= ~LW_RESP;
4384 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004385 switch (t->logs.status) {
4386 case 200:
4387 case 203:
4388 case 206:
4389 case 300:
4390 case 301:
4391 case 410:
4392 /* RFC2616 @13.4:
4393 * "A response received with a status code of
4394 * 200, 203, 206, 300, 301 or 410 MAY be stored
4395 * by a cache (...) unless a cache-control
4396 * directive prohibits caching."
4397 *
4398 * RFC2616 @9.5: POST method :
4399 * "Responses to this method are not cacheable,
4400 * unless the response includes appropriate
4401 * Cache-Control or Expires header fields."
4402 */
4403 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4404 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4405 break;
4406 default:
4407 break;
4408 }
willy tarreau4302f492005-12-18 01:00:37 +01004409 }
4410 else if (t->logs.logwait & LW_RSPHDR) {
4411 struct cap_hdr *h;
4412 int len;
4413 for (h = t->proxy->rsp_cap; h; h = h->next) {
4414 if ((h->namelen + 2 <= ptr - rep->h) &&
4415 (rep->h[h->namelen] == ':') &&
4416 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4417
4418 if (t->rsp_cap[h->index] == NULL)
4419 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4420
4421 len = ptr - (rep->h + h->namelen + 2);
4422 if (len > h->len)
4423 len = h->len;
4424
4425 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4426 t->rsp_cap[h->index][len]=0;
4427 }
4428 }
4429
willy tarreaua1598082005-12-17 13:08:06 +01004430 }
4431
willy tarreau5cbea6f2005-12-17 12:48:26 +01004432 delete_header = 0;
4433
willy tarreau982249e2005-12-18 00:57:06 +01004434 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004435 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004436 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 +01004437 max = ptr - rep->h;
4438 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004439 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004440 trash[len++] = '\n';
4441 write(1, trash, len);
4442 }
4443
willy tarreau25c4ea52005-12-18 00:49:49 +01004444 /* remove "connection: " if needed */
4445 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4446 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4447 delete_header = 1;
4448 }
4449
willy tarreau5cbea6f2005-12-17 12:48:26 +01004450 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004451 if (!delete_header && t->proxy->rsp_exp != NULL
4452 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004453 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004454 char term;
4455
4456 term = *ptr;
4457 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004458 exp = t->proxy->rsp_exp;
4459 do {
4460 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4461 switch (exp->action) {
4462 case ACT_ALLOW:
4463 if (!(t->flags & SN_SVDENY))
4464 t->flags |= SN_SVALLOW;
4465 break;
4466 case ACT_REPLACE:
4467 if (!(t->flags & SN_SVDENY)) {
4468 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4469 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4470 }
4471 break;
4472 case ACT_REMOVE:
4473 if (!(t->flags & SN_SVDENY))
4474 delete_header = 1;
4475 break;
4476 case ACT_DENY:
4477 if (!(t->flags & SN_SVALLOW))
4478 t->flags |= SN_SVDENY;
4479 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004480 case ACT_PASS: /* we simply don't deny this one */
4481 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004482 }
4483 break;
4484 }
willy tarreaue39cd132005-12-17 13:00:18 +01004485 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004486 *ptr = term; /* restore the string terminator */
4487 }
4488
willy tarreau97f58572005-12-18 00:53:44 +01004489 /* check for cache-control: or pragma: headers */
4490 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4491 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4492 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4493 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4494 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004495 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004496 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4497 else {
4498 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004499 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004500 t->flags &= ~SN_CACHE_COOK;
4501 }
4502 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004503 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004504 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004505 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004506 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4507 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004508 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004509 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004510 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4511 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4512 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4513 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4514 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4515 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004516 }
4517 }
4518 }
4519
willy tarreau5cbea6f2005-12-17 12:48:26 +01004520 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004521 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004522 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004523 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004524 char *p1, *p2, *p3, *p4;
4525
willy tarreau97f58572005-12-18 00:53:44 +01004526 t->flags |= SN_SCK_ANY;
4527
willy tarreau5cbea6f2005-12-17 12:48:26 +01004528 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4529
4530 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004531 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004532 p1++;
4533
4534 if (p1 == ptr || *p1 == ';') /* end of cookie */
4535 break;
4536
4537 /* p1 is at the beginning of the cookie name */
4538 p2 = p1;
4539
4540 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4541 p2++;
4542
4543 if (p2 == ptr || *p2 == ';') /* next cookie */
4544 break;
4545
4546 p3 = p2 + 1; /* skips the '=' sign */
4547 if (p3 == ptr)
4548 break;
4549
4550 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004551 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004552 p4++;
4553
4554 /* here, we have the cookie name between p1 and p2,
4555 * and its value between p3 and p4.
4556 * we can process it.
4557 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004558
4559 /* first, let's see if we want to capture it */
4560 if (t->proxy->capture_name != NULL &&
4561 t->logs.srv_cookie == NULL &&
4562 (p4 - p1 >= t->proxy->capture_namelen) &&
4563 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4564 int log_len = p4 - p1;
4565
4566 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4567 Alert("HTTP logging : out of memory.\n");
4568 }
4569
4570 if (log_len > t->proxy->capture_len)
4571 log_len = t->proxy->capture_len;
4572 memcpy(t->logs.srv_cookie, p1, log_len);
4573 t->logs.srv_cookie[log_len] = 0;
4574 }
4575
4576 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4577 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004578 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004579 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004580
4581 /* If the cookie is in insert mode on a known server, we'll delete
4582 * this occurrence because we'll insert another one later.
4583 * We'll delete it too if the "indirect" option is set and we're in
4584 * a direct access. */
4585 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004586 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004587 /* this header must be deleted */
4588 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004589 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004590 }
4591 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4592 /* replace bytes p3->p4 with the cookie name associated
4593 * with this server since we know it.
4594 */
4595 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004596 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004597 }
willy tarreau0174f312005-12-18 01:02:42 +01004598 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4599 /* insert the cookie name associated with this server
4600 * before existing cookie, and insert a delimitor between them..
4601 */
4602 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4603 p3[t->srv->cklen] = COOKIE_DELIM;
4604 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4605 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004606 break;
4607 }
willy tarreau12350152005-12-18 01:03:27 +01004608
4609 /* first, let's see if the cookie is our appcookie*/
4610 if ((t->proxy->appsession_name != NULL) &&
4611 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4612
4613 /* Cool... it's the right one */
4614
willy tarreaub952e1d2005-12-18 01:31:20 +01004615 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004616 asession_temp = &local_asession;
4617
willy tarreaub952e1d2005-12-18 01:31:20 +01004618 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004619 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4620 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4621 }
4622 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4623 asession_temp->sessid[t->proxy->appsession_len] = 0;
4624 asession_temp->serverid = NULL;
4625
4626 /* only do insert, if lookup fails */
4627 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4628 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4629 Alert("Not enought Memory process_srv():asession:calloc().\n");
4630 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4631 return 0;
4632 }
4633 asession_temp->sessid = local_asession.sessid;
4634 asession_temp->serverid = local_asession.serverid;
4635 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004636 }/* end if (chtbl_lookup()) */
4637 else {
willy tarreau12350152005-12-18 01:03:27 +01004638 /* free wasted memory */
4639 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004640 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004641
willy tarreaub952e1d2005-12-18 01:31:20 +01004642 if (asession_temp->serverid == NULL) {
4643 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004644 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4645 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4646 }
4647 asession_temp->serverid[0] = '\0';
4648 }
4649
willy tarreaub952e1d2005-12-18 01:31:20 +01004650 if (asession_temp->serverid[0] == '\0')
4651 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004652
4653 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4654
4655#if defined(DEBUG_HASH)
4656 print_table(&(t->proxy->htbl_proxy));
4657#endif
4658 break;
4659 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004660 else {
4661 // fprintf(stderr,"Ignoring unknown cookie : ");
4662 // write(2, p1, p2-p1);
4663 // fprintf(stderr," = ");
4664 // write(2, p3, p4-p3);
4665 // fprintf(stderr,"\n");
4666 }
4667 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4668 } /* we're now at the end of the cookie value */
4669 } /* end of cookie processing */
4670
willy tarreau97f58572005-12-18 00:53:44 +01004671 /* check for any set-cookie in case we check for cacheability */
4672 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4673 (t->proxy->options & PR_O_CHK_CACHE) &&
4674 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4675 t->flags |= SN_SCK_ANY;
4676 }
4677
willy tarreau5cbea6f2005-12-17 12:48:26 +01004678 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004679 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004680 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004681
willy tarreau5cbea6f2005-12-17 12:48:26 +01004682 rep->h = rep->lr;
4683 } /* while (rep->lr < rep->r) */
4684
4685 /* end of header processing (even if incomplete) */
4686
willy tarreauef900ab2005-12-17 12:52:52 +01004687 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4688 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4689 * full. We cannot loop here since event_srv_read will disable it only if
4690 * rep->l == rlim-data
4691 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004692 FD_SET(t->srv_fd, StaticReadEvent);
4693 if (t->proxy->srvtimeout)
4694 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4695 else
4696 tv_eternity(&t->srexpire);
4697 }
willy tarreau0f7af912005-12-17 12:21:26 +01004698
willy tarreau8337c6b2005-12-17 13:41:01 +01004699 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004700 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004701 tv_eternity(&t->srexpire);
4702 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004703 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004704 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004705 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004706 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004707 if (!(t->flags & SN_ERR_MASK))
4708 t->flags |= SN_ERR_SRVCL;
4709 if (!(t->flags & SN_FINST_MASK))
4710 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004711 return 1;
4712 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004713 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004714 * since we are in header mode, if there's no space left for headers, we
4715 * won't be able to free more later, so the session will never terminate.
4716 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004717 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 +01004718 FD_CLR(t->srv_fd, StaticReadEvent);
4719 tv_eternity(&t->srexpire);
4720 shutdown(t->srv_fd, SHUT_RD);
4721 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004722 //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 +01004723 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004724 }
4725 /* read timeout : return a 504 to the client.
4726 */
4727 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4728 tv_eternity(&t->srexpire);
4729 tv_eternity(&t->swexpire);
4730 fd_delete(t->srv_fd);
4731 t->srv_state = SV_STCLOSE;
4732 t->logs.status = 504;
4733 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004734 if (!(t->flags & SN_ERR_MASK))
4735 t->flags |= SN_ERR_SRVTO;
4736 if (!(t->flags & SN_FINST_MASK))
4737 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004738 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004739
4740 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004741 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004742 /* FIXME!!! here, we don't want to switch to SHUTW if the
4743 * client shuts read too early, because we may still have
4744 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004745 * The side-effect is that if the client completely closes its
4746 * connection during SV_STHEADER, the connection to the server
4747 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004748 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004749 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004750 FD_CLR(t->srv_fd, StaticWriteEvent);
4751 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004752
4753 /* We must ensure that the read part is still alive when switching
4754 * to shutw */
4755 FD_SET(t->srv_fd, StaticReadEvent);
4756 if (t->proxy->srvtimeout)
4757 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4758
willy tarreau0f7af912005-12-17 12:21:26 +01004759 shutdown(t->srv_fd, SHUT_WR);
4760 t->srv_state = SV_STSHUTW;
4761 return 1;
4762 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004763 /* write timeout */
4764 /* FIXME!!! here, we don't want to switch to SHUTW if the
4765 * client shuts read too early, because we may still have
4766 * some work to do on the headers.
4767 */
4768 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4769 FD_CLR(t->srv_fd, StaticWriteEvent);
4770 tv_eternity(&t->swexpire);
4771 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004772 /* We must ensure that the read part is still alive when switching
4773 * to shutw */
4774 FD_SET(t->srv_fd, StaticReadEvent);
4775 if (t->proxy->srvtimeout)
4776 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4777
4778 /* We must ensure that the read part is still alive when switching
4779 * to shutw */
4780 FD_SET(t->srv_fd, StaticReadEvent);
4781 if (t->proxy->srvtimeout)
4782 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4783
willy tarreau036e1ce2005-12-17 13:46:33 +01004784 t->srv_state = SV_STSHUTW;
4785 if (!(t->flags & SN_ERR_MASK))
4786 t->flags |= SN_ERR_SRVTO;
4787 if (!(t->flags & SN_FINST_MASK))
4788 t->flags |= SN_FINST_H;
4789 return 1;
4790 }
willy tarreau0f7af912005-12-17 12:21:26 +01004791
4792 if (req->l == 0) {
4793 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4794 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4795 tv_eternity(&t->swexpire);
4796 }
4797 }
4798 else { /* client buffer not empty */
4799 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4800 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004801 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004802 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004803 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4804 t->srexpire = t->swexpire;
4805 }
willy tarreau0f7af912005-12-17 12:21:26 +01004806 else
4807 tv_eternity(&t->swexpire);
4808 }
4809 }
4810
willy tarreau5cbea6f2005-12-17 12:48:26 +01004811 /* be nice with the client side which would like to send a complete header
4812 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4813 * would read all remaining data at once ! The client should not write past rep->lr
4814 * when the server is in header state.
4815 */
4816 //return header_processed;
4817 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004818 }
4819 else if (s == SV_STDATA) {
4820 /* read or write error */
4821 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004822 tv_eternity(&t->srexpire);
4823 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004824 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004825 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004826 if (!(t->flags & SN_ERR_MASK))
4827 t->flags |= SN_ERR_SRVCL;
4828 if (!(t->flags & SN_FINST_MASK))
4829 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004830 return 1;
4831 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004832 /* last read, or end of client write */
4833 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004834 FD_CLR(t->srv_fd, StaticReadEvent);
4835 tv_eternity(&t->srexpire);
4836 shutdown(t->srv_fd, SHUT_RD);
4837 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004838 //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 +01004839 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004840 }
4841 /* end of client read and no more data to send */
4842 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4843 FD_CLR(t->srv_fd, StaticWriteEvent);
4844 tv_eternity(&t->swexpire);
4845 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004846 /* We must ensure that the read part is still alive when switching
4847 * to shutw */
4848 FD_SET(t->srv_fd, StaticReadEvent);
4849 if (t->proxy->srvtimeout)
4850 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4851
willy tarreaua41a8b42005-12-17 14:02:24 +01004852 t->srv_state = SV_STSHUTW;
4853 return 1;
4854 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004855 /* read timeout */
4856 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4857 FD_CLR(t->srv_fd, StaticReadEvent);
4858 tv_eternity(&t->srexpire);
4859 shutdown(t->srv_fd, SHUT_RD);
4860 t->srv_state = SV_STSHUTR;
4861 if (!(t->flags & SN_ERR_MASK))
4862 t->flags |= SN_ERR_SRVTO;
4863 if (!(t->flags & SN_FINST_MASK))
4864 t->flags |= SN_FINST_D;
4865 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004866 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004867 /* write timeout */
4868 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004869 FD_CLR(t->srv_fd, StaticWriteEvent);
4870 tv_eternity(&t->swexpire);
4871 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004872 /* We must ensure that the read part is still alive when switching
4873 * to shutw */
4874 FD_SET(t->srv_fd, StaticReadEvent);
4875 if (t->proxy->srvtimeout)
4876 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004877 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004878 if (!(t->flags & SN_ERR_MASK))
4879 t->flags |= SN_ERR_SRVTO;
4880 if (!(t->flags & SN_FINST_MASK))
4881 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004882 return 1;
4883 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004884
4885 /* recompute request time-outs */
4886 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004887 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4888 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4889 tv_eternity(&t->swexpire);
4890 }
4891 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004892 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004893 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4894 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004895 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004896 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004897 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4898 t->srexpire = t->swexpire;
4899 }
willy tarreau0f7af912005-12-17 12:21:26 +01004900 else
4901 tv_eternity(&t->swexpire);
4902 }
4903 }
4904
willy tarreaub1ff9db2005-12-17 13:51:03 +01004905 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004906 if (rep->l == BUFSIZE) { /* no room to read more data */
4907 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4908 FD_CLR(t->srv_fd, StaticReadEvent);
4909 tv_eternity(&t->srexpire);
4910 }
4911 }
4912 else {
4913 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4914 FD_SET(t->srv_fd, StaticReadEvent);
4915 if (t->proxy->srvtimeout)
4916 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4917 else
4918 tv_eternity(&t->srexpire);
4919 }
4920 }
4921
4922 return 0; /* other cases change nothing */
4923 }
4924 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004925 if (t->res_sw == RES_ERROR) {
4926 //FD_CLR(t->srv_fd, StaticWriteEvent);
4927 tv_eternity(&t->swexpire);
4928 fd_delete(t->srv_fd);
4929 //close(t->srv_fd);
4930 t->srv_state = SV_STCLOSE;
4931 if (!(t->flags & SN_ERR_MASK))
4932 t->flags |= SN_ERR_SRVCL;
4933 if (!(t->flags & SN_FINST_MASK))
4934 t->flags |= SN_FINST_D;
4935 return 1;
4936 }
4937 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004938 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004939 tv_eternity(&t->swexpire);
4940 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004941 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004942 t->srv_state = SV_STCLOSE;
4943 return 1;
4944 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004945 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4946 //FD_CLR(t->srv_fd, StaticWriteEvent);
4947 tv_eternity(&t->swexpire);
4948 fd_delete(t->srv_fd);
4949 //close(t->srv_fd);
4950 t->srv_state = SV_STCLOSE;
4951 if (!(t->flags & SN_ERR_MASK))
4952 t->flags |= SN_ERR_SRVTO;
4953 if (!(t->flags & SN_FINST_MASK))
4954 t->flags |= SN_FINST_D;
4955 return 1;
4956 }
willy tarreau0f7af912005-12-17 12:21:26 +01004957 else if (req->l == 0) {
4958 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4959 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4960 tv_eternity(&t->swexpire);
4961 }
4962 }
4963 else { /* buffer not empty */
4964 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4965 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004966 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004967 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004968 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4969 t->srexpire = t->swexpire;
4970 }
willy tarreau0f7af912005-12-17 12:21:26 +01004971 else
4972 tv_eternity(&t->swexpire);
4973 }
4974 }
4975 return 0;
4976 }
4977 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004978 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004979 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004980 tv_eternity(&t->srexpire);
4981 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004982 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004983 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004984 if (!(t->flags & SN_ERR_MASK))
4985 t->flags |= SN_ERR_SRVCL;
4986 if (!(t->flags & SN_FINST_MASK))
4987 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004988 return 1;
4989 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004990 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4991 //FD_CLR(t->srv_fd, StaticReadEvent);
4992 tv_eternity(&t->srexpire);
4993 fd_delete(t->srv_fd);
4994 //close(t->srv_fd);
4995 t->srv_state = SV_STCLOSE;
4996 return 1;
4997 }
4998 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4999 //FD_CLR(t->srv_fd, StaticReadEvent);
5000 tv_eternity(&t->srexpire);
5001 fd_delete(t->srv_fd);
5002 //close(t->srv_fd);
5003 t->srv_state = SV_STCLOSE;
5004 if (!(t->flags & SN_ERR_MASK))
5005 t->flags |= SN_ERR_SRVTO;
5006 if (!(t->flags & SN_FINST_MASK))
5007 t->flags |= SN_FINST_D;
5008 return 1;
5009 }
willy tarreau0f7af912005-12-17 12:21:26 +01005010 else if (rep->l == BUFSIZE) { /* no room to read more data */
5011 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5012 FD_CLR(t->srv_fd, StaticReadEvent);
5013 tv_eternity(&t->srexpire);
5014 }
5015 }
5016 else {
5017 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5018 FD_SET(t->srv_fd, StaticReadEvent);
5019 if (t->proxy->srvtimeout)
5020 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5021 else
5022 tv_eternity(&t->srexpire);
5023 }
5024 }
5025 return 0;
5026 }
5027 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005028 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005029 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005030 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 +01005031 write(1, trash, len);
5032 }
5033 return 0;
5034 }
5035 return 0;
5036}
5037
5038
willy tarreau5cbea6f2005-12-17 12:48:26 +01005039/* Processes the client and server jobs of a session task, then
5040 * puts it back to the wait queue in a clean state, or
5041 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005042 * the time the task accepts to wait, or TIME_ETERNITY for
5043 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005044 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005045int process_session(struct task *t) {
5046 struct session *s = t->context;
5047 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005048
willy tarreau5cbea6f2005-12-17 12:48:26 +01005049 do {
5050 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005051 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005052 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005053 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005054 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005055 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005056 } while (fsm_resync);
5057
5058 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005059 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005060 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005061
willy tarreau5cbea6f2005-12-17 12:48:26 +01005062 tv_min(&min1, &s->crexpire, &s->cwexpire);
5063 tv_min(&min2, &s->srexpire, &s->swexpire);
5064 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005065 tv_min(&t->expire, &min1, &min2);
5066
5067 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005068 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005069
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005070#ifdef DEBUG_FULL
5071 /* DEBUG code : this should never ever happen, otherwise it indicates
5072 * that a task still has something to do and will provoke a quick loop.
5073 */
5074 if (tv_remain2(&now, &t->expire) <= 0)
5075 exit(100);
5076#endif
5077
willy tarreaub952e1d2005-12-18 01:31:20 +01005078 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005079 }
5080
willy tarreau5cbea6f2005-12-17 12:48:26 +01005081 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005082 actconn--;
5083
willy tarreau982249e2005-12-18 00:57:06 +01005084 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005085 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005086 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 +01005087 write(1, trash, len);
5088 }
5089
willy tarreau750a4722005-12-17 13:21:24 +01005090 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005091 if (s->rep != NULL)
5092 s->logs.bytes = s->rep->total;
5093
willy tarreau9fe663a2005-12-17 13:02:59 +01005094 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005095 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005096 sess_log(s);
5097
willy tarreau0f7af912005-12-17 12:21:26 +01005098 /* the task MUST not be in the run queue anymore */
5099 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005100 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005101 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005102 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005103}
5104
5105
5106
5107/*
5108 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005109 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005110 */
5111int process_chk(struct task *t) {
5112 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005113 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005114 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005115
willy tarreauef900ab2005-12-17 12:52:52 +01005116 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005117
willy tarreau25424f82006-03-19 19:37:48 +01005118 new_chk:
5119 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005120 if (fd < 0) { /* no check currently running */
5121 //fprintf(stderr, "process_chk: 2\n");
5122 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5123 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005124 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005125 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005126
5127 /* we don't send any health-checks when the proxy is stopped or when
5128 * the server should not be checked.
5129 */
5130 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005131 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5132 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005133 task_queue(t); /* restore t to its place in the task list */
5134 return tv_remain2(&now, &t->expire);
5135 }
5136
willy tarreau5cbea6f2005-12-17 12:48:26 +01005137 /* we'll initiate a new check */
5138 s->result = 0; /* no result yet */
5139 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005140 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005141 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5142 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5143 //fprintf(stderr, "process_chk: 3\n");
5144
willy tarreaua41a8b42005-12-17 14:02:24 +01005145 /* we'll connect to the check port on the server */
5146 sa = s->addr;
5147 sa.sin_port = htons(s->check_port);
5148
willy tarreau0174f312005-12-18 01:02:42 +01005149 /* allow specific binding :
5150 * - server-specific at first
5151 * - proxy-specific next
5152 */
5153 if (s->state & SRV_BIND_SRC) {
5154 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5155 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5156 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5157 s->proxy->id, s->id);
5158 s->result = -1;
5159 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005160 }
willy tarreau0174f312005-12-18 01:02:42 +01005161 else if (s->proxy->options & PR_O_BIND_SRC) {
5162 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5163 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5164 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5165 s->proxy->id);
5166 s->result = -1;
5167 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005168 }
willy tarreau0174f312005-12-18 01:02:42 +01005169
5170 if (!s->result) {
5171 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5172 /* OK, connection in progress or established */
5173
5174 //fprintf(stderr, "process_chk: 4\n");
5175
5176 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5177 fdtab[fd].owner = t;
5178 fdtab[fd].read = &event_srv_chk_r;
5179 fdtab[fd].write = &event_srv_chk_w;
5180 fdtab[fd].state = FD_STCONN; /* connection in progress */
5181 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005182#ifdef DEBUG_FULL
5183 assert (!FD_ISSET(fd, StaticReadEvent));
5184#endif
willy tarreau0174f312005-12-18 01:02:42 +01005185 fd_insert(fd);
5186 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5187 tv_delayfrom(&t->expire, &now, s->inter);
5188 task_queue(t); /* restore t to its place in the task list */
5189 return tv_remain(&now, &t->expire);
5190 }
5191 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5192 s->result = -1; /* a real error */
5193 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005194 }
5195 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005196 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005197 }
5198
5199 if (!s->result) { /* nothing done */
5200 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005201 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5202 tv_delayfrom(&t->expire, &t->expire, s->inter);
5203 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005204 }
5205
5206 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005207 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005208 s->health--; /* still good */
5209 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005210 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005211 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005212 recount_servers(s->proxy);
5213 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5214 s->state & SRV_BACKUP ? "Backup " : "",
5215 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5216 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5217 send_log(s->proxy, LOG_ALERT,
5218 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5219 s->state & SRV_BACKUP ? "Backup " : "",
5220 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5221 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005222
willy tarreau62084d42006-03-24 18:57:41 +01005223 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005224 Alert("Proxy %s has no server available !\n", s->proxy->id);
5225 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5226 }
5227 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005228 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005229 }
5230
5231 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005232 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005233 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5234 tv_delayfrom(&t->expire, &t->expire, s->inter);
5235 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005236 }
5237 else {
5238 //fprintf(stderr, "process_chk: 8\n");
5239 /* there was a test running */
5240 if (s->result > 0) { /* good server detected */
5241 //fprintf(stderr, "process_chk: 9\n");
5242 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005243 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005244 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005245 recount_servers(s->proxy);
5246 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5247 s->state & SRV_BACKUP ? "Backup " : "",
5248 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5249 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5250 send_log(s->proxy, LOG_NOTICE,
5251 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5252 s->state & SRV_BACKUP ? "Backup " : "",
5253 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5254 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005255 }
willy tarreauef900ab2005-12-17 12:52:52 +01005256
willy tarreaue47c8d72005-12-17 12:55:52 +01005257 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005258 s->state |= SRV_RUNNING;
5259 }
willy tarreauef900ab2005-12-17 12:52:52 +01005260 s->curfd = -1; /* no check running anymore */
5261 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005262 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005263 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5264 tv_delayfrom(&t->expire, &t->expire, s->inter);
5265 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005266 }
5267 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5268 //fprintf(stderr, "process_chk: 10\n");
5269 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005270 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005271 s->health--; /* still good */
5272 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005273 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005274
willy tarreau62084d42006-03-24 18:57:41 +01005275 if (s->health == s->rise) {
5276 recount_servers(s->proxy);
5277 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5278 s->state & SRV_BACKUP ? "Backup " : "",
5279 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5280 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5281 send_log(s->proxy, LOG_ALERT,
5282 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5283 s->state & SRV_BACKUP ? "Backup " : "",
5284 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5285 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5286
5287 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5288 Alert("Proxy %s has no server available !\n", s->proxy->id);
5289 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5290 }
5291 }
willy tarreauef900ab2005-12-17 12:52:52 +01005292
willy tarreau5cbea6f2005-12-17 12:48:26 +01005293 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005294 }
5295 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005296 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005297 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005298 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5299 tv_delayfrom(&t->expire, &t->expire, s->inter);
5300 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005301 }
5302 /* if result is 0 and there's no timeout, we have to wait again */
5303 }
5304 //fprintf(stderr, "process_chk: 11\n");
5305 s->result = 0;
5306 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005307 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005308}
5309
5310
willy tarreau5cbea6f2005-12-17 12:48:26 +01005311
willy tarreau0f7af912005-12-17 12:21:26 +01005312#if STATTIME > 0
5313int stats(void);
5314#endif
5315
5316/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005317 * This does 4 things :
5318 * - wake up all expired tasks
5319 * - call all runnable tasks
5320 * - call maintain_proxies() to enable/disable the listeners
5321 * - return the delay till next event in ms, -1 = wait indefinitely
5322 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5323 *
willy tarreau0f7af912005-12-17 12:21:26 +01005324 */
5325
willy tarreau1c2ad212005-12-18 01:11:29 +01005326int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005327 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005328 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005329 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005330
willy tarreaub952e1d2005-12-18 01:31:20 +01005331 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005332
willy tarreau1c2ad212005-12-18 01:11:29 +01005333 /* look for expired tasks and add them to the run queue.
5334 */
5335 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5336 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5337 tnext = t->next;
5338 if (t->state & TASK_RUNNING)
5339 continue;
5340
willy tarreaub952e1d2005-12-18 01:31:20 +01005341 if (tv_iseternity(&t->expire))
5342 continue;
5343
willy tarreau1c2ad212005-12-18 01:11:29 +01005344 /* wakeup expired entries. It doesn't matter if they are
5345 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005346 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005347 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005348 task_wakeup(&rq, t);
5349 }
5350 else {
5351 /* first non-runnable task. Use its expiration date as an upper bound */
5352 int temp_time = tv_remain(&now, &t->expire);
5353 if (temp_time)
5354 next_time = temp_time;
5355 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005356 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005357 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005358
willy tarreau1c2ad212005-12-18 01:11:29 +01005359 /* process each task in the run queue now. Each task may be deleted
5360 * since we only use tnext.
5361 */
5362 tnext = rq;
5363 while ((t = tnext) != NULL) {
5364 int temp_time;
5365
5366 tnext = t->rqnext;
5367 task_sleep(&rq, t);
5368 temp_time = t->process(t);
5369 next_time = MINTIME(temp_time, next_time);
5370 }
5371
5372 /* maintain all proxies in a consistent state. This should quickly become a task */
5373 time2 = maintain_proxies();
5374 return MINTIME(time2, next_time);
5375}
5376
5377
5378#if defined(ENABLE_EPOLL)
5379
5380/*
5381 * Main epoll() loop.
5382 */
5383
5384/* does 3 actions :
5385 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5386 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5387 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5388 *
5389 * returns 0 if initialization failed, !0 otherwise.
5390 */
5391
5392int epoll_loop(int action) {
5393 int next_time;
5394 int status;
5395 int fd;
5396
5397 int fds, count;
5398 int pr, pw, sr, sw;
5399 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5400 struct epoll_event ev;
5401
5402 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005403 static struct epoll_event *epoll_events = NULL;
5404 static int epoll_fd;
5405
5406 if (action == POLL_LOOP_ACTION_INIT) {
5407 epoll_fd = epoll_create(global.maxsock + 1);
5408 if (epoll_fd < 0)
5409 return 0;
5410 else {
5411 epoll_events = (struct epoll_event*)
5412 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5413 PrevReadEvent = (fd_set *)
5414 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5415 PrevWriteEvent = (fd_set *)
5416 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005417 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005418 return 1;
5419 }
5420 else if (action == POLL_LOOP_ACTION_CLEAN) {
5421 if (PrevWriteEvent) free(PrevWriteEvent);
5422 if (PrevReadEvent) free(PrevReadEvent);
5423 if (epoll_events) free(epoll_events);
5424 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005425 epoll_fd = 0;
5426 return 1;
5427 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005428
willy tarreau1c2ad212005-12-18 01:11:29 +01005429 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005430
willy tarreau1c2ad212005-12-18 01:11:29 +01005431 tv_now(&now);
5432
5433 while (1) {
5434 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005435
5436 /* stop when there's no connection left and we don't allow them anymore */
5437 if (!actconn && listeners == 0)
5438 break;
5439
willy tarreau0f7af912005-12-17 12:21:26 +01005440#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005441 {
5442 int time2;
5443 time2 = stats();
5444 next_time = MINTIME(time2, next_time);
5445 }
willy tarreau0f7af912005-12-17 12:21:26 +01005446#endif
5447
willy tarreau1c2ad212005-12-18 01:11:29 +01005448 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5449
5450 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5451 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5452
5453 if ((ro^rn) | (wo^wn)) {
5454 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5455#define FDSETS_ARE_INT_ALIGNED
5456#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005457
willy tarreauad90a0c2005-12-18 01:09:15 +01005458#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5459#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005460 pr = (ro >> count) & 1;
5461 pw = (wo >> count) & 1;
5462 sr = (rn >> count) & 1;
5463 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005464#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005465 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5466 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5467 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5468 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005469#endif
5470#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005471 pr = FD_ISSET(fd, PrevReadEvent);
5472 pw = FD_ISSET(fd, PrevWriteEvent);
5473 sr = FD_ISSET(fd, StaticReadEvent);
5474 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005475#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005476 if (!((sr^pr) | (sw^pw)))
5477 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005478
willy tarreau1c2ad212005-12-18 01:11:29 +01005479 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5480 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005481
willy tarreaub952e1d2005-12-18 01:31:20 +01005482#ifdef EPOLL_CTL_MOD_WORKAROUND
5483 /* I encountered a rarely reproducible problem with
5484 * EPOLL_CTL_MOD where a modified FD (systematically
5485 * the one in epoll_events[0], fd#7) would sometimes
5486 * be set EPOLL_OUT while asked for a read ! This is
5487 * with the 2.4 epoll patch. The workaround is to
5488 * delete then recreate in case of modification.
5489 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5490 * nor RHEL kernels.
5491 */
5492
5493 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5494 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5495
5496 if ((sr | sw))
5497 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5498#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005499 if ((pr | pw)) {
5500 /* the file-descriptor already exists... */
5501 if ((sr | sw)) {
5502 /* ...and it will still exist */
5503 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5504 // perror("epoll_ctl(MOD)");
5505 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005506 }
5507 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005508 /* ...and it will be removed */
5509 if (fdtab[fd].state != FD_STCLOSE &&
5510 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5511 // perror("epoll_ctl(DEL)");
5512 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005513 }
5514 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005515 } else {
5516 /* the file-descriptor did not exist, let's add it */
5517 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5518 // perror("epoll_ctl(ADD)");
5519 // exit(1);
5520 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005521 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005522#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005523 }
5524 ((int*)PrevReadEvent)[fds] = rn;
5525 ((int*)PrevWriteEvent)[fds] = wn;
5526 }
5527 }
5528
5529 /* now let's wait for events */
5530 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5531 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005532
willy tarreau1c2ad212005-12-18 01:11:29 +01005533 for (count = 0; count < status; count++) {
5534 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005535
5536 if (FD_ISSET(fd, StaticReadEvent)) {
5537 if (fdtab[fd].state == FD_STCLOSE)
5538 continue;
5539 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5540 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005541 }
willy tarreau05be12b2006-03-19 19:35:00 +01005542
5543 if (FD_ISSET(fd, StaticWriteEvent)) {
5544 if (fdtab[fd].state == FD_STCLOSE)
5545 continue;
5546 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5547 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005548 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005549 }
5550 }
5551 return 1;
5552}
5553#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005554
willy tarreauad90a0c2005-12-18 01:09:15 +01005555
willy tarreau5cbea6f2005-12-17 12:48:26 +01005556
willy tarreau1c2ad212005-12-18 01:11:29 +01005557#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005558
willy tarreau1c2ad212005-12-18 01:11:29 +01005559/*
5560 * Main poll() loop.
5561 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005562
willy tarreau1c2ad212005-12-18 01:11:29 +01005563/* does 3 actions :
5564 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5565 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5566 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5567 *
5568 * returns 0 if initialization failed, !0 otherwise.
5569 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005570
willy tarreau1c2ad212005-12-18 01:11:29 +01005571int poll_loop(int action) {
5572 int next_time;
5573 int status;
5574 int fd, nbfd;
5575
5576 int fds, count;
5577 int sr, sw;
5578 unsigned rn, wn; /* read new, write new */
5579
5580 /* private data */
5581 static struct pollfd *poll_events = NULL;
5582
5583 if (action == POLL_LOOP_ACTION_INIT) {
5584 poll_events = (struct pollfd*)
5585 calloc(1, sizeof(struct pollfd) * global.maxsock);
5586 return 1;
5587 }
5588 else if (action == POLL_LOOP_ACTION_CLEAN) {
5589 if (poll_events)
5590 free(poll_events);
5591 return 1;
5592 }
5593
5594 /* OK, it's POLL_LOOP_ACTION_RUN */
5595
5596 tv_now(&now);
5597
5598 while (1) {
5599 next_time = process_runnable_tasks();
5600
5601 /* stop when there's no connection left and we don't allow them anymore */
5602 if (!actconn && listeners == 0)
5603 break;
5604
5605#if STATTIME > 0
5606 {
5607 int time2;
5608 time2 = stats();
5609 next_time = MINTIME(time2, next_time);
5610 }
5611#endif
5612
5613
5614 nbfd = 0;
5615 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5616
5617 rn = ((int*)StaticReadEvent)[fds];
5618 wn = ((int*)StaticWriteEvent)[fds];
5619
5620 if ((rn|wn)) {
5621 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5622#define FDSETS_ARE_INT_ALIGNED
5623#ifdef FDSETS_ARE_INT_ALIGNED
5624
5625#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5626#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5627 sr = (rn >> count) & 1;
5628 sw = (wn >> count) & 1;
5629#else
5630 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5631 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5632#endif
5633#else
5634 sr = FD_ISSET(fd, StaticReadEvent);
5635 sw = FD_ISSET(fd, StaticWriteEvent);
5636#endif
5637 if ((sr|sw)) {
5638 poll_events[nbfd].fd = fd;
5639 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5640 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005641 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005642 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005643 }
5644 }
5645
5646 /* now let's wait for events */
5647 status = poll(poll_events, nbfd, next_time);
5648 tv_now(&now);
5649
5650 for (count = 0; status > 0 && count < nbfd; count++) {
5651 fd = poll_events[count].fd;
5652
5653 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5654 continue;
5655
5656 /* ok, we found one active fd */
5657 status--;
5658
willy tarreau05be12b2006-03-19 19:35:00 +01005659 if (FD_ISSET(fd, StaticReadEvent)) {
5660 if (fdtab[fd].state == FD_STCLOSE)
5661 continue;
5662 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5663 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005664 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005665
willy tarreau05be12b2006-03-19 19:35:00 +01005666 if (FD_ISSET(fd, StaticWriteEvent)) {
5667 if (fdtab[fd].state == FD_STCLOSE)
5668 continue;
5669 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5670 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005671 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005672 }
5673 }
5674 return 1;
5675}
willy tarreauad90a0c2005-12-18 01:09:15 +01005676#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005677
willy tarreauad90a0c2005-12-18 01:09:15 +01005678
willy tarreauad90a0c2005-12-18 01:09:15 +01005679
willy tarreau1c2ad212005-12-18 01:11:29 +01005680/*
5681 * Main select() loop.
5682 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005683
willy tarreau1c2ad212005-12-18 01:11:29 +01005684/* does 3 actions :
5685 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5686 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5687 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5688 *
5689 * returns 0 if initialization failed, !0 otherwise.
5690 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005691
willy tarreauad90a0c2005-12-18 01:09:15 +01005692
willy tarreau1c2ad212005-12-18 01:11:29 +01005693int select_loop(int action) {
5694 int next_time;
5695 int status;
5696 int fd,i;
5697 struct timeval delta;
5698 int readnotnull, writenotnull;
5699 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005700
willy tarreau1c2ad212005-12-18 01:11:29 +01005701 if (action == POLL_LOOP_ACTION_INIT) {
5702 ReadEvent = (fd_set *)
5703 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5704 WriteEvent = (fd_set *)
5705 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5706 return 1;
5707 }
5708 else if (action == POLL_LOOP_ACTION_CLEAN) {
5709 if (WriteEvent) free(WriteEvent);
5710 if (ReadEvent) free(ReadEvent);
5711 return 1;
5712 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005713
willy tarreau1c2ad212005-12-18 01:11:29 +01005714 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005715
willy tarreau1c2ad212005-12-18 01:11:29 +01005716 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005717
willy tarreau1c2ad212005-12-18 01:11:29 +01005718 while (1) {
5719 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005720
willy tarreau1c2ad212005-12-18 01:11:29 +01005721 /* stop when there's no connection left and we don't allow them anymore */
5722 if (!actconn && listeners == 0)
5723 break;
5724
5725#if STATTIME > 0
5726 {
5727 int time2;
5728 time2 = stats();
5729 next_time = MINTIME(time2, next_time);
5730 }
5731#endif
5732
willy tarreau1c2ad212005-12-18 01:11:29 +01005733 if (next_time > 0) { /* FIXME */
5734 /* Convert to timeval */
5735 /* to avoid eventual select loops due to timer precision */
5736 next_time += SCHEDULER_RESOLUTION;
5737 delta.tv_sec = next_time / 1000;
5738 delta.tv_usec = (next_time % 1000) * 1000;
5739 }
5740 else if (next_time == 0) { /* allow select to return immediately when needed */
5741 delta.tv_sec = delta.tv_usec = 0;
5742 }
5743
5744
5745 /* let's restore fdset state */
5746
5747 readnotnull = 0; writenotnull = 0;
5748 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5749 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5750 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5751 }
5752
5753 // /* just a verification code, needs to be removed for performance */
5754 // for (i=0; i<maxfd; i++) {
5755 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5756 // abort();
5757 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5758 // abort();
5759 //
5760 // }
5761
5762 status = select(maxfd,
5763 readnotnull ? ReadEvent : NULL,
5764 writenotnull ? WriteEvent : NULL,
5765 NULL,
5766 (next_time >= 0) ? &delta : NULL);
5767
5768 /* this is an experiment on the separation of the select work */
5769 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5770 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5771
5772 tv_now(&now);
5773
5774 if (status > 0) { /* must proceed with events */
5775
5776 int fds;
5777 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005778
willy tarreau1c2ad212005-12-18 01:11:29 +01005779 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5780 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5781 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5782
5783 /* if we specify read first, the accepts and zero reads will be
5784 * seen first. Moreover, system buffers will be flushed faster.
5785 */
willy tarreau05be12b2006-03-19 19:35:00 +01005786 if (FD_ISSET(fd, ReadEvent)) {
5787 if (fdtab[fd].state == FD_STCLOSE)
5788 continue;
5789 fdtab[fd].read(fd);
5790 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005791
willy tarreau05be12b2006-03-19 19:35:00 +01005792 if (FD_ISSET(fd, WriteEvent)) {
5793 if (fdtab[fd].state == FD_STCLOSE)
5794 continue;
5795 fdtab[fd].write(fd);
5796 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005797 }
5798 }
5799 else {
5800 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005801 }
willy tarreau0f7af912005-12-17 12:21:26 +01005802 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005803 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005804}
5805
5806
5807#if STATTIME > 0
5808/*
5809 * Display proxy statistics regularly. It is designed to be called from the
5810 * select_loop().
5811 */
5812int stats(void) {
5813 static int lines;
5814 static struct timeval nextevt;
5815 static struct timeval lastevt;
5816 static struct timeval starttime = {0,0};
5817 unsigned long totaltime, deltatime;
5818 int ret;
5819
willy tarreau750a4722005-12-17 13:21:24 +01005820 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005821 deltatime = (tv_diff(&lastevt, &now)?:1);
5822 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005823
willy tarreau9fe663a2005-12-17 13:02:59 +01005824 if (global.mode & MODE_STATS) {
5825 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005826 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005827 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5828 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005829 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005830 actconn, totalconn,
5831 stats_tsk_new, stats_tsk_good,
5832 stats_tsk_left, stats_tsk_right,
5833 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5834 }
5835 }
5836
5837 tv_delayfrom(&nextevt, &now, STATTIME);
5838
5839 lastevt=now;
5840 }
5841 ret = tv_remain(&now, &nextevt);
5842 return ret;
5843}
5844#endif
5845
5846
5847/*
5848 * this function enables proxies when there are enough free sessions,
5849 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005850 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005851 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005852 */
5853static int maintain_proxies(void) {
5854 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005855 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005856 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005857
5858 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005859 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005860
5861 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005862 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005863 while (p) {
5864 if (p->nbconn < p->maxconn) {
5865 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005866 for (l = p->listen; l != NULL; l = l->next) {
5867 FD_SET(l->fd, StaticReadEvent);
5868 }
willy tarreau0f7af912005-12-17 12:21:26 +01005869 p->state = PR_STRUN;
5870 }
5871 }
5872 else {
5873 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005874 for (l = p->listen; l != NULL; l = l->next) {
5875 FD_CLR(l->fd, StaticReadEvent);
5876 }
willy tarreau0f7af912005-12-17 12:21:26 +01005877 p->state = PR_STIDLE;
5878 }
5879 }
5880 p = p->next;
5881 }
5882 }
5883 else { /* block all proxies */
5884 while (p) {
5885 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005886 for (l = p->listen; l != NULL; l = l->next) {
5887 FD_CLR(l->fd, StaticReadEvent);
5888 }
willy tarreau0f7af912005-12-17 12:21:26 +01005889 p->state = PR_STIDLE;
5890 }
5891 p = p->next;
5892 }
5893 }
5894
willy tarreau5cbea6f2005-12-17 12:48:26 +01005895 if (stopping) {
5896 p = proxy;
5897 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005898 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005899 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005900 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005901 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005902 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005903 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005904
willy tarreaua41a8b42005-12-17 14:02:24 +01005905 for (l = p->listen; l != NULL; l = l->next) {
5906 fd_delete(l->fd);
5907 listeners--;
5908 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005909 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005910 }
5911 else {
5912 tleft = MINTIME(t, tleft);
5913 }
5914 }
5915 p = p->next;
5916 }
5917 }
5918 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005919}
5920
5921/*
5922 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01005923 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
5924 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01005925 */
5926static void soft_stop(void) {
5927 struct proxy *p;
5928
5929 stopping = 1;
5930 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005931 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005932 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01005933 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005934 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005935 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005936 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005937 }
willy tarreau0f7af912005-12-17 12:21:26 +01005938 p = p->next;
5939 }
5940}
5941
willy tarreaudbd3bef2006-01-20 19:35:18 +01005942static void pause_proxy(struct proxy *p) {
5943 struct listener *l;
5944 for (l = p->listen; l != NULL; l = l->next) {
5945 shutdown(l->fd, SHUT_RD);
5946 FD_CLR(l->fd, StaticReadEvent);
5947 p->state = PR_STPAUSED;
5948 }
5949}
5950
5951/*
5952 * This function temporarily disables listening so that another new instance
5953 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01005954 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01005955 * the proxy, or a SIGTTIN can be sent to listen again.
5956 */
5957static void pause_proxies(void) {
5958 struct proxy *p;
5959
5960 p = proxy;
5961 tv_now(&now); /* else, the old time before select will be used */
5962 while (p) {
5963 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
5964 Warning("Pausing proxy %s.\n", p->id);
5965 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
5966 pause_proxy(p);
5967 }
5968 p = p->next;
5969 }
5970}
5971
5972
5973/*
5974 * This function reactivates listening. This can be used after a call to
5975 * sig_pause(), for example when a new instance has failed starting up.
5976 * It is designed to be called upon reception of a SIGTTIN.
5977 */
5978static void listen_proxies(void) {
5979 struct proxy *p;
5980 struct listener *l;
5981
5982 p = proxy;
5983 tv_now(&now); /* else, the old time before select will be used */
5984 while (p) {
5985 if (p->state == PR_STPAUSED) {
5986 Warning("Enabling proxy %s.\n", p->id);
5987 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
5988
5989 for (l = p->listen; l != NULL; l = l->next) {
5990 if (listen(l->fd, p->maxconn) == 0) {
5991 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
5992 FD_SET(l->fd, StaticReadEvent);
5993 p->state = PR_STRUN;
5994 }
5995 else
5996 p->state = PR_STIDLE;
5997 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01005998 int port;
5999
6000 if (l->addr.ss_family == AF_INET6)
6001 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6002 else
6003 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6004
willy tarreaudbd3bef2006-01-20 19:35:18 +01006005 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006006 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006007 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006008 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006009 /* Another port might have been enabled. Let's stop everything. */
6010 pause_proxy(p);
6011 break;
6012 }
6013 }
6014 }
6015 p = p->next;
6016 }
6017}
6018
6019
willy tarreau0f7af912005-12-17 12:21:26 +01006020/*
6021 * upon SIGUSR1, let's have a soft stop.
6022 */
6023void sig_soft_stop(int sig) {
6024 soft_stop();
6025 signal(sig, SIG_IGN);
6026}
6027
willy tarreaudbd3bef2006-01-20 19:35:18 +01006028/*
6029 * upon SIGTTOU, we pause everything
6030 */
6031void sig_pause(int sig) {
6032 pause_proxies();
6033 signal(sig, sig_pause);
6034}
willy tarreau0f7af912005-12-17 12:21:26 +01006035
willy tarreau8337c6b2005-12-17 13:41:01 +01006036/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006037 * upon SIGTTIN, let's have a soft stop.
6038 */
6039void sig_listen(int sig) {
6040 listen_proxies();
6041 signal(sig, sig_listen);
6042}
6043
6044/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006045 * this function dumps every server's state when the process receives SIGHUP.
6046 */
6047void sig_dump_state(int sig) {
6048 struct proxy *p = proxy;
6049
6050 Warning("SIGHUP received, dumping servers states.\n");
6051 while (p) {
6052 struct server *s = p->srv;
6053
6054 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6055 while (s) {
6056 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006057 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
6058 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006059 }
6060 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006061 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
6062 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006063 }
6064 s = s->next;
6065 }
willy tarreaudd07e972005-12-18 00:48:48 +01006066
willy tarreau62084d42006-03-24 18:57:41 +01006067 if (p->srv_act == 0) {
6068 if (p->srv_bck) {
6069 Warning("SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6070 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6071 } else {
6072 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6073 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
6074 }
6075 }
willy tarreaudd07e972005-12-18 00:48:48 +01006076
willy tarreau8337c6b2005-12-17 13:41:01 +01006077 p = p->next;
6078 }
6079 signal(sig, sig_dump_state);
6080}
6081
willy tarreau0f7af912005-12-17 12:21:26 +01006082void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006083 struct task *t, *tnext;
6084 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006085
willy tarreau5cbea6f2005-12-17 12:48:26 +01006086 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6087 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6088 tnext = t->next;
6089 s = t->context;
6090 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6091 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6092 "req=%d, rep=%d, clifd=%d\n",
6093 s, tv_remain(&now, &t->expire),
6094 s->cli_state,
6095 s->srv_state,
6096 FD_ISSET(s->cli_fd, StaticReadEvent),
6097 FD_ISSET(s->cli_fd, StaticWriteEvent),
6098 FD_ISSET(s->srv_fd, StaticReadEvent),
6099 FD_ISSET(s->srv_fd, StaticWriteEvent),
6100 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6101 );
willy tarreau0f7af912005-12-17 12:21:26 +01006102 }
willy tarreau12350152005-12-18 01:03:27 +01006103}
6104
willy tarreau64a3cc32005-12-18 01:13:11 +01006105#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006106static void fast_stop(void)
6107{
6108 struct proxy *p;
6109 p = proxy;
6110 while (p) {
6111 p->grace = 0;
6112 p = p->next;
6113 }
6114 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006115}
6116
willy tarreau12350152005-12-18 01:03:27 +01006117void sig_int(int sig) {
6118 /* This would normally be a hard stop,
6119 but we want to be sure about deallocation,
6120 and so on, so we do a soft stop with
6121 0 GRACE time
6122 */
6123 fast_stop();
6124 /* If we are killed twice, we decide to die*/
6125 signal(sig, SIG_DFL);
6126}
6127
6128void sig_term(int sig) {
6129 /* This would normally be a hard stop,
6130 but we want to be sure about deallocation,
6131 and so on, so we do a soft stop with
6132 0 GRACE time
6133 */
6134 fast_stop();
6135 /* If we are killed twice, we decide to die*/
6136 signal(sig, SIG_DFL);
6137}
willy tarreau64a3cc32005-12-18 01:13:11 +01006138#endif
willy tarreau12350152005-12-18 01:03:27 +01006139
willy tarreauc1f47532005-12-18 01:08:26 +01006140/* returns the pointer to an error in the replacement string, or NULL if OK */
6141char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006142 struct hdr_exp *exp;
6143
willy tarreauc1f47532005-12-18 01:08:26 +01006144 if (replace != NULL) {
6145 char *err;
6146 err = check_replace_string(replace);
6147 if (err)
6148 return err;
6149 }
6150
willy tarreaue39cd132005-12-17 13:00:18 +01006151 while (*head != NULL)
6152 head = &(*head)->next;
6153
6154 exp = calloc(1, sizeof(struct hdr_exp));
6155
6156 exp->preg = preg;
6157 exp->replace = replace;
6158 exp->action = action;
6159 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006160
6161 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006162}
6163
willy tarreau9fe663a2005-12-17 13:02:59 +01006164
willy tarreau0f7af912005-12-17 12:21:26 +01006165/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006166 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006167 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006168int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006169
willy tarreau9fe663a2005-12-17 13:02:59 +01006170 if (!strcmp(args[0], "global")) { /* new section */
6171 /* no option, nothing special to do */
6172 return 0;
6173 }
6174 else if (!strcmp(args[0], "daemon")) {
6175 global.mode |= MODE_DAEMON;
6176 }
6177 else if (!strcmp(args[0], "debug")) {
6178 global.mode |= MODE_DEBUG;
6179 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006180 else if (!strcmp(args[0], "noepoll")) {
6181 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6182 }
6183 else if (!strcmp(args[0], "nopoll")) {
6184 cfg_polling_mechanism &= ~POLL_USE_POLL;
6185 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006186 else if (!strcmp(args[0], "quiet")) {
6187 global.mode |= MODE_QUIET;
6188 }
6189 else if (!strcmp(args[0], "stats")) {
6190 global.mode |= MODE_STATS;
6191 }
6192 else if (!strcmp(args[0], "uid")) {
6193 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006194 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006195 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006196 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006197 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006198 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006199 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006200 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006201 global.uid = atol(args[1]);
6202 }
6203 else if (!strcmp(args[0], "gid")) {
6204 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006205 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006206 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006207 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006208 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006209 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006210 return -1;
6211 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006212 global.gid = atol(args[1]);
6213 }
6214 else if (!strcmp(args[0], "nbproc")) {
6215 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006216 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006217 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006218 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006219 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006220 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006221 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006222 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006223 global.nbproc = atol(args[1]);
6224 }
6225 else if (!strcmp(args[0], "maxconn")) {
6226 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006227 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006228 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006229 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006230 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006231 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006232 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006233 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006234 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006235#ifdef SYSTEM_MAXCONN
6236 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6237 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);
6238 global.maxconn = DEFAULT_MAXCONN;
6239 }
6240#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006241 }
willy tarreaub1285d52005-12-18 01:20:14 +01006242 else if (!strcmp(args[0], "ulimit-n")) {
6243 if (global.rlimit_nofile != 0) {
6244 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6245 return 0;
6246 }
6247 if (*(args[1]) == 0) {
6248 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6249 return -1;
6250 }
6251 global.rlimit_nofile = atol(args[1]);
6252 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006253 else if (!strcmp(args[0], "chroot")) {
6254 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006255 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006256 return 0;
6257 }
6258 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006259 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006260 return -1;
6261 }
6262 global.chroot = strdup(args[1]);
6263 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006264 else if (!strcmp(args[0], "pidfile")) {
6265 if (global.pidfile != NULL) {
6266 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6267 return 0;
6268 }
6269 if (*(args[1]) == 0) {
6270 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6271 return -1;
6272 }
6273 global.pidfile = strdup(args[1]);
6274 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006275 else if (!strcmp(args[0], "log")) { /* syslog server address */
6276 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006277 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006278
6279 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006280 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006281 return -1;
6282 }
6283
6284 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6285 if (!strcmp(log_facilities[facility], args[2]))
6286 break;
6287
6288 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006289 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006290 exit(1);
6291 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006292
6293 level = 7; /* max syslog level = debug */
6294 if (*(args[3])) {
6295 while (level >= 0 && strcmp(log_levels[level], args[3]))
6296 level--;
6297 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006298 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006299 exit(1);
6300 }
6301 }
6302
willy tarreau9fe663a2005-12-17 13:02:59 +01006303 sa = str2sa(args[1]);
6304 if (!sa->sin_port)
6305 sa->sin_port = htons(SYSLOG_PORT);
6306
6307 if (global.logfac1 == -1) {
6308 global.logsrv1 = *sa;
6309 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006310 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006311 }
6312 else if (global.logfac2 == -1) {
6313 global.logsrv2 = *sa;
6314 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006315 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006316 }
6317 else {
6318 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6319 return -1;
6320 }
6321
6322 }
6323 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006324 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006325 return -1;
6326 }
6327 return 0;
6328}
6329
6330
willy tarreaua41a8b42005-12-17 14:02:24 +01006331void init_default_instance() {
6332 memset(&defproxy, 0, sizeof(defproxy));
6333 defproxy.mode = PR_MODE_TCP;
6334 defproxy.state = PR_STNEW;
6335 defproxy.maxconn = cfg_maxpconn;
6336 defproxy.conn_retries = CONN_RETRIES;
6337 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6338}
6339
willy tarreau9fe663a2005-12-17 13:02:59 +01006340/*
6341 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6342 */
6343int cfg_parse_listen(char *file, int linenum, char **args) {
6344 static struct proxy *curproxy = NULL;
6345 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006346 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006347 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006348
6349 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006350 if (!*args[1]) {
6351 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6352 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006353 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006354 return -1;
6355 }
6356
6357 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006358 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006359 return -1;
6360 }
6361 curproxy->next = proxy;
6362 proxy = curproxy;
6363 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006364
6365 /* parse the listener address if any */
6366 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006367 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006368 if (!curproxy->listen)
6369 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006370 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006371 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006372
willy tarreau9fe663a2005-12-17 13:02:59 +01006373 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006374 curproxy->state = defproxy.state;
6375 curproxy->maxconn = defproxy.maxconn;
6376 curproxy->conn_retries = defproxy.conn_retries;
6377 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006378
6379 if (defproxy.check_req)
6380 curproxy->check_req = strdup(defproxy.check_req);
6381 curproxy->check_len = defproxy.check_len;
6382
6383 if (defproxy.cookie_name)
6384 curproxy->cookie_name = strdup(defproxy.cookie_name);
6385 curproxy->cookie_len = defproxy.cookie_len;
6386
6387 if (defproxy.capture_name)
6388 curproxy->capture_name = strdup(defproxy.capture_name);
6389 curproxy->capture_namelen = defproxy.capture_namelen;
6390 curproxy->capture_len = defproxy.capture_len;
6391
6392 if (defproxy.errmsg.msg400)
6393 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6394 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6395
6396 if (defproxy.errmsg.msg403)
6397 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6398 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6399
6400 if (defproxy.errmsg.msg408)
6401 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6402 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6403
6404 if (defproxy.errmsg.msg500)
6405 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6406 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6407
6408 if (defproxy.errmsg.msg502)
6409 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6410 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6411
6412 if (defproxy.errmsg.msg503)
6413 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6414 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6415
6416 if (defproxy.errmsg.msg504)
6417 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6418 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6419
willy tarreaua41a8b42005-12-17 14:02:24 +01006420 curproxy->clitimeout = defproxy.clitimeout;
6421 curproxy->contimeout = defproxy.contimeout;
6422 curproxy->srvtimeout = defproxy.srvtimeout;
6423 curproxy->mode = defproxy.mode;
6424 curproxy->logfac1 = defproxy.logfac1;
6425 curproxy->logsrv1 = defproxy.logsrv1;
6426 curproxy->loglev1 = defproxy.loglev1;
6427 curproxy->logfac2 = defproxy.logfac2;
6428 curproxy->logsrv2 = defproxy.logsrv2;
6429 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006430 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006431 curproxy->grace = defproxy.grace;
6432 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006433 curproxy->mon_net = defproxy.mon_net;
6434 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006435 return 0;
6436 }
6437 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006438 /* some variables may have already been initialized earlier */
6439 if (defproxy.check_req) free(defproxy.check_req);
6440 if (defproxy.cookie_name) free(defproxy.cookie_name);
6441 if (defproxy.capture_name) free(defproxy.capture_name);
6442 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6443 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6444 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6445 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6446 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6447 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6448 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6449
6450 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006451 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006452 return 0;
6453 }
6454 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006455 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006456 return -1;
6457 }
6458
willy tarreaua41a8b42005-12-17 14:02:24 +01006459 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6460 if (curproxy == &defproxy) {
6461 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6462 return -1;
6463 }
6464
6465 if (strchr(args[1], ':') == NULL) {
6466 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6467 file, linenum, args[0]);
6468 return -1;
6469 }
6470 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006471 if (!curproxy->listen)
6472 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006473 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006474 return 0;
6475 }
willy tarreaub1285d52005-12-18 01:20:14 +01006476 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6477 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6478 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6479 file, linenum, args[0]);
6480 return -1;
6481 }
6482 /* flush useless bits */
6483 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6484 return 0;
6485 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006486 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006487 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6488 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6489 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6490 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006491 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006492 return -1;
6493 }
6494 }
6495 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006496 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006497 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006498 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6499 curproxy->state = PR_STNEW;
6500 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006501 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6502 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006503// if (curproxy == &defproxy) {
6504// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6505// return -1;
6506// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006507
willy tarreau9fe663a2005-12-17 13:02:59 +01006508 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006509// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6510// file, linenum);
6511// return 0;
6512 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006513 }
6514
6515 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006516 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6517 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006518 return -1;
6519 }
6520 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006521 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006522
6523 cur_arg = 2;
6524 while (*(args[cur_arg])) {
6525 if (!strcmp(args[cur_arg], "rewrite")) {
6526 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006527 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006528 else if (!strcmp(args[cur_arg], "indirect")) {
6529 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006530 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006531 else if (!strcmp(args[cur_arg], "insert")) {
6532 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006533 }
willy tarreau240afa62005-12-17 13:14:35 +01006534 else if (!strcmp(args[cur_arg], "nocache")) {
6535 curproxy->options |= PR_O_COOK_NOC;
6536 }
willy tarreaucd878942005-12-17 13:27:43 +01006537 else if (!strcmp(args[cur_arg], "postonly")) {
6538 curproxy->options |= PR_O_COOK_POST;
6539 }
willy tarreau0174f312005-12-18 01:02:42 +01006540 else if (!strcmp(args[cur_arg], "prefix")) {
6541 curproxy->options |= PR_O_COOK_PFX;
6542 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006543 else {
willy tarreau0174f312005-12-18 01:02:42 +01006544 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006545 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006546 return -1;
6547 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006548 cur_arg++;
6549 }
willy tarreau0174f312005-12-18 01:02:42 +01006550 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6551 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6552 file, linenum);
6553 return -1;
6554 }
6555
6556 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6557 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006558 file, linenum);
6559 return -1;
6560 }
willy tarreau12350152005-12-18 01:03:27 +01006561 }/* end else if (!strcmp(args[0], "cookie")) */
6562 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6563// if (curproxy == &defproxy) {
6564// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6565// return -1;
6566// }
6567
6568 if (curproxy->appsession_name != NULL) {
6569// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6570// file, linenum);
6571// return 0;
6572 free(curproxy->appsession_name);
6573 }
6574
6575 if (*(args[5]) == 0) {
6576 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6577 file, linenum, args[0]);
6578 return -1;
6579 }
6580 have_appsession = 1;
6581 curproxy->appsession_name = strdup(args[1]);
6582 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6583 curproxy->appsession_len = atoi(args[3]);
6584 curproxy->appsession_timeout = atoi(args[5]);
6585 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6586 if (rc) {
6587 Alert("Error Init Appsession Hashtable.\n");
6588 return -1;
6589 }
6590 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006591 else if (!strcmp(args[0], "capture")) {
6592 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6593 // if (curproxy == &defproxy) {
6594 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6595 // return -1;
6596 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006597
willy tarreau4302f492005-12-18 01:00:37 +01006598 if (curproxy->capture_name != NULL) {
6599 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6600 // file, linenum, args[0]);
6601 // return 0;
6602 free(curproxy->capture_name);
6603 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006604
willy tarreau4302f492005-12-18 01:00:37 +01006605 if (*(args[4]) == 0) {
6606 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6607 file, linenum, args[0]);
6608 return -1;
6609 }
6610 curproxy->capture_name = strdup(args[2]);
6611 curproxy->capture_namelen = strlen(curproxy->capture_name);
6612 curproxy->capture_len = atol(args[4]);
6613 if (curproxy->capture_len >= CAPTURE_LEN) {
6614 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6615 file, linenum, CAPTURE_LEN - 1);
6616 curproxy->capture_len = CAPTURE_LEN - 1;
6617 }
6618 curproxy->to_log |= LW_COOKIE;
6619 }
6620 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6621 struct cap_hdr *hdr;
6622
6623 if (curproxy == &defproxy) {
6624 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6625 return -1;
6626 }
6627
6628 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6629 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6630 file, linenum, args[0], args[1]);
6631 return -1;
6632 }
6633
6634 hdr = calloc(sizeof(struct cap_hdr), 1);
6635 hdr->next = curproxy->req_cap;
6636 hdr->name = strdup(args[3]);
6637 hdr->namelen = strlen(args[3]);
6638 hdr->len = atol(args[5]);
6639 hdr->index = curproxy->nb_req_cap++;
6640 curproxy->req_cap = hdr;
6641 curproxy->to_log |= LW_REQHDR;
6642 }
6643 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6644 struct cap_hdr *hdr;
6645
6646 if (curproxy == &defproxy) {
6647 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6648 return -1;
6649 }
6650
6651 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6652 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6653 file, linenum, args[0], args[1]);
6654 return -1;
6655 }
6656 hdr = calloc(sizeof(struct cap_hdr), 1);
6657 hdr->next = curproxy->rsp_cap;
6658 hdr->name = strdup(args[3]);
6659 hdr->namelen = strlen(args[3]);
6660 hdr->len = atol(args[5]);
6661 hdr->index = curproxy->nb_rsp_cap++;
6662 curproxy->rsp_cap = hdr;
6663 curproxy->to_log |= LW_RSPHDR;
6664 }
6665 else {
6666 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006667 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006668 return -1;
6669 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006670 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006671 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006672 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006673 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006674 return 0;
6675 }
6676 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006677 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6678 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006679 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006680 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006681 curproxy->contimeout = atol(args[1]);
6682 }
6683 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006684 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006685 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6686 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006687 return 0;
6688 }
6689 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006690 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6691 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006692 return -1;
6693 }
6694 curproxy->clitimeout = atol(args[1]);
6695 }
6696 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006697 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006698 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006699 return 0;
6700 }
6701 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006702 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6703 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006704 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006705 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006706 curproxy->srvtimeout = atol(args[1]);
6707 }
6708 else if (!strcmp(args[0], "retries")) { /* connection retries */
6709 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006710 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6711 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006712 return -1;
6713 }
6714 curproxy->conn_retries = atol(args[1]);
6715 }
6716 else if (!strcmp(args[0], "option")) {
6717 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006718 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006719 return -1;
6720 }
6721 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006722 /* enable reconnections to dispatch */
6723 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006724#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006725 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006726 /* enable transparent proxy connections */
6727 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006728#endif
6729 else if (!strcmp(args[1], "keepalive"))
6730 /* enable keep-alive */
6731 curproxy->options |= PR_O_KEEPALIVE;
6732 else if (!strcmp(args[1], "forwardfor"))
6733 /* insert x-forwarded-for field */
6734 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006735 else if (!strcmp(args[1], "logasap"))
6736 /* log as soon as possible, without waiting for the session to complete */
6737 curproxy->options |= PR_O_LOGASAP;
6738 else if (!strcmp(args[1], "httpclose"))
6739 /* force connection: close in both directions in HTTP mode */
6740 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006741 else if (!strcmp(args[1], "forceclose"))
6742 /* force connection: close in both directions in HTTP mode and enforce end of session */
6743 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006744 else if (!strcmp(args[1], "checkcache"))
6745 /* require examination of cacheability of the 'set-cookie' field */
6746 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006747 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006748 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006749 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006750 else if (!strcmp(args[1], "tcplog"))
6751 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006752 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006753 else if (!strcmp(args[1], "dontlognull")) {
6754 /* don't log empty requests */
6755 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006756 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006757 else if (!strcmp(args[1], "tcpka")) {
6758 /* enable TCP keep-alives on client and server sessions */
6759 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6760 }
6761 else if (!strcmp(args[1], "clitcpka")) {
6762 /* enable TCP keep-alives on client sessions */
6763 curproxy->options |= PR_O_TCP_CLI_KA;
6764 }
6765 else if (!strcmp(args[1], "srvtcpka")) {
6766 /* enable TCP keep-alives on server sessions */
6767 curproxy->options |= PR_O_TCP_SRV_KA;
6768 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006769 else if (!strcmp(args[1], "allbackups")) {
6770 /* Use all backup servers simultaneously */
6771 curproxy->options |= PR_O_USE_ALL_BK;
6772 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006773 else if (!strcmp(args[1], "httpchk")) {
6774 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006775 if (curproxy->check_req != NULL) {
6776 free(curproxy->check_req);
6777 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006778 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006779 if (!*args[2]) { /* no argument */
6780 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6781 curproxy->check_len = strlen(DEF_CHECK_REQ);
6782 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006783 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6784 curproxy->check_req = (char *)malloc(reqlen);
6785 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6786 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006787 } else { /* more arguments : METHOD URI [HTTP_VER] */
6788 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6789 if (*args[4])
6790 reqlen += strlen(args[4]);
6791 else
6792 reqlen += strlen("HTTP/1.0");
6793
6794 curproxy->check_req = (char *)malloc(reqlen);
6795 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6796 "%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 +01006797 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006798 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006799 else if (!strcmp(args[1], "persist")) {
6800 /* persist on using the server specified by the cookie, even when it's down */
6801 curproxy->options |= PR_O_PERSIST;
6802 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006803 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006804 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006805 return -1;
6806 }
6807 return 0;
6808 }
6809 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6810 /* enable reconnections to dispatch */
6811 curproxy->options |= PR_O_REDISP;
6812 }
willy tarreaua1598082005-12-17 13:08:06 +01006813#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006814 else if (!strcmp(args[0], "transparent")) {
6815 /* enable transparent proxy connections */
6816 curproxy->options |= PR_O_TRANSP;
6817 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006818#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006819 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6820 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006821 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006822 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006823 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006824 curproxy->maxconn = atol(args[1]);
6825 }
6826 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6827 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006828 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006829 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006830 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006831 curproxy->grace = atol(args[1]);
6832 }
6833 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006834 if (curproxy == &defproxy) {
6835 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6836 return -1;
6837 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006838 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006839 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006840 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006841 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006842 curproxy->dispatch_addr = *str2sa(args[1]);
6843 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006844 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006845 if (*(args[1])) {
6846 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006847 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006848 }
6849 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006850 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006851 return -1;
6852 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006853 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006854 else /* if no option is set, use round-robin by default */
6855 curproxy->options |= PR_O_BALANCE_RR;
6856 }
6857 else if (!strcmp(args[0], "server")) { /* server address */
6858 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006859 char *rport;
6860 char *raddr;
6861 short realport;
6862 int do_check;
6863
6864 if (curproxy == &defproxy) {
6865 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6866 return -1;
6867 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006868
willy tarreaua41a8b42005-12-17 14:02:24 +01006869 if (!*args[2]) {
6870 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006871 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006872 return -1;
6873 }
6874 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6875 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6876 return -1;
6877 }
willy tarreau0174f312005-12-18 01:02:42 +01006878
6879 if (curproxy->srv == NULL)
6880 curproxy->srv = newsrv;
6881 else
6882 curproxy->cursrv->next = newsrv;
6883 curproxy->cursrv = newsrv;
6884
6885 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006886 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006887
6888 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006889 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006890 newsrv->id = strdup(args[1]);
6891
6892 /* several ways to check the port component :
6893 * - IP => port=+0, relative
6894 * - IP: => port=+0, relative
6895 * - IP:N => port=N, absolute
6896 * - IP:+N => port=+N, relative
6897 * - IP:-N => port=-N, relative
6898 */
6899 raddr = strdup(args[2]);
6900 rport = strchr(raddr, ':');
6901 if (rport) {
6902 *rport++ = 0;
6903 realport = atol(rport);
6904 if (!isdigit((int)*rport))
6905 newsrv->state |= SRV_MAPPORTS;
6906 } else {
6907 realport = 0;
6908 newsrv->state |= SRV_MAPPORTS;
6909 }
6910
6911 newsrv->addr = *str2sa(raddr);
6912 newsrv->addr.sin_port = htons(realport);
6913 free(raddr);
6914
willy tarreau9fe663a2005-12-17 13:02:59 +01006915 newsrv->curfd = -1; /* no health-check in progress */
6916 newsrv->inter = DEF_CHKINTR;
6917 newsrv->rise = DEF_RISETIME;
6918 newsrv->fall = DEF_FALLTIME;
6919 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6920 cur_arg = 3;
6921 while (*args[cur_arg]) {
6922 if (!strcmp(args[cur_arg], "cookie")) {
6923 newsrv->cookie = strdup(args[cur_arg + 1]);
6924 newsrv->cklen = strlen(args[cur_arg + 1]);
6925 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006926 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006927 else if (!strcmp(args[cur_arg], "rise")) {
6928 newsrv->rise = atol(args[cur_arg + 1]);
6929 newsrv->health = newsrv->rise;
6930 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006931 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006932 else if (!strcmp(args[cur_arg], "fall")) {
6933 newsrv->fall = atol(args[cur_arg + 1]);
6934 cur_arg += 2;
6935 }
6936 else if (!strcmp(args[cur_arg], "inter")) {
6937 newsrv->inter = atol(args[cur_arg + 1]);
6938 cur_arg += 2;
6939 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006940 else if (!strcmp(args[cur_arg], "port")) {
6941 newsrv->check_port = atol(args[cur_arg + 1]);
6942 cur_arg += 2;
6943 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006944 else if (!strcmp(args[cur_arg], "backup")) {
6945 newsrv->state |= SRV_BACKUP;
6946 cur_arg ++;
6947 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006948 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01006949 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006950 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006951 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006952 }
willy tarreau0174f312005-12-18 01:02:42 +01006953 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6954 if (!*args[cur_arg + 1]) {
6955 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6956 file, linenum, "source");
6957 return -1;
6958 }
6959 newsrv->state |= SRV_BIND_SRC;
6960 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6961 cur_arg += 2;
6962 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 else {
willy tarreau0174f312005-12-18 01:02:42 +01006964 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port' and 'source'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01006965 file, linenum, newsrv->id);
6966 return -1;
6967 }
6968 }
6969
6970 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006971 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6972 newsrv->check_port = realport; /* by default */
6973 if (!newsrv->check_port) {
6974 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 +01006975 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006976 return -1;
6977 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006978 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006979 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006980
willy tarreau62084d42006-03-24 18:57:41 +01006981 if (newsrv->state & SRV_BACKUP)
6982 curproxy->srv_bck++;
6983 else
6984 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01006985 }
6986 else if (!strcmp(args[0], "log")) { /* syslog server address */
6987 struct sockaddr_in *sa;
6988 int facility;
6989
6990 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6991 curproxy->logfac1 = global.logfac1;
6992 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006993 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006994 curproxy->logfac2 = global.logfac2;
6995 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006996 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006997 }
6998 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006999 int level;
7000
willy tarreau0f7af912005-12-17 12:21:26 +01007001 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7002 if (!strcmp(log_facilities[facility], args[2]))
7003 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007004
willy tarreau0f7af912005-12-17 12:21:26 +01007005 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007006 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007007 exit(1);
7008 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007009
willy tarreau8337c6b2005-12-17 13:41:01 +01007010 level = 7; /* max syslog level = debug */
7011 if (*(args[3])) {
7012 while (level >= 0 && strcmp(log_levels[level], args[3]))
7013 level--;
7014 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007015 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007016 exit(1);
7017 }
7018 }
7019
willy tarreau0f7af912005-12-17 12:21:26 +01007020 sa = str2sa(args[1]);
7021 if (!sa->sin_port)
7022 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007023
willy tarreau0f7af912005-12-17 12:21:26 +01007024 if (curproxy->logfac1 == -1) {
7025 curproxy->logsrv1 = *sa;
7026 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007027 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007028 }
7029 else if (curproxy->logfac2 == -1) {
7030 curproxy->logsrv2 = *sa;
7031 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007032 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007033 }
7034 else {
7035 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007036 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007037 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007038 }
7039 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007040 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007041 file, linenum);
7042 return -1;
7043 }
7044 }
willy tarreaua1598082005-12-17 13:08:06 +01007045 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007046 if (!*args[1]) {
7047 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007048 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007049 return -1;
7050 }
7051
7052 curproxy->source_addr = *str2sa(args[1]);
7053 curproxy->options |= PR_O_BIND_SRC;
7054 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007055 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7056 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007057 if (curproxy == &defproxy) {
7058 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7059 return -1;
7060 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007061
7062 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007063 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7064 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007065 return -1;
7066 }
7067
7068 preg = calloc(1, sizeof(regex_t));
7069 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007070 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007071 return -1;
7072 }
7073
willy tarreauc1f47532005-12-18 01:08:26 +01007074 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7075 if (err) {
7076 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7077 file, linenum, *err);
7078 return -1;
7079 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007080 }
7081 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7082 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007083 if (curproxy == &defproxy) {
7084 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7085 return -1;
7086 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007087
7088 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007089 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007090 return -1;
7091 }
7092
7093 preg = calloc(1, sizeof(regex_t));
7094 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007095 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007096 return -1;
7097 }
7098
7099 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7100 }
7101 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7102 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007103 if (curproxy == &defproxy) {
7104 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7105 return -1;
7106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007107
7108 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007109 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007110 return -1;
7111 }
7112
7113 preg = calloc(1, sizeof(regex_t));
7114 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007115 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007116 return -1;
7117 }
7118
7119 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7120 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007121 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7122 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007123 if (curproxy == &defproxy) {
7124 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7125 return -1;
7126 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007127
7128 if (*(args[1]) == 0) {
7129 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7130 return -1;
7131 }
7132
7133 preg = calloc(1, sizeof(regex_t));
7134 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7135 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7136 return -1;
7137 }
7138
7139 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7140 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007141 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7142 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007143 if (curproxy == &defproxy) {
7144 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7145 return -1;
7146 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007147
7148 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007149 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007150 return -1;
7151 }
7152
7153 preg = calloc(1, sizeof(regex_t));
7154 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007155 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007156 return -1;
7157 }
7158
7159 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7160 }
7161 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7162 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007163 if (curproxy == &defproxy) {
7164 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7165 return -1;
7166 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007167
7168 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007169 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7170 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007171 return -1;
7172 }
7173
7174 preg = calloc(1, sizeof(regex_t));
7175 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007176 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007177 return -1;
7178 }
7179
willy tarreauc1f47532005-12-18 01:08:26 +01007180 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7181 if (err) {
7182 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7183 file, linenum, *err);
7184 return -1;
7185 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007186 }
7187 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7188 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007189 if (curproxy == &defproxy) {
7190 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7191 return -1;
7192 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007193
7194 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007195 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007196 return -1;
7197 }
7198
7199 preg = calloc(1, sizeof(regex_t));
7200 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007201 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007202 return -1;
7203 }
7204
7205 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7206 }
7207 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7208 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007209 if (curproxy == &defproxy) {
7210 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7211 return -1;
7212 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007213
7214 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007215 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007216 return -1;
7217 }
7218
7219 preg = calloc(1, sizeof(regex_t));
7220 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007221 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007222 return -1;
7223 }
7224
7225 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7226 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007227 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7228 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007229 if (curproxy == &defproxy) {
7230 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7231 return -1;
7232 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007233
7234 if (*(args[1]) == 0) {
7235 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7236 return -1;
7237 }
7238
7239 preg = calloc(1, sizeof(regex_t));
7240 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7241 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7242 return -1;
7243 }
7244
7245 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7246 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007247 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7248 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007249 if (curproxy == &defproxy) {
7250 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7251 return -1;
7252 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007253
7254 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007255 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007256 return -1;
7257 }
7258
7259 preg = calloc(1, sizeof(regex_t));
7260 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007261 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007262 return -1;
7263 }
7264
7265 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7266 }
7267 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007268 if (curproxy == &defproxy) {
7269 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7270 return -1;
7271 }
7272
willy tarreau9fe663a2005-12-17 13:02:59 +01007273 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007274 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007275 return 0;
7276 }
7277
7278 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007279 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007280 return -1;
7281 }
7282
willy tarreau4302f492005-12-18 01:00:37 +01007283 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7284 }
7285 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7286 regex_t *preg;
7287
7288 if (*(args[1]) == 0 || *(args[2]) == 0) {
7289 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7290 file, linenum, args[0]);
7291 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007292 }
willy tarreau4302f492005-12-18 01:00:37 +01007293
7294 preg = calloc(1, sizeof(regex_t));
7295 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7296 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7297 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007298 }
willy tarreau4302f492005-12-18 01:00:37 +01007299
willy tarreauc1f47532005-12-18 01:08:26 +01007300 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7301 if (err) {
7302 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7303 file, linenum, *err);
7304 return -1;
7305 }
willy tarreau4302f492005-12-18 01:00:37 +01007306 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007307 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7308 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007309 if (curproxy == &defproxy) {
7310 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7311 return -1;
7312 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007313
7314 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007315 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007316 return -1;
7317 }
willy tarreaue39cd132005-12-17 13:00:18 +01007318
willy tarreau9fe663a2005-12-17 13:02:59 +01007319 preg = calloc(1, sizeof(regex_t));
7320 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007321 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007322 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007323 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007324
willy tarreauc1f47532005-12-18 01:08:26 +01007325 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7326 if (err) {
7327 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7328 file, linenum, *err);
7329 return -1;
7330 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007331 }
willy tarreau982249e2005-12-18 00:57:06 +01007332 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7333 regex_t *preg;
7334 if (curproxy == &defproxy) {
7335 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7336 return -1;
7337 }
7338
7339 if (*(args[1]) == 0) {
7340 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7341 return -1;
7342 }
7343
7344 preg = calloc(1, sizeof(regex_t));
7345 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7346 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7347 return -1;
7348 }
7349
willy tarreauc1f47532005-12-18 01:08:26 +01007350 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7351 if (err) {
7352 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7353 file, linenum, *err);
7354 return -1;
7355 }
willy tarreau982249e2005-12-18 00:57:06 +01007356 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007357 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007358 regex_t *preg;
7359 if (curproxy == &defproxy) {
7360 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7361 return -1;
7362 }
willy tarreaue39cd132005-12-17 13:00:18 +01007363
willy tarreaua41a8b42005-12-17 14:02:24 +01007364 if (*(args[1]) == 0 || *(args[2]) == 0) {
7365 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7366 file, linenum, args[0]);
7367 return -1;
7368 }
willy tarreaue39cd132005-12-17 13:00:18 +01007369
willy tarreaua41a8b42005-12-17 14:02:24 +01007370 preg = calloc(1, sizeof(regex_t));
7371 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7372 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7373 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007374 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007375
willy tarreauc1f47532005-12-18 01:08:26 +01007376 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7377 if (err) {
7378 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7379 file, linenum, *err);
7380 return -1;
7381 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007382 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007383 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7384 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007385 if (curproxy == &defproxy) {
7386 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7387 return -1;
7388 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007389
7390 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007391 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007392 return -1;
7393 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007394
willy tarreau9fe663a2005-12-17 13:02:59 +01007395 preg = calloc(1, sizeof(regex_t));
7396 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007397 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007398 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007399 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007400
willy tarreauc1f47532005-12-18 01:08:26 +01007401 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7402 if (err) {
7403 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7404 file, linenum, *err);
7405 return -1;
7406 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007407 }
willy tarreau982249e2005-12-18 00:57:06 +01007408 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7409 regex_t *preg;
7410 if (curproxy == &defproxy) {
7411 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7412 return -1;
7413 }
7414
7415 if (*(args[1]) == 0) {
7416 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7417 return -1;
7418 }
7419
7420 preg = calloc(1, sizeof(regex_t));
7421 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7422 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7423 return -1;
7424 }
7425
willy tarreauc1f47532005-12-18 01:08:26 +01007426 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7427 if (err) {
7428 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7429 file, linenum, *err);
7430 return -1;
7431 }
willy tarreau982249e2005-12-18 00:57:06 +01007432 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007433 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007434 if (curproxy == &defproxy) {
7435 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7436 return -1;
7437 }
7438
willy tarreau9fe663a2005-12-17 13:02:59 +01007439 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007440 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007441 return 0;
7442 }
7443
7444 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007445 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007446 return -1;
7447 }
7448
7449 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7450 }
willy tarreauc1f47532005-12-18 01:08:26 +01007451 else if (!strcmp(args[0], "errorloc") ||
7452 !strcmp(args[0], "errorloc302") ||
7453 !strcmp(args[0], "errorloc303")) { /* error location */
7454 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007455 char *err;
7456
willy tarreaueedaa9f2005-12-17 14:08:03 +01007457 // if (curproxy == &defproxy) {
7458 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7459 // return -1;
7460 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007461
willy tarreau8337c6b2005-12-17 13:41:01 +01007462 if (*(args[2]) == 0) {
7463 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7464 return -1;
7465 }
7466
7467 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007468 if (!strcmp(args[0], "errorloc303")) {
7469 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7470 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7471 } else {
7472 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7473 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7474 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007475
7476 if (errnum == 400) {
7477 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007478 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007479 free(curproxy->errmsg.msg400);
7480 }
7481 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007482 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007483 }
7484 else if (errnum == 403) {
7485 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007486 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007487 free(curproxy->errmsg.msg403);
7488 }
7489 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007490 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007491 }
7492 else if (errnum == 408) {
7493 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007494 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007495 free(curproxy->errmsg.msg408);
7496 }
7497 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007498 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007499 }
7500 else if (errnum == 500) {
7501 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007502 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007503 free(curproxy->errmsg.msg500);
7504 }
7505 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007506 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007507 }
7508 else if (errnum == 502) {
7509 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007510 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007511 free(curproxy->errmsg.msg502);
7512 }
7513 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007514 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007515 }
7516 else if (errnum == 503) {
7517 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007518 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007519 free(curproxy->errmsg.msg503);
7520 }
7521 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007522 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007523 }
7524 else if (errnum == 504) {
7525 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007526 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007527 free(curproxy->errmsg.msg504);
7528 }
7529 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007530 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007531 }
7532 else {
7533 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7534 free(err);
7535 }
7536 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007537 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007538 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007539 return -1;
7540 }
7541 return 0;
7542}
willy tarreaue39cd132005-12-17 13:00:18 +01007543
willy tarreau5cbea6f2005-12-17 12:48:26 +01007544
willy tarreau9fe663a2005-12-17 13:02:59 +01007545/*
7546 * This function reads and parses the configuration file given in the argument.
7547 * returns 0 if OK, -1 if error.
7548 */
7549int readcfgfile(char *file) {
7550 char thisline[256];
7551 char *line;
7552 FILE *f;
7553 int linenum = 0;
7554 char *end;
7555 char *args[MAX_LINE_ARGS];
7556 int arg;
7557 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007558 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007559 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007560
willy tarreau9fe663a2005-12-17 13:02:59 +01007561 struct proxy *curproxy = NULL;
7562 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007563
willy tarreau9fe663a2005-12-17 13:02:59 +01007564 if ((f=fopen(file,"r")) == NULL)
7565 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007566
willy tarreaueedaa9f2005-12-17 14:08:03 +01007567 init_default_instance();
7568
willy tarreau9fe663a2005-12-17 13:02:59 +01007569 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7570 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007571
willy tarreau9fe663a2005-12-17 13:02:59 +01007572 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007573
willy tarreau9fe663a2005-12-17 13:02:59 +01007574 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007575 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007576 line++;
7577
7578 arg = 0;
7579 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007580
willy tarreau9fe663a2005-12-17 13:02:59 +01007581 while (*line && arg < MAX_LINE_ARGS) {
7582 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7583 * C equivalent value. Other combinations left unchanged (eg: \1).
7584 */
7585 if (*line == '\\') {
7586 int skip = 0;
7587 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7588 *line = line[1];
7589 skip = 1;
7590 }
7591 else if (line[1] == 'r') {
7592 *line = '\r';
7593 skip = 1;
7594 }
7595 else if (line[1] == 'n') {
7596 *line = '\n';
7597 skip = 1;
7598 }
7599 else if (line[1] == 't') {
7600 *line = '\t';
7601 skip = 1;
7602 }
willy tarreauc1f47532005-12-18 01:08:26 +01007603 else if (line[1] == 'x') {
7604 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7605 unsigned char hex1, hex2;
7606 hex1 = toupper(line[2]) - '0';
7607 hex2 = toupper(line[3]) - '0';
7608 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7609 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7610 *line = (hex1<<4) + hex2;
7611 skip = 3;
7612 }
7613 else {
7614 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7615 return -1;
7616 }
7617 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007618 if (skip) {
7619 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7620 end -= skip;
7621 }
7622 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007623 }
willy tarreaua1598082005-12-17 13:08:06 +01007624 else if (*line == '#' || *line == '\n' || *line == '\r') {
7625 /* end of string, end of loop */
7626 *line = 0;
7627 break;
7628 }
willy tarreauc29948c2005-12-17 13:10:27 +01007629 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007630 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007631 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007632 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007633 line++;
7634 args[++arg] = line;
7635 }
7636 else {
7637 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007638 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007639 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007640
willy tarreau9fe663a2005-12-17 13:02:59 +01007641 /* empty line */
7642 if (!**args)
7643 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007644
willy tarreau9fe663a2005-12-17 13:02:59 +01007645 /* zero out remaining args */
7646 while (++arg < MAX_LINE_ARGS) {
7647 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007648 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007649
willy tarreaua41a8b42005-12-17 14:02:24 +01007650 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007651 confsect = CFG_LISTEN;
7652 else if (!strcmp(args[0], "global")) /* global config */
7653 confsect = CFG_GLOBAL;
7654 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007655
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 switch (confsect) {
7657 case CFG_LISTEN:
7658 if (cfg_parse_listen(file, linenum, args) < 0)
7659 return -1;
7660 break;
7661 case CFG_GLOBAL:
7662 if (cfg_parse_global(file, linenum, args) < 0)
7663 return -1;
7664 break;
7665 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007666 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007667 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007668 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007669
7670
willy tarreau0f7af912005-12-17 12:21:26 +01007671 }
7672 fclose(f);
7673
7674 /*
7675 * Now, check for the integrity of all that we have collected.
7676 */
7677
Willy TARREAU3759f982006-03-01 22:44:17 +01007678 /* will be needed further to delay some tasks */
7679 tv_now(&now);
7680
willy tarreau0f7af912005-12-17 12:21:26 +01007681 if ((curproxy = proxy) == NULL) {
7682 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7683 file);
7684 return -1;
7685 }
7686
7687 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007688 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007689 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007690 curproxy = curproxy->next;
7691 continue;
7692 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007693
7694 if (curproxy->listen == NULL) {
7695 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);
7696 cfgerr++;
7697 }
7698 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007699 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007700 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007701 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7702 file, curproxy->id);
7703 cfgerr++;
7704 }
7705 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7706 if (curproxy->options & PR_O_TRANSP) {
7707 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7708 file, curproxy->id);
7709 cfgerr++;
7710 }
7711 else if (curproxy->srv == NULL) {
7712 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7713 file, curproxy->id);
7714 cfgerr++;
7715 }
willy tarreaua1598082005-12-17 13:08:06 +01007716 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007717 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7718 file, curproxy->id);
7719 }
7720 }
7721 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007722 if (curproxy->cookie_name != NULL) {
7723 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7724 file, curproxy->id);
7725 }
7726 if ((newsrv = curproxy->srv) != NULL) {
7727 Warning("parsing %s : servers will be ignored for listener %s.\n",
7728 file, curproxy->id);
7729 }
willy tarreaue39cd132005-12-17 13:00:18 +01007730 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007731 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7732 file, curproxy->id);
7733 }
willy tarreaue39cd132005-12-17 13:00:18 +01007734 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007735 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7736 file, curproxy->id);
7737 }
7738 }
7739 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7740 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7741 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7742 file, curproxy->id);
7743 cfgerr++;
7744 }
7745 else {
7746 while (newsrv != NULL) {
7747 /* nothing to check for now */
7748 newsrv = newsrv->next;
7749 }
7750 }
7751 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007752
7753 if (curproxy->options & PR_O_LOGASAP)
7754 curproxy->to_log &= ~LW_BYTES;
7755
willy tarreau8337c6b2005-12-17 13:41:01 +01007756 if (curproxy->errmsg.msg400 == NULL) {
7757 curproxy->errmsg.msg400 = (char *)HTTP_400;
7758 curproxy->errmsg.len400 = strlen(HTTP_400);
7759 }
7760 if (curproxy->errmsg.msg403 == NULL) {
7761 curproxy->errmsg.msg403 = (char *)HTTP_403;
7762 curproxy->errmsg.len403 = strlen(HTTP_403);
7763 }
7764 if (curproxy->errmsg.msg408 == NULL) {
7765 curproxy->errmsg.msg408 = (char *)HTTP_408;
7766 curproxy->errmsg.len408 = strlen(HTTP_408);
7767 }
7768 if (curproxy->errmsg.msg500 == NULL) {
7769 curproxy->errmsg.msg500 = (char *)HTTP_500;
7770 curproxy->errmsg.len500 = strlen(HTTP_500);
7771 }
7772 if (curproxy->errmsg.msg502 == NULL) {
7773 curproxy->errmsg.msg502 = (char *)HTTP_502;
7774 curproxy->errmsg.len502 = strlen(HTTP_502);
7775 }
7776 if (curproxy->errmsg.msg503 == NULL) {
7777 curproxy->errmsg.msg503 = (char *)HTTP_503;
7778 curproxy->errmsg.len503 = strlen(HTTP_503);
7779 }
7780 if (curproxy->errmsg.msg504 == NULL) {
7781 curproxy->errmsg.msg504 = (char *)HTTP_504;
7782 curproxy->errmsg.len504 = strlen(HTTP_504);
7783 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007784
7785 /* now we'll start this proxy's health checks if any */
7786 /* 1- count the checkers to run simultaneously */
7787 nbchk = 0;
7788 mininter = 0;
7789 newsrv = curproxy->srv;
7790 while (newsrv != NULL) {
7791 if (newsrv->state & SRV_CHECKED) {
7792 if (!mininter || mininter > newsrv->inter)
7793 mininter = newsrv->inter;
7794 nbchk++;
7795 }
7796 newsrv = newsrv->next;
7797 }
7798
7799 /* 2- start them as far as possible from each others while respecting
7800 * their own intervals. For this, we will start them after their own
7801 * interval added to the min interval divided by the number of servers,
7802 * weighted by the server's position in the list.
7803 */
7804 if (nbchk > 0) {
7805 struct task *t;
7806 int srvpos;
7807
7808 newsrv = curproxy->srv;
7809 srvpos = 0;
7810 while (newsrv != NULL) {
7811 /* should this server be checked ? */
7812 if (newsrv->state & SRV_CHECKED) {
7813 if ((t = pool_alloc(task)) == NULL) {
7814 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7815 return -1;
7816 }
7817
7818 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7819 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7820 t->state = TASK_IDLE;
7821 t->process = process_chk;
7822 t->context = newsrv;
7823
7824 /* check this every ms */
7825 tv_delayfrom(&t->expire, &now,
7826 newsrv->inter + mininter * srvpos / nbchk);
7827 task_queue(t);
7828 //task_wakeup(&rq, t);
7829 srvpos++;
7830 }
7831 newsrv = newsrv->next;
7832 }
7833 }
7834
willy tarreau0f7af912005-12-17 12:21:26 +01007835 curproxy = curproxy->next;
7836 }
7837 if (cfgerr > 0) {
7838 Alert("Errors found in configuration file, aborting.\n");
7839 return -1;
7840 }
7841 else
7842 return 0;
7843}
7844
7845
7846/*
7847 * This function initializes all the necessary variables. It only returns
7848 * if everything is OK. If something fails, it exits.
7849 */
7850void init(int argc, char **argv) {
7851 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007852 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007853 char *old_argv = *argv;
7854 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007855 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007856
7857 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007858 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007859 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007860 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007861 exit(1);
7862 }
7863
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007864 /* initialize the libc's localtime structures once for all so that we
7865 * won't be missing memory if we want to send alerts under OOM conditions.
7866 */
7867 tv_now(&now);
7868 localtime(&now.tv_sec);
7869
willy tarreau4302f492005-12-18 01:00:37 +01007870 /* initialize the log header encoding map : '{|}"#' should be encoded with
7871 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7872 * URL encoding only requires '"', '#' to be encoded as well as non-
7873 * printable characters above.
7874 */
7875 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7876 memset(url_encode_map, 0, sizeof(url_encode_map));
7877 for (i = 0; i < 32; i++) {
7878 FD_SET(i, hdr_encode_map);
7879 FD_SET(i, url_encode_map);
7880 }
7881 for (i = 127; i < 256; i++) {
7882 FD_SET(i, hdr_encode_map);
7883 FD_SET(i, url_encode_map);
7884 }
7885
7886 tmp = "\"#{|}";
7887 while (*tmp) {
7888 FD_SET(*tmp, hdr_encode_map);
7889 tmp++;
7890 }
7891
7892 tmp = "\"#";
7893 while (*tmp) {
7894 FD_SET(*tmp, url_encode_map);
7895 tmp++;
7896 }
7897
willy tarreau64a3cc32005-12-18 01:13:11 +01007898 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7899#if defined(ENABLE_POLL)
7900 cfg_polling_mechanism |= POLL_USE_POLL;
7901#endif
7902#if defined(ENABLE_EPOLL)
7903 cfg_polling_mechanism |= POLL_USE_EPOLL;
7904#endif
7905
willy tarreau0f7af912005-12-17 12:21:26 +01007906 pid = getpid();
7907 progname = *argv;
7908 while ((tmp = strchr(progname, '/')) != NULL)
7909 progname = tmp + 1;
7910
7911 argc--; argv++;
7912 while (argc > 0) {
7913 char *flag;
7914
7915 if (**argv == '-') {
7916 flag = *argv+1;
7917
7918 /* 1 arg */
7919 if (*flag == 'v') {
7920 display_version();
7921 exit(0);
7922 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007923#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007924 else if (*flag == 'd' && flag[1] == 'e')
7925 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007926#endif
7927#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007928 else if (*flag == 'd' && flag[1] == 'p')
7929 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007930#endif
willy tarreau982249e2005-12-18 00:57:06 +01007931 else if (*flag == 'V')
7932 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007933 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007934 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007935 else if (*flag == 'c')
7936 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007937 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007938 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007939 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007940 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007941#if STATTIME > 0
7942 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007943 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007944 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007945 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007946#endif
7947 else { /* >=2 args */
7948 argv++; argc--;
7949 if (argc == 0)
7950 usage(old_argv);
7951
7952 switch (*flag) {
7953 case 'n' : cfg_maxconn = atol(*argv); break;
7954 case 'N' : cfg_maxpconn = atol(*argv); break;
7955 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007956 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007957 default: usage(old_argv);
7958 }
7959 }
7960 }
7961 else
7962 usage(old_argv);
7963 argv++; argc--;
7964 }
7965
willy tarreaud0fb4652005-12-18 01:32:04 +01007966 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7967 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007968
willy tarreau0f7af912005-12-17 12:21:26 +01007969 if (!cfg_cfgfile)
7970 usage(old_argv);
7971
7972 gethostname(hostname, MAX_HOSTNAME_LEN);
7973
willy tarreau12350152005-12-18 01:03:27 +01007974 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007975 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01007976 if (readcfgfile(cfg_cfgfile) < 0) {
7977 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7978 exit(1);
7979 }
willy tarreau12350152005-12-18 01:03:27 +01007980 if (have_appsession)
7981 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007982
willy tarreau982249e2005-12-18 00:57:06 +01007983 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007984 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7985 exit(0);
7986 }
7987
willy tarreau9fe663a2005-12-17 13:02:59 +01007988 if (cfg_maxconn > 0)
7989 global.maxconn = cfg_maxconn;
7990
willy tarreaufe2c5c12005-12-17 14:14:34 +01007991 if (cfg_pidfile) {
7992 if (global.pidfile)
7993 free(global.pidfile);
7994 global.pidfile = strdup(cfg_pidfile);
7995 }
7996
willy tarreau9fe663a2005-12-17 13:02:59 +01007997 if (global.maxconn == 0)
7998 global.maxconn = DEFAULT_MAXCONN;
7999
Willy TARREAU203b0b62006-03-12 18:00:28 +01008000 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008001
8002 if (arg_mode & MODE_DEBUG) {
8003 /* command line debug mode inhibits configuration mode */
8004 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8005 }
willy tarreau982249e2005-12-18 00:57:06 +01008006 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
8007 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008008
8009 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8010 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8011 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8012 }
8013
8014 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
8015 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
8016 global.nbproc = 1;
8017 }
8018
8019 if (global.nbproc < 1)
8020 global.nbproc = 1;
8021
willy tarreau0f7af912005-12-17 12:21:26 +01008022 StaticReadEvent = (fd_set *)calloc(1,
8023 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008024 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008025 StaticWriteEvent = (fd_set *)calloc(1,
8026 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008027 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008028
8029 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008030 sizeof(struct fdtab) * (global.maxsock));
8031 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008032 fdtab[i].state = FD_STCLOSE;
8033 }
8034}
8035
8036/*
8037 * this function starts all the proxies. It returns 0 if OK, -1 if not.
8038 */
8039int start_proxies() {
8040 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008041 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01008042 int fd;
8043
8044 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008045 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01008046 continue;
8047
willy tarreaua41a8b42005-12-17 14:02:24 +01008048 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
8049 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01008050 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008051 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8052 curproxy->id);
8053 return -1;
8054 }
willy tarreau0f7af912005-12-17 12:21:26 +01008055
willy tarreaua41a8b42005-12-17 14:02:24 +01008056 if (fd >= global.maxsock) {
8057 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8058 curproxy->id);
8059 close(fd);
8060 return -1;
8061 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008062
willy tarreaua41a8b42005-12-17 14:02:24 +01008063 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8064 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8065 (char *) &one, sizeof(one)) == -1)) {
8066 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8067 curproxy->id);
8068 close(fd);
8069 return -1;
8070 }
willy tarreau0f7af912005-12-17 12:21:26 +01008071
willy tarreaua41a8b42005-12-17 14:02:24 +01008072 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8073 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8074 curproxy->id);
8075 }
willy tarreau0f7af912005-12-17 12:21:26 +01008076
willy tarreaua41a8b42005-12-17 14:02:24 +01008077 if (bind(fd,
8078 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008079 listener->addr.ss_family == AF_INET6 ?
8080 sizeof(struct sockaddr_in6) :
8081 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008082 Alert("cannot bind socket for proxy %s. Aborting.\n",
8083 curproxy->id);
8084 close(fd);
8085 return -1;
8086 }
willy tarreau0f7af912005-12-17 12:21:26 +01008087
willy tarreaua41a8b42005-12-17 14:02:24 +01008088 if (listen(fd, curproxy->maxconn) == -1) {
8089 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8090 curproxy->id);
8091 close(fd);
8092 return -1;
8093 }
willy tarreau0f7af912005-12-17 12:21:26 +01008094
willy tarreaua41a8b42005-12-17 14:02:24 +01008095 /* the function for the accept() event */
8096 fdtab[fd].read = &event_accept;
8097 fdtab[fd].write = NULL; /* never called */
8098 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
8099 curproxy->state = PR_STRUN;
8100 fdtab[fd].state = FD_STLISTEN;
8101 FD_SET(fd, StaticReadEvent);
8102 fd_insert(fd);
8103 listeners++;
8104 }
willy tarreaua1598082005-12-17 13:08:06 +01008105 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008106 }
8107 return 0;
8108}
8109
willy tarreaub952e1d2005-12-18 01:31:20 +01008110int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008111
8112 appsess *temp1,*temp2;
8113 temp1 = (appsess *)key1;
8114 temp2 = (appsess *)key2;
8115
8116 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8117 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8118
8119 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8120}/* end match_str */
8121
willy tarreaub952e1d2005-12-18 01:31:20 +01008122void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008123 appsess *temp1;
8124
8125 //printf("destroy called\n");
8126 temp1 = (appsess *)data;
8127
8128 if (temp1->sessid)
8129 pool_free_to(apools.sessid, temp1->sessid);
8130
8131 if (temp1->serverid)
8132 pool_free_to(apools.serverid, temp1->serverid);
8133
8134 pool_free(appsess, temp1);
8135} /* end destroy */
8136
8137void appsession_cleanup( void )
8138{
8139 struct proxy *p = proxy;
8140
8141 while(p) {
8142 chtbl_destroy(&(p->htbl_proxy));
8143 p = p->next;
8144 }
8145}/* end appsession_cleanup() */
8146
8147void pool_destroy(void **pool)
8148{
8149 void *temp, *next;
8150 next = pool;
8151 while (next) {
8152 temp = next;
8153 next = *(void **)temp;
8154 free(temp);
8155 }
8156}/* end pool_destroy() */
8157
willy tarreaub952e1d2005-12-18 01:31:20 +01008158void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008159 struct proxy *p = proxy;
8160 struct cap_hdr *h,*h_next;
8161 struct server *s,*s_next;
8162 struct listener *l,*l_next;
8163
8164 while (p) {
8165 if (p->id)
8166 free(p->id);
8167
8168 if (p->check_req)
8169 free(p->check_req);
8170
8171 if (p->cookie_name)
8172 free(p->cookie_name);
8173
8174 if (p->capture_name)
8175 free(p->capture_name);
8176
8177 /* only strup if the user have set in config.
8178 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008179 if (p->errmsg.msg400) free(p->errmsg.msg400);
8180 if (p->errmsg.msg403) free(p->errmsg.msg403);
8181 if (p->errmsg.msg408) free(p->errmsg.msg408);
8182 if (p->errmsg.msg500) free(p->errmsg.msg500);
8183 if (p->errmsg.msg502) free(p->errmsg.msg502);
8184 if (p->errmsg.msg503) free(p->errmsg.msg503);
8185 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008186 */
8187 if (p->appsession_name)
8188 free(p->appsession_name);
8189
8190 h = p->req_cap;
8191 while (h) {
8192 h_next = h->next;
8193 if (h->name)
8194 free(h->name);
8195 pool_destroy(h->pool);
8196 free(h);
8197 h = h_next;
8198 }/* end while(h) */
8199
8200 h = p->rsp_cap;
8201 while (h) {
8202 h_next = h->next;
8203 if (h->name)
8204 free(h->name);
8205
8206 pool_destroy(h->pool);
8207 free(h);
8208 h = h_next;
8209 }/* end while(h) */
8210
8211 s = p->srv;
8212 while (s) {
8213 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008214 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008215 free(s->id);
8216
willy tarreaub952e1d2005-12-18 01:31:20 +01008217 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008218 free(s->cookie);
8219
8220 free(s);
8221 s = s_next;
8222 }/* end while(s) */
8223
8224 l = p->listen;
8225 while (l) {
8226 l_next = l->next;
8227 free(l);
8228 l = l_next;
8229 }/* end while(l) */
8230
8231 pool_destroy((void **) p->req_cap_pool);
8232 pool_destroy((void **) p->rsp_cap_pool);
8233 p = p->next;
8234 }/* end while(p) */
8235
8236 if (global.chroot) free(global.chroot);
8237 if (global.pidfile) free(global.pidfile);
8238
willy tarreau12350152005-12-18 01:03:27 +01008239 if (StaticReadEvent) free(StaticReadEvent);
8240 if (StaticWriteEvent) free(StaticWriteEvent);
8241 if (fdtab) free(fdtab);
8242
8243 pool_destroy(pool_session);
8244 pool_destroy(pool_buffer);
8245 pool_destroy(pool_fdtab);
8246 pool_destroy(pool_requri);
8247 pool_destroy(pool_task);
8248 pool_destroy(pool_capture);
8249 pool_destroy(pool_appsess);
8250
8251 if (have_appsession) {
8252 pool_destroy(apools.serverid);
8253 pool_destroy(apools.sessid);
8254 }
8255} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008256
8257int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008258 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008259 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008260 init(argc, argv);
8261
willy tarreau0f7af912005-12-17 12:21:26 +01008262 signal(SIGQUIT, dump);
8263 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008264 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008265#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008266 signal(SIGINT, sig_int);
8267 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008268#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008269
8270 /* on very high loads, a sigpipe sometimes happen just between the
8271 * getsockopt() which tells "it's OK to write", and the following write :-(
8272 */
willy tarreau3242e862005-12-17 12:27:53 +01008273#ifndef MSG_NOSIGNAL
8274 signal(SIGPIPE, SIG_IGN);
8275#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008276
willy tarreaud0fb4652005-12-18 01:32:04 +01008277 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008278 if (start_proxies() < 0)
8279 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008280
8281 if (listeners == 0) {
8282 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8283 exit(1);
8284 }
8285
willy tarreaudbd3bef2006-01-20 19:35:18 +01008286 /* prepare pause/play signals */
8287 signal(SIGTTOU, sig_pause);
8288 signal(SIGTTIN, sig_listen);
8289
Willy TARREAUe3283d12006-03-01 22:15:29 +01008290 if (global.mode & MODE_DAEMON) {
8291 global.mode &= ~MODE_VERBOSE;
8292 global.mode |= MODE_QUIET;
8293 }
8294
willy tarreaud0fb4652005-12-18 01:32:04 +01008295 /* MODE_QUIET can inhibit alerts and warnings below this line */
8296
8297 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008298 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008299 /* detach from the tty */
8300 fclose(stdin); fclose(stdout); fclose(stderr);
8301 close(0); close(1); close(2);
8302 }
willy tarreau0f7af912005-12-17 12:21:26 +01008303
willy tarreaufe2c5c12005-12-17 14:14:34 +01008304 /* open log & pid files before the chroot */
8305 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8306 int pidfd;
8307 unlink(global.pidfile);
8308 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8309 if (pidfd < 0) {
8310 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8311 exit(1);
8312 }
8313 pidfile = fdopen(pidfd, "w");
8314 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008315
8316 /* chroot if needed */
8317 if (global.chroot != NULL) {
8318 if (chroot(global.chroot) == -1) {
8319 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8320 exit(1);
8321 }
8322 chdir("/");
8323 }
8324
willy tarreaub1285d52005-12-18 01:20:14 +01008325 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008326 if (!global.rlimit_nofile)
8327 global.rlimit_nofile = global.maxsock;
8328
willy tarreaub1285d52005-12-18 01:20:14 +01008329 if (global.rlimit_nofile) {
8330 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8331 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8332 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8333 }
8334 }
8335
willy tarreau9fe663a2005-12-17 13:02:59 +01008336 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008337 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008338 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8339 exit(1);
8340 }
8341
willy tarreau036e1ce2005-12-17 13:46:33 +01008342 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008343 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8344 exit(1);
8345 }
8346
willy tarreaub1285d52005-12-18 01:20:14 +01008347 /* check ulimits */
8348 limit.rlim_cur = limit.rlim_max = 0;
8349 getrlimit(RLIMIT_NOFILE, &limit);
8350 if (limit.rlim_cur < global.maxsock) {
8351 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",
8352 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8353 }
8354
willy tarreau9fe663a2005-12-17 13:02:59 +01008355 if (global.mode & MODE_DAEMON) {
8356 int ret = 0;
8357 int proc;
8358
8359 /* the father launches the required number of processes */
8360 for (proc = 0; proc < global.nbproc; proc++) {
8361 ret = fork();
8362 if (ret < 0) {
8363 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8364 exit(1); /* there has been an error */
8365 }
8366 else if (ret == 0) /* child breaks here */
8367 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008368 if (pidfile != NULL) {
8369 fprintf(pidfile, "%d\n", ret);
8370 fflush(pidfile);
8371 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008372 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008373 /* close the pidfile both in children and father */
8374 if (pidfile != NULL)
8375 fclose(pidfile);
8376 free(global.pidfile);
8377
willy tarreau9fe663a2005-12-17 13:02:59 +01008378 if (proc == global.nbproc)
8379 exit(0); /* parent must leave */
8380
willy tarreau750a4722005-12-17 13:21:24 +01008381 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8382 * that we can detach from the TTY. We MUST NOT do it in other cases since
8383 * it would have already be done, and 0-2 would have been affected to listening
8384 * sockets
8385 */
8386 if (!(global.mode & MODE_QUIET)) {
8387 /* detach from the tty */
8388 fclose(stdin); fclose(stdout); fclose(stderr);
8389 close(0); close(1); close(2); /* close all fd's */
8390 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8391 }
willy tarreaua1598082005-12-17 13:08:06 +01008392 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008393 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008394 }
8395
willy tarreau1c2ad212005-12-18 01:11:29 +01008396#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008397 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008398 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8399 epoll_loop(POLL_LOOP_ACTION_RUN);
8400 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008401 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008402 }
8403 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008404 Warning("epoll() is not available. Using poll()/select() instead.\n");
8405 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008406 }
8407 }
8408#endif
8409
8410#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008411 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008412 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8413 poll_loop(POLL_LOOP_ACTION_RUN);
8414 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008415 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008416 }
8417 else {
8418 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008419 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008420 }
8421 }
8422#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008423 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008424 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8425 select_loop(POLL_LOOP_ACTION_RUN);
8426 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008427 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008428 }
8429 }
8430
willy tarreau0f7af912005-12-17 12:21:26 +01008431
willy tarreau12350152005-12-18 01:03:27 +01008432 /* Free all Hash Keys and all Hash elements */
8433 appsession_cleanup();
8434 /* Do some cleanup */
8435 deinit();
8436
willy tarreau0f7af912005-12-17 12:21:26 +01008437 exit(0);
8438}
willy tarreau12350152005-12-18 01:03:27 +01008439
8440#if defined(DEBUG_HASH)
8441static void print_table(const CHTbl *htbl) {
8442
8443 ListElmt *element;
8444 int i;
8445 appsess *asession;
8446
8447 /*****************************************************************************
8448 * *
8449 * Display the chained hash table. *
8450 * *
8451 *****************************************************************************/
8452
8453 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8454
8455 for (i = 0; i < TBLSIZ; i++) {
8456 fprintf(stdout, "Bucket[%03d]\n", i);
8457
8458 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8459 //fprintf(stdout, "%c", *(char *)list_data(element));
8460 asession = (appsess *)list_data(element);
8461 fprintf(stdout, "ELEM :%s:", asession->sessid);
8462 fprintf(stdout, " Server :%s: \n", asession->serverid);
8463 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8464 }
8465
8466 fprintf(stdout, "\n");
8467 }
8468 return;
8469} /* end print_table */
8470#endif
8471
8472static int appsession_init(void)
8473{
8474 static int initialized = 0;
8475 int idlen;
8476 struct server *s;
8477 struct proxy *p = proxy;
8478
8479 if (!initialized) {
8480 if (!appsession_task_init()) {
8481 apools.sessid = NULL;
8482 apools.serverid = NULL;
8483 apools.ser_waste = 0;
8484 apools.ser_use = 0;
8485 apools.ser_msize = sizeof(void *);
8486 apools.ses_waste = 0;
8487 apools.ses_use = 0;
8488 apools.ses_msize = sizeof(void *);
8489 while (p) {
8490 s = p->srv;
8491 if (apools.ses_msize < p->appsession_len)
8492 apools.ses_msize = p->appsession_len;
8493 while (s) {
8494 idlen = strlen(s->id);
8495 if (apools.ser_msize < idlen)
8496 apools.ser_msize = idlen;
8497 s = s->next;
8498 }
8499 p = p->next;
8500 }
8501 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8502 apools.ses_msize ++;
8503 }
8504 else {
8505 fprintf(stderr, "appsession_task_init failed\n");
8506 return -1;
8507 }
8508 initialized ++;
8509 }
8510 return 0;
8511}
8512
8513static int appsession_task_init(void)
8514{
8515 static int initialized = 0;
8516 struct task *t;
8517 if (!initialized) {
8518 if ((t = pool_alloc(task)) == NULL)
8519 return -1;
8520 t->next = t->prev = t->rqnext = NULL;
8521 t->wq = LIST_HEAD(wait_queue);
8522 t->state = TASK_IDLE;
8523 t->context = NULL;
8524 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8525 task_queue(t);
8526 t->process = appsession_refresh;
8527 initialized ++;
8528 }
8529 return 0;
8530}
8531
8532static int appsession_refresh(struct task *t) {
8533 struct proxy *p = proxy;
8534 CHTbl *htbl;
8535 ListElmt *element, *last;
8536 int i;
8537 appsess *asession;
8538 void *data;
8539
8540 while (p) {
8541 if (p->appsession_name != NULL) {
8542 htbl = &p->htbl_proxy;
8543 /* if we ever give up the use of TBLSIZ, we need to change this */
8544 for (i = 0; i < TBLSIZ; i++) {
8545 last = NULL;
8546 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8547 asession = (appsess *)list_data(element);
8548 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8549 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8550 int len;
8551 /*
8552 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8553 */
8554 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8555 asession->sessid, asession->serverid?asession->serverid:"(null)");
8556 write(1, trash, len);
8557 }
8558 /* delete the expired element from within the hash table */
8559 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8560 && (htbl->table[i].destroy != NULL)) {
8561 htbl->table[i].destroy(data);
8562 }
8563 if (last == NULL) {/* patient lost his head, get a new one */
8564 element = list_head(&htbl->table[i]);
8565 if (element == NULL) break; /* no heads left, go to next patient */
8566 }
8567 else
8568 element = last;
8569 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8570 else
8571 last = element;
8572 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8573 }
8574 }
8575 p = p->next;
8576 }
8577 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8578 return TBLCHKINT;
8579} /* end appsession_refresh */
8580