blob: 27b834ec1c1aa84f547f658faadcd0d4f27d1eb4 [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 */
575 int nbservers; /* # 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 tarreau8337c6b2005-12-17 13:41:01 +01001788 * This function tries to find a running server for the proxy <px>. A first
1789 * pass looks for active servers, and if none is found, a second pass also
1790 * looks for backup servers.
1791 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1792 */
1793static inline struct server *find_server(struct proxy *px) {
1794 struct server *srv = px->cursrv;
willy tarreau72e583d2006-03-23 11:27:02 +01001795 struct server *end;
willy tarreau8337c6b2005-12-17 13:41:01 +01001796 int ignore_backup = 1;
1797
1798 do {
willy tarreau72e583d2006-03-23 11:27:02 +01001799 if (srv == NULL)
1800 srv = px->srv;
1801 end = srv;
willy tarreau8337c6b2005-12-17 13:41:01 +01001802 do {
willy tarreau8337c6b2005-12-17 13:41:01 +01001803 if (srv->state & SRV_RUNNING
1804 && !((srv->state & SRV_BACKUP) && ignore_backup))
1805 return srv;
1806 srv = srv->next;
willy tarreau72e583d2006-03-23 11:27:02 +01001807 if (srv == NULL)
1808 srv = px->srv;
1809 } while (srv != end);
Willy TARREAU3481c462006-03-01 22:37:57 +01001810
1811 /* By default, we look for the first backup server if all others are
1812 * DOWN. But in some cases, it may be desirable to load-balance across
1813 * all backup servers.
1814 */
1815 if (!(px->options & PR_O_USE_ALL_BK))
1816 srv = px->srv;
1817
willy tarreau8337c6b2005-12-17 13:41:01 +01001818 } while (ignore_backup--);
1819 return NULL;
1820}
1821
1822/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001823 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001824 * is set, or to the dispatch server if (s->direct) is 0.
1825 * It can return one of :
1826 * - SN_ERR_NONE if everything's OK
1827 * - SN_ERR_SRVTO if there are no more servers
1828 * - SN_ERR_SRVCL if the connection was refused by the server
1829 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1830 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1831 * - SN_ERR_INTERNAL for any other purely internal errors
1832 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001833 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001834int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001835 int fd;
1836
willy tarreau12350152005-12-18 01:03:27 +01001837#ifdef DEBUG_FULL
1838 fprintf(stderr,"connect_server : s=%p\n",s);
1839#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001840
willy tarreaue39cd132005-12-17 13:00:18 +01001841 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001842 s->srv_addr = s->srv->addr;
1843 }
1844 else if (s->proxy->options & PR_O_BALANCE) {
1845 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001846 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001847
willy tarreau8337c6b2005-12-17 13:41:01 +01001848 srv = find_server(s->proxy);
1849
1850 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001851 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001852
willy tarreau8337c6b2005-12-17 13:41:01 +01001853 s->srv_addr = srv->addr;
1854 s->srv = srv;
1855 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001856 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001857 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001858 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001859 }
willy tarreaua1598082005-12-17 13:08:06 +01001860 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001861 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001862 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001863 }
1864 else if (s->proxy->options & PR_O_TRANSP) {
1865 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001866 socklen_t salen = sizeof(s->srv_addr);
1867
willy tarreau5cbea6f2005-12-17 12:48:26 +01001868 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1869 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001870 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001871 }
1872 }
willy tarreau0f7af912005-12-17 12:21:26 +01001873
willy tarreaua41a8b42005-12-17 14:02:24 +01001874 /* if this server remaps proxied ports, we'll use
1875 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001876 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001877 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001878 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001879
willy tarreaub952e1d2005-12-18 01:31:20 +01001880 if (!(s->proxy->options & PR_O_TRANSP) ||
1881 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001882 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1883 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1884 }
1885
willy tarreau0f7af912005-12-17 12:21:26 +01001886 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001887 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001888
1889 if (errno == ENFILE)
1890 send_log(s->proxy, LOG_EMERG,
1891 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1892 s->proxy->id, maxfd);
1893 else if (errno == EMFILE)
1894 send_log(s->proxy, LOG_EMERG,
1895 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1896 s->proxy->id, maxfd);
1897 else if (errno == ENOBUFS || errno == ENOMEM)
1898 send_log(s->proxy, LOG_EMERG,
1899 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1900 s->proxy->id, maxfd);
1901 /* this is a resource error */
1902 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001903 }
1904
willy tarreau9fe663a2005-12-17 13:02:59 +01001905 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001906 /* do not log anything there, it's a normal condition when this option
1907 * is used to serialize connections to a server !
1908 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001909 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1910 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001911 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001912 }
1913
willy tarreau0f7af912005-12-17 12:21:26 +01001914 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1915 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001916 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001917 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001918 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001919 }
1920
willy tarreaub952e1d2005-12-18 01:31:20 +01001921 if (s->proxy->options & PR_O_TCP_SRV_KA)
1922 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1923
willy tarreau0174f312005-12-18 01:02:42 +01001924 /* allow specific binding :
1925 * - server-specific at first
1926 * - proxy-specific next
1927 */
1928 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1929 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1930 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1931 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1932 s->proxy->id, s->srv->id);
1933 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001934 send_log(s->proxy, LOG_EMERG,
1935 "Cannot bind to source address before connect() for server %s/%s.\n",
1936 s->proxy->id, s->srv->id);
1937 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001938 }
1939 }
1940 else if (s->proxy->options & PR_O_BIND_SRC) {
1941 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1942 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1943 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1944 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001945 send_log(s->proxy, LOG_EMERG,
1946 "Cannot bind to source address before connect() for server %s/%s.\n",
1947 s->proxy->id, s->srv->id);
1948 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001949 }
willy tarreaua1598082005-12-17 13:08:06 +01001950 }
1951
willy tarreaub1285d52005-12-18 01:20:14 +01001952 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1953 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1954
1955 if (errno == EAGAIN || errno == EADDRINUSE) {
1956 char *msg;
1957 if (errno == EAGAIN) /* no free ports left, try again later */
1958 msg = "no free ports";
1959 else
1960 msg = "local address already in use";
1961
1962 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001963 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001964 send_log(s->proxy, LOG_EMERG,
1965 "Connect() failed for server %s/%s: %s.\n",
1966 s->proxy->id, s->srv->id, msg);
1967 return SN_ERR_RESOURCE;
1968 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001969 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01001970 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001971 return SN_ERR_SRVTO;
1972 } else {
1973 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01001974 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01001975 close(fd);
1976 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001977 }
1978 }
1979
willy tarreau5cbea6f2005-12-17 12:48:26 +01001980 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001981 fdtab[fd].read = &event_srv_read;
1982 fdtab[fd].write = &event_srv_write;
1983 fdtab[fd].state = FD_STCONN; /* connection in progress */
1984
1985 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01001986#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
1987 if (PrevReadEvent) {
1988 assert(!(FD_ISSET(fd, PrevReadEvent)));
1989 assert(!(FD_ISSET(fd, PrevWriteEvent)));
1990 }
1991#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001992
1993 fd_insert(fd);
1994
1995 if (s->proxy->contimeout)
1996 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1997 else
1998 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001999 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002000}
2001
2002/*
2003 * this function is called on a read event from a client socket.
2004 * It returns 0.
2005 */
2006int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007 struct task *t = fdtab[fd].owner;
2008 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002009 struct buffer *b = s->req;
2010 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002011
willy tarreau12350152005-12-18 01:03:27 +01002012#ifdef DEBUG_FULL
2013 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2014#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002015
willy tarreau0f7af912005-12-17 12:21:26 +01002016 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002017#ifdef FILL_BUFFERS
2018 while (1)
2019#else
2020 do
2021#endif
2022 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002023 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2024 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002025 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002026 }
2027 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002028 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002029 }
2030 else {
2031 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002032 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2033 * since it means that the rewrite protection has been removed. This
2034 * implies that the if statement can be removed.
2035 */
2036 if (max > b->rlim - b->data)
2037 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002038 }
2039
2040 if (max == 0) { /* not anymore room to store data */
2041 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002042 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002043 }
2044
willy tarreau3242e862005-12-17 12:27:53 +01002045#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002046 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002047 int skerr;
2048 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002049
willy tarreau5cbea6f2005-12-17 12:48:26 +01002050 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2051 if (skerr)
2052 ret = -1;
2053 else
2054 ret = recv(fd, b->r, max, 0);
2055 }
willy tarreau3242e862005-12-17 12:27:53 +01002056#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002057 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002058#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002059 if (ret > 0) {
2060 b->r += ret;
2061 b->l += ret;
2062 s->res_cr = RES_DATA;
2063
2064 if (b->r == b->data + BUFSIZE) {
2065 b->r = b->data; /* wrap around the buffer */
2066 }
willy tarreaua1598082005-12-17 13:08:06 +01002067
2068 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002069 /* we hope to read more data or to get a close on next round */
2070 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002071 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002072 else if (ret == 0) {
2073 s->res_cr = RES_NULL;
2074 break;
2075 }
2076 else if (errno == EAGAIN) {/* ignore EAGAIN */
2077 break;
2078 }
2079 else {
2080 s->res_cr = RES_ERROR;
2081 fdtab[fd].state = FD_STERROR;
2082 break;
2083 }
2084 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002085#ifndef FILL_BUFFERS
2086 while (0);
2087#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002088 }
2089 else {
2090 s->res_cr = RES_ERROR;
2091 fdtab[fd].state = FD_STERROR;
2092 }
2093
willy tarreau5cbea6f2005-12-17 12:48:26 +01002094 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002095 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002096 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2097 else
2098 tv_eternity(&s->crexpire);
2099
2100 task_wakeup(&rq, t);
2101 }
willy tarreau0f7af912005-12-17 12:21:26 +01002102
willy tarreau0f7af912005-12-17 12:21:26 +01002103 return 0;
2104}
2105
2106
2107/*
2108 * this function is called on a read event from a server socket.
2109 * It returns 0.
2110 */
2111int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002112 struct task *t = fdtab[fd].owner;
2113 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002114 struct buffer *b = s->rep;
2115 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002116
willy tarreau12350152005-12-18 01:03:27 +01002117#ifdef DEBUG_FULL
2118 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2119#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002120
willy tarreau0f7af912005-12-17 12:21:26 +01002121 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002122#ifdef FILL_BUFFERS
2123 while (1)
2124#else
2125 do
2126#endif
2127 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002128 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2129 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002130 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002131 }
2132 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002133 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002134 }
2135 else {
2136 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002137 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2138 * since it means that the rewrite protection has been removed. This
2139 * implies that the if statement can be removed.
2140 */
2141 if (max > b->rlim - b->data)
2142 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002143 }
2144
2145 if (max == 0) { /* not anymore room to store data */
2146 FD_CLR(fd, StaticReadEvent);
2147 break;
2148 }
2149
willy tarreau3242e862005-12-17 12:27:53 +01002150#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002151 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002152 int skerr;
2153 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002154
willy tarreau5cbea6f2005-12-17 12:48:26 +01002155 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2156 if (skerr)
2157 ret = -1;
2158 else
2159 ret = recv(fd, b->r, max, 0);
2160 }
willy tarreau3242e862005-12-17 12:27:53 +01002161#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002162 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002163#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002164 if (ret > 0) {
2165 b->r += ret;
2166 b->l += ret;
2167 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002168
willy tarreau5cbea6f2005-12-17 12:48:26 +01002169 if (b->r == b->data + BUFSIZE) {
2170 b->r = b->data; /* wrap around the buffer */
2171 }
willy tarreaua1598082005-12-17 13:08:06 +01002172
2173 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002174 /* we hope to read more data or to get a close on next round */
2175 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002176 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002177 else if (ret == 0) {
2178 s->res_sr = RES_NULL;
2179 break;
2180 }
2181 else if (errno == EAGAIN) {/* ignore EAGAIN */
2182 break;
2183 }
2184 else {
2185 s->res_sr = RES_ERROR;
2186 fdtab[fd].state = FD_STERROR;
2187 break;
2188 }
2189 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002190#ifndef FILL_BUFFERS
2191 while (0);
2192#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002193 }
2194 else {
2195 s->res_sr = RES_ERROR;
2196 fdtab[fd].state = FD_STERROR;
2197 }
2198
willy tarreau5cbea6f2005-12-17 12:48:26 +01002199 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002200 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002201 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2202 else
2203 tv_eternity(&s->srexpire);
2204
2205 task_wakeup(&rq, t);
2206 }
willy tarreau0f7af912005-12-17 12:21:26 +01002207
willy tarreau0f7af912005-12-17 12:21:26 +01002208 return 0;
2209}
2210
2211/*
2212 * this function is called on a write event from a client socket.
2213 * It returns 0.
2214 */
2215int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002216 struct task *t = fdtab[fd].owner;
2217 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002218 struct buffer *b = s->rep;
2219 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002220
willy tarreau12350152005-12-18 01:03:27 +01002221#ifdef DEBUG_FULL
2222 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2223#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002224
2225 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002226 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002227 // max = BUFSIZE; BUG !!!!
2228 max = 0;
2229 }
2230 else if (b->r > b->w) {
2231 max = b->r - b->w;
2232 }
2233 else
2234 max = b->data + BUFSIZE - b->w;
2235
willy tarreau0f7af912005-12-17 12:21:26 +01002236 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002237 if (max == 0) {
2238 s->res_cw = RES_NULL;
2239 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002240 tv_eternity(&s->cwexpire);
2241 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002242 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002243 }
2244
willy tarreau3242e862005-12-17 12:27:53 +01002245#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002246 {
2247 int skerr;
2248 socklen_t lskerr = sizeof(skerr);
2249
2250 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2251 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002252 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002253 else
willy tarreau3242e862005-12-17 12:27:53 +01002254 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002255 }
willy tarreau3242e862005-12-17 12:27:53 +01002256#else
willy tarreau0f7af912005-12-17 12:21:26 +01002257 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002258#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002259
2260 if (ret > 0) {
2261 b->l -= ret;
2262 b->w += ret;
2263
2264 s->res_cw = RES_DATA;
2265
2266 if (b->w == b->data + BUFSIZE) {
2267 b->w = b->data; /* wrap around the buffer */
2268 }
2269 }
2270 else if (ret == 0) {
2271 /* nothing written, just make as if we were never called */
2272// s->res_cw = RES_NULL;
2273 return 0;
2274 }
2275 else if (errno == EAGAIN) /* ignore EAGAIN */
2276 return 0;
2277 else {
2278 s->res_cw = RES_ERROR;
2279 fdtab[fd].state = FD_STERROR;
2280 }
2281 }
2282 else {
2283 s->res_cw = RES_ERROR;
2284 fdtab[fd].state = FD_STERROR;
2285 }
2286
willy tarreaub1ff9db2005-12-17 13:51:03 +01002287 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002288 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002289 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2290 s->crexpire = s->cwexpire;
2291 }
willy tarreau0f7af912005-12-17 12:21:26 +01002292 else
2293 tv_eternity(&s->cwexpire);
2294
willy tarreau5cbea6f2005-12-17 12:48:26 +01002295 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002296 return 0;
2297}
2298
2299
2300/*
2301 * this function is called on a write event from a server socket.
2302 * It returns 0.
2303 */
2304int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002305 struct task *t = fdtab[fd].owner;
2306 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002307 struct buffer *b = s->req;
2308 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002309
willy tarreau12350152005-12-18 01:03:27 +01002310#ifdef DEBUG_FULL
2311 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2312#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002313
2314 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002315 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002316 // max = BUFSIZE; BUG !!!!
2317 max = 0;
2318 }
2319 else if (b->r > b->w) {
2320 max = b->r - b->w;
2321 }
2322 else
2323 max = b->data + BUFSIZE - b->w;
2324
willy tarreau0f7af912005-12-17 12:21:26 +01002325 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002326 if (max == 0) {
2327 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002328 if (s->srv_state == SV_STCONN) {
2329 int skerr;
2330 socklen_t lskerr = sizeof(skerr);
2331 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2332 if (skerr) {
2333 s->res_sw = RES_ERROR;
2334 fdtab[fd].state = FD_STERROR;
2335 task_wakeup(&rq, t);
2336 tv_eternity(&s->swexpire);
2337 FD_CLR(fd, StaticWriteEvent);
2338 return 0;
2339 }
2340 }
2341
willy tarreau0f7af912005-12-17 12:21:26 +01002342 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002343 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002344 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002345 tv_eternity(&s->swexpire);
2346 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002347 return 0;
2348 }
2349
willy tarreau3242e862005-12-17 12:27:53 +01002350#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002351 {
2352 int skerr;
2353 socklen_t lskerr = sizeof(skerr);
2354 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2355 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002356 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002357 else
willy tarreau3242e862005-12-17 12:27:53 +01002358 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002359 }
willy tarreau3242e862005-12-17 12:27:53 +01002360#else
willy tarreau0f7af912005-12-17 12:21:26 +01002361 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002362#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002363 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002364 if (ret > 0) {
2365 b->l -= ret;
2366 b->w += ret;
2367
2368 s->res_sw = RES_DATA;
2369
2370 if (b->w == b->data + BUFSIZE) {
2371 b->w = b->data; /* wrap around the buffer */
2372 }
2373 }
2374 else if (ret == 0) {
2375 /* nothing written, just make as if we were never called */
2376 // s->res_sw = RES_NULL;
2377 return 0;
2378 }
2379 else if (errno == EAGAIN) /* ignore EAGAIN */
2380 return 0;
2381 else {
2382 s->res_sw = RES_ERROR;
2383 fdtab[fd].state = FD_STERROR;
2384 }
2385 }
2386 else {
2387 s->res_sw = RES_ERROR;
2388 fdtab[fd].state = FD_STERROR;
2389 }
2390
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002391 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2392 * otherwise it could loop indefinitely !
2393 */
2394 if (s->srv_state != SV_STCONN) {
2395 if (s->proxy->srvtimeout) {
2396 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2397 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2398 s->srexpire = s->swexpire;
2399 }
2400 else
2401 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002402 }
willy tarreau0f7af912005-12-17 12:21:26 +01002403
willy tarreau5cbea6f2005-12-17 12:48:26 +01002404 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002405 return 0;
2406}
2407
2408
2409/*
willy tarreaue39cd132005-12-17 13:00:18 +01002410 * returns a message to the client ; the connection is shut down for read,
2411 * and the request is cleared so that no server connection can be initiated.
2412 * The client must be in a valid state for this (HEADER, DATA ...).
2413 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002414 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002415 */
2416void client_retnclose(struct session *s, int len, const char *msg) {
2417 FD_CLR(s->cli_fd, StaticReadEvent);
2418 FD_SET(s->cli_fd, StaticWriteEvent);
2419 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002420 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002421 shutdown(s->cli_fd, SHUT_RD);
2422 s->cli_state = CL_STSHUTR;
2423 strcpy(s->rep->data, msg);
2424 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002425 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002426 s->rep->r += len;
2427 s->req->l = 0;
2428}
2429
2430
2431/*
2432 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002433 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002434 */
2435void client_return(struct session *s, int len, const char *msg) {
2436 strcpy(s->rep->data, msg);
2437 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002438 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002439 s->rep->r += len;
2440 s->req->l = 0;
2441}
2442
willy tarreau9fe663a2005-12-17 13:02:59 +01002443/*
2444 * send a log for the session when we have enough info about it
2445 */
2446void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002447 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002448 struct proxy *p = s->proxy;
2449 int log;
2450 char *uri;
2451 char *pxid;
2452 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002453 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002454
2455 /* This is a first attempt at a better logging system.
2456 * For now, we rely on send_log() to provide the date, although it obviously
2457 * is the date of the log and not of the request, and most fields are not
2458 * computed.
2459 */
2460
willy tarreaua1598082005-12-17 13:08:06 +01002461 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002462
willy tarreau8a86dbf2005-12-18 00:45:59 +01002463 if (s->cli_addr.ss_family == AF_INET)
2464 inet_ntop(AF_INET,
2465 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2466 pn, sizeof(pn));
2467 else
2468 inet_ntop(AF_INET6,
2469 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2470 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002471
willy tarreauc1cae632005-12-17 14:12:23 +01002472 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002473 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002474 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002475
willy tarreauc1cae632005-12-17 14:12:23 +01002476 tm = localtime(&s->logs.tv_accept.tv_sec);
2477 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002478 char tmpline[MAX_SYSLOG_LEN], *h;
2479 int hdr;
2480
2481 h = tmpline;
2482 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2483 *(h++) = ' ';
2484 *(h++) = '{';
2485 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2486 if (hdr)
2487 *(h++) = '|';
2488 if (s->req_cap[hdr] != NULL)
2489 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2490 }
2491 *(h++) = '}';
2492 }
2493
2494 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2495 *(h++) = ' ';
2496 *(h++) = '{';
2497 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2498 if (hdr)
2499 *(h++) = '|';
2500 if (s->rsp_cap[hdr] != NULL)
2501 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2502 }
2503 *(h++) = '}';
2504 }
2505
2506 if (h < tmpline + sizeof(tmpline) - 4) {
2507 *(h++) = ' ';
2508 *(h++) = '"';
2509 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2510 *(h++) = '"';
2511 }
2512 *h = '\0';
2513
willy tarreau0fe39652005-12-18 01:25:24 +01002514 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 +01002515 pn,
2516 (s->cli_addr.ss_family == AF_INET) ?
2517 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2518 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002519 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2520 tm->tm_hour, tm->tm_min, tm->tm_sec,
2521 pxid, srv,
2522 s->logs.t_request,
2523 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2524 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002525 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2526 s->logs.status,
2527 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002528 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2529 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002530 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2531 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2532 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2533 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002534 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002535 }
2536 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002537 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 +01002538 pn,
2539 (s->cli_addr.ss_family == AF_INET) ?
2540 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2541 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002542 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2543 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002544 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002545 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002546 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2547 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002548 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002549 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2550 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002551 }
2552
2553 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002554}
2555
willy tarreaue39cd132005-12-17 13:00:18 +01002556
2557/*
willy tarreau0f7af912005-12-17 12:21:26 +01002558 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002559 * to an accept. It tries to accept as many connections as possible.
2560 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002561 */
2562int event_accept(int fd) {
2563 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002564 struct session *s;
2565 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002566 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002567 int max_accept;
2568
2569 if (global.nbproc > 1)
2570 max_accept = 8; /* let other processes catch some connections too */
2571 else
2572 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002573
willy tarreauc2becdc2006-03-19 19:36:48 +01002574 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002575 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002576 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002577
willy tarreaub1285d52005-12-18 01:20:14 +01002578 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2579 switch (errno) {
2580 case EAGAIN:
2581 case EINTR:
2582 case ECONNABORTED:
2583 return 0; /* nothing more to accept */
2584 case ENFILE:
2585 send_log(p, LOG_EMERG,
2586 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2587 p->id, maxfd);
2588 return 0;
2589 case EMFILE:
2590 send_log(p, LOG_EMERG,
2591 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2592 p->id, maxfd);
2593 return 0;
2594 case ENOBUFS:
2595 case ENOMEM:
2596 send_log(p, LOG_EMERG,
2597 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2598 p->id, maxfd);
2599 return 0;
2600 default:
2601 return 0;
2602 }
2603 }
willy tarreau0f7af912005-12-17 12:21:26 +01002604
willy tarreau5cbea6f2005-12-17 12:48:26 +01002605 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2606 Alert("out of memory in event_accept().\n");
2607 FD_CLR(fd, StaticReadEvent);
2608 p->state = PR_STIDLE;
2609 close(cfd);
2610 return 0;
2611 }
willy tarreau0f7af912005-12-17 12:21:26 +01002612
willy tarreaub1285d52005-12-18 01:20:14 +01002613 /* if this session comes from a known monitoring system, we want to ignore
2614 * it as soon as possible, which means closing it immediately for TCP.
2615 */
2616 s->flags = 0;
2617 if (addr.ss_family == AF_INET &&
2618 p->mon_mask.s_addr &&
2619 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2620 if (p->mode == PR_MODE_TCP) {
2621 close(cfd);
2622 pool_free(session, s);
2623 continue;
2624 }
2625 s->flags |= SN_MONITOR;
2626 }
2627
willy tarreau5cbea6f2005-12-17 12:48:26 +01002628 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2629 Alert("out of memory in event_accept().\n");
2630 FD_CLR(fd, StaticReadEvent);
2631 p->state = PR_STIDLE;
2632 close(cfd);
2633 pool_free(session, s);
2634 return 0;
2635 }
willy tarreau0f7af912005-12-17 12:21:26 +01002636
willy tarreau5cbea6f2005-12-17 12:48:26 +01002637 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002638 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002639 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2640 close(cfd);
2641 pool_free(task, t);
2642 pool_free(session, s);
2643 return 0;
2644 }
willy tarreau0f7af912005-12-17 12:21:26 +01002645
willy tarreau5cbea6f2005-12-17 12:48:26 +01002646 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2647 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2648 (char *) &one, sizeof(one)) == -1)) {
2649 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2650 close(cfd);
2651 pool_free(task, t);
2652 pool_free(session, s);
2653 return 0;
2654 }
willy tarreau0f7af912005-12-17 12:21:26 +01002655
willy tarreaub952e1d2005-12-18 01:31:20 +01002656 if (p->options & PR_O_TCP_CLI_KA)
2657 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2658
willy tarreau9fe663a2005-12-17 13:02:59 +01002659 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2660 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2661 t->state = TASK_IDLE;
2662 t->process = process_session;
2663 t->context = s;
2664
2665 s->task = t;
2666 s->proxy = p;
2667 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2668 s->srv_state = SV_STIDLE;
2669 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002670
willy tarreau9fe663a2005-12-17 13:02:59 +01002671 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2672 s->cli_fd = cfd;
2673 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002674 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002675 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002676
willy tarreaub1285d52005-12-18 01:20:14 +01002677 if (s->flags & SN_MONITOR)
2678 s->logs.logwait = 0;
2679 else
2680 s->logs.logwait = p->to_log;
2681
willy tarreaua1598082005-12-17 13:08:06 +01002682 s->logs.tv_accept = now;
2683 s->logs.t_request = -1;
2684 s->logs.t_connect = -1;
2685 s->logs.t_data = -1;
2686 s->logs.t_close = 0;
2687 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002688 s->logs.cli_cookie = NULL;
2689 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002690 s->logs.status = -1;
2691 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002692
willy tarreau2f6ba652005-12-17 13:57:42 +01002693 s->uniq_id = totalconn;
2694
willy tarreau4302f492005-12-18 01:00:37 +01002695 if (p->nb_req_cap > 0) {
2696 if ((s->req_cap =
2697 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2698 == NULL) { /* no memory */
2699 close(cfd); /* nothing can be done for this fd without memory */
2700 pool_free(task, t);
2701 pool_free(session, s);
2702 return 0;
2703 }
2704 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2705 }
2706 else
2707 s->req_cap = NULL;
2708
2709 if (p->nb_rsp_cap > 0) {
2710 if ((s->rsp_cap =
2711 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2712 == NULL) { /* no memory */
2713 if (s->req_cap != NULL)
2714 pool_free_to(p->req_cap_pool, s->req_cap);
2715 close(cfd); /* nothing can be done for this fd without memory */
2716 pool_free(task, t);
2717 pool_free(session, s);
2718 return 0;
2719 }
2720 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2721 }
2722 else
2723 s->rsp_cap = NULL;
2724
willy tarreau5cbea6f2005-12-17 12:48:26 +01002725 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2726 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002727 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002728 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002729
willy tarreau8a86dbf2005-12-18 00:45:59 +01002730 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002731 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002732 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002733 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002734
willy tarreau9fe663a2005-12-17 13:02:59 +01002735 if (p->to_log) {
2736 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002737 if (s->logs.logwait & LW_CLIP)
2738 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002739 sess_log(s);
2740 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002741 else if (s->cli_addr.ss_family == AF_INET) {
2742 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2743 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2744 sn, sizeof(sn)) &&
2745 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2746 pn, sizeof(pn))) {
2747 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2748 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2749 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2750 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2751 }
2752 }
2753 else {
2754 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2755 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2756 sn, sizeof(sn)) &&
2757 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2758 pn, sizeof(pn))) {
2759 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2760 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2761 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2762 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2763 }
2764 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002765 }
willy tarreau0f7af912005-12-17 12:21:26 +01002766
willy tarreau982249e2005-12-18 00:57:06 +01002767 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002768 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002769 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002770 int len;
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 tarreau2f6ba652005-12-17 13:57:42 +01002774 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002775
willy tarreau8a86dbf2005-12-18 00:45:59 +01002776 if (s->cli_addr.ss_family == AF_INET) {
2777 char pn[INET_ADDRSTRLEN];
2778 inet_ntop(AF_INET,
2779 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2780 pn, sizeof(pn));
2781
2782 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2783 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2784 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2785 }
2786 else {
2787 char pn[INET6_ADDRSTRLEN];
2788 inet_ntop(AF_INET6,
2789 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2790 pn, sizeof(pn));
2791
2792 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2793 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2794 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2795 }
2796
willy tarreauef900ab2005-12-17 12:52:52 +01002797 write(1, trash, len);
2798 }
willy tarreau0f7af912005-12-17 12:21:26 +01002799
willy tarreau5cbea6f2005-12-17 12:48:26 +01002800 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002801 if (s->rsp_cap != NULL)
2802 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2803 if (s->req_cap != NULL)
2804 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002805 close(cfd); /* nothing can be done for this fd without memory */
2806 pool_free(task, t);
2807 pool_free(session, s);
2808 return 0;
2809 }
willy tarreau4302f492005-12-18 01:00:37 +01002810
willy tarreau5cbea6f2005-12-17 12:48:26 +01002811 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002812 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002813 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2814 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002815 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002816 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002817
willy tarreau5cbea6f2005-12-17 12:48:26 +01002818 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2819 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002820 if (s->rsp_cap != NULL)
2821 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2822 if (s->req_cap != NULL)
2823 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002824 close(cfd); /* nothing can be done for this fd without memory */
2825 pool_free(task, t);
2826 pool_free(session, s);
2827 return 0;
2828 }
2829 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002830 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002831 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 +01002832
willy tarreau5cbea6f2005-12-17 12:48:26 +01002833 fdtab[cfd].read = &event_cli_read;
2834 fdtab[cfd].write = &event_cli_write;
2835 fdtab[cfd].owner = t;
2836 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002837
willy tarreaub1285d52005-12-18 01:20:14 +01002838 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2839 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2840 /* Either we got a request from a monitoring system on an HTTP instance,
2841 * or we're in health check mode with the 'httpchk' option enabled. In
2842 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2843 */
2844 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2845 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2846 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002847 }
2848 else {
2849 FD_SET(cfd, StaticReadEvent);
2850 }
2851
willy tarreaub952e1d2005-12-18 01:31:20 +01002852#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2853 if (PrevReadEvent) {
2854 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2855 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2856 }
2857#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002858 fd_insert(cfd);
2859
2860 tv_eternity(&s->cnexpire);
2861 tv_eternity(&s->srexpire);
2862 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002863 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002864 tv_eternity(&s->cwexpire);
2865
willy tarreaub1285d52005-12-18 01:20:14 +01002866 if (s->proxy->clitimeout) {
2867 if (FD_ISSET(cfd, StaticReadEvent))
2868 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2869 if (FD_ISSET(cfd, StaticWriteEvent))
2870 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2871 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002872
willy tarreaub1285d52005-12-18 01:20:14 +01002873 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002874
2875 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002876
2877 if (p->mode != PR_MODE_HEALTH)
2878 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002879
2880 p->nbconn++;
2881 actconn++;
2882 totalconn++;
2883
willy tarreaub952e1d2005-12-18 01:31:20 +01002884 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002885 } /* end of while (p->nbconn < p->maxconn) */
2886 return 0;
2887}
willy tarreau0f7af912005-12-17 12:21:26 +01002888
willy tarreau0f7af912005-12-17 12:21:26 +01002889
willy tarreau5cbea6f2005-12-17 12:48:26 +01002890/*
2891 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002892 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2893 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002894 * or -1 if an error occured.
2895 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002896int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002897 struct task *t = fdtab[fd].owner;
2898 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002899 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002900 socklen_t lskerr = sizeof(skerr);
2901
willy tarreau05be12b2006-03-19 19:35:00 +01002902 skerr = 1;
2903 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
2904 || (skerr != 0)) {
2905 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002906 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002907 fdtab[fd].state = FD_STERROR;
2908 FD_CLR(fd, StaticWriteEvent);
2909 }
willy tarreaua4a583a2005-12-18 01:39:19 +01002910 else if (s->result != -1) {
2911 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002912 if (s->proxy->options & PR_O_HTTP_CHK) {
2913 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002914 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002915 * so we'll send the request, and won't wake the checker up now.
2916 */
2917#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002918 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002919#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002920 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002921#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002922 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002923 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2924 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2925 return 0;
2926 }
willy tarreau05be12b2006-03-19 19:35:00 +01002927 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002928 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01002929 FD_CLR(fd, StaticWriteEvent);
2930 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002931 }
2932 else {
2933 /* good TCP connection is enough */
2934 s->result = 1;
2935 }
2936 }
2937
2938 task_wakeup(&rq, t);
2939 return 0;
2940}
2941
willy tarreau0f7af912005-12-17 12:21:26 +01002942
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002943/*
2944 * This function is used only for server health-checks. It handles
2945 * the server's reply to an HTTP request. It returns 1 if the server replies
2946 * 2xx or 3xx (valid responses), or -1 in other cases.
2947 */
2948int event_srv_chk_r(int fd) {
2949 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002950 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002951 struct task *t = fdtab[fd].owner;
2952 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01002953 int skerr;
2954 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002955
willy tarreaua4a583a2005-12-18 01:39:19 +01002956 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002957
willy tarreau05be12b2006-03-19 19:35:00 +01002958 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2959 if (!skerr) {
2960#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002961 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002962#else
willy tarreau05be12b2006-03-19 19:35:00 +01002963 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2964 * but the connection was closed on the remote end. Fortunately, recv still
2965 * works correctly and we don't need to do the getsockopt() on linux.
2966 */
2967 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002968#endif
willy tarreau05be12b2006-03-19 19:35:00 +01002969
2970 if ((len >= sizeof("HTTP/1.0 000")) &&
2971 !memcmp(reply, "HTTP/1.", 7) &&
2972 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2973 result = 1;
2974 }
2975
2976 if (result == -1)
2977 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01002978
2979 if (s->result != -1)
2980 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002981
2982 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002983 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002984 return 0;
2985}
2986
2987
2988/*
2989 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2990 * and moves <end> just after the end of <str>.
2991 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2992 * the shift value (positive or negative) is returned.
2993 * If there's no space left, the move is not done.
2994 *
2995 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002996int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002997 int delta;
2998 int len;
2999
3000 len = strlen(str);
3001 delta = len - (end - pos);
3002
3003 if (delta + b->r >= b->data + BUFSIZE)
3004 return 0; /* no space left */
3005
3006 /* first, protect the end of the buffer */
3007 memmove(end + delta, end, b->data + b->l - end);
3008
3009 /* now, copy str over pos */
3010 memcpy(pos, str,len);
3011
willy tarreau5cbea6f2005-12-17 12:48:26 +01003012 /* we only move data after the displaced zone */
3013 if (b->r > pos) b->r += delta;
3014 if (b->w > pos) b->w += delta;
3015 if (b->h > pos) b->h += delta;
3016 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003017 b->l += delta;
3018
3019 return delta;
3020}
3021
willy tarreau8337c6b2005-12-17 13:41:01 +01003022/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003023 * len is 0.
3024 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003025int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003026 int delta;
3027
3028 delta = len - (end - pos);
3029
3030 if (delta + b->r >= b->data + BUFSIZE)
3031 return 0; /* no space left */
3032
Willy TARREAUe78ae262006-01-08 01:24:12 +01003033 if (b->data + b->l < end)
3034 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3035 return 0;
3036
willy tarreau0f7af912005-12-17 12:21:26 +01003037 /* first, protect the end of the buffer */
3038 memmove(end + delta, end, b->data + b->l - end);
3039
3040 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003041 if (len)
3042 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003043
willy tarreau5cbea6f2005-12-17 12:48:26 +01003044 /* we only move data after the displaced zone */
3045 if (b->r > pos) b->r += delta;
3046 if (b->w > pos) b->w += delta;
3047 if (b->h > pos) b->h += delta;
3048 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003049 b->l += delta;
3050
3051 return delta;
3052}
3053
3054
3055int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3056 char *old_dst = dst;
3057
3058 while (*str) {
3059 if (*str == '\\') {
3060 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003061 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003062 int len, num;
3063
3064 num = *str - '0';
3065 str++;
3066
willy tarreau8a86dbf2005-12-18 00:45:59 +01003067 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003068 len = matches[num].rm_eo - matches[num].rm_so;
3069 memcpy(dst, src + matches[num].rm_so, len);
3070 dst += len;
3071 }
3072
3073 }
3074 else if (*str == 'x') {
3075 unsigned char hex1, hex2;
3076 str++;
3077
willy tarreauc1f47532005-12-18 01:08:26 +01003078 hex1 = toupper(*str++) - '0';
3079 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003080
3081 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3082 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3083 *dst++ = (hex1<<4) + hex2;
3084 }
3085 else
3086 *dst++ = *str++;
3087 }
3088 else
3089 *dst++ = *str++;
3090 }
3091 *dst = 0;
3092 return dst - old_dst;
3093}
3094
willy tarreauc1f47532005-12-18 01:08:26 +01003095static int ishex(char s)
3096{
3097 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3098}
3099
3100/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3101char *check_replace_string(char *str)
3102{
3103 char *err = NULL;
3104 while (*str) {
3105 if (*str == '\\') {
3106 err = str; /* in case of a backslash, we return the pointer to it */
3107 str++;
3108 if (!*str)
3109 return err;
3110 else if (isdigit((int)*str))
3111 err = NULL;
3112 else if (*str == 'x') {
3113 str++;
3114 if (!ishex(*str))
3115 return err;
3116 str++;
3117 if (!ishex(*str))
3118 return err;
3119 err = NULL;
3120 }
3121 else {
3122 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3123 err = NULL;
3124 }
3125 }
3126 str++;
3127 }
3128 return err;
3129}
3130
3131
willy tarreau9fe663a2005-12-17 13:02:59 +01003132
willy tarreau0f7af912005-12-17 12:21:26 +01003133/*
3134 * manages the client FSM and its socket. BTW, it also tries to handle the
3135 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3136 * 0 else.
3137 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003138int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003139 int s = t->srv_state;
3140 int c = t->cli_state;
3141 struct buffer *req = t->req;
3142 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003143 int method_checked = 0;
3144 appsess *asession_temp = NULL;
3145 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003146
willy tarreau750a4722005-12-17 13:21:24 +01003147#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003148 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3149 cli_stnames[c], srv_stnames[s],
3150 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3151 t->crexpire.tv_sec, t->crexpire.tv_usec,
3152 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003153#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003154 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3155 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3156 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3157 //);
3158 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003159 /* now parse the partial (or complete) headers */
3160 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3161 char *ptr;
3162 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003163 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003164
willy tarreau5cbea6f2005-12-17 12:48:26 +01003165 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003166
willy tarreau0f7af912005-12-17 12:21:26 +01003167 /* look for the end of the current header */
3168 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3169 ptr++;
3170
willy tarreau5cbea6f2005-12-17 12:48:26 +01003171 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003172 int line, len;
3173 /* we can only get here after an end of headers */
3174 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003175
willy tarreaue39cd132005-12-17 13:00:18 +01003176 if (t->flags & SN_CLDENY) {
3177 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003178 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003179 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003180 if (!(t->flags & SN_ERR_MASK))
3181 t->flags |= SN_ERR_PRXCOND;
3182 if (!(t->flags & SN_FINST_MASK))
3183 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003184 return 1;
3185 }
3186
willy tarreau5cbea6f2005-12-17 12:48:26 +01003187 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003188 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3189 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003190 }
willy tarreau0f7af912005-12-17 12:21:26 +01003191
willy tarreau9fe663a2005-12-17 13:02:59 +01003192 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003193 if (t->cli_addr.ss_family == AF_INET) {
3194 unsigned char *pn;
3195 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3196 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3197 pn[0], pn[1], pn[2], pn[3]);
3198 buffer_replace2(req, req->h, req->h, trash, len);
3199 }
3200 else if (t->cli_addr.ss_family == AF_INET6) {
3201 char pn[INET6_ADDRSTRLEN];
3202 inet_ntop(AF_INET6,
3203 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3204 pn, sizeof(pn));
3205 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3206 buffer_replace2(req, req->h, req->h, trash, len);
3207 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003208 }
3209
willy tarreau25c4ea52005-12-18 00:49:49 +01003210 /* add a "connection: close" line if needed */
3211 if (t->proxy->options & PR_O_HTTP_CLOSE)
3212 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3213
willy tarreau982249e2005-12-18 00:57:06 +01003214 if (!memcmp(req->data, "POST ", 5)) {
3215 /* this is a POST request, which is not cacheable by default */
3216 t->flags |= SN_POST;
3217 }
willy tarreaucd878942005-12-17 13:27:43 +01003218
willy tarreau5cbea6f2005-12-17 12:48:26 +01003219 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003220 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003221
willy tarreau750a4722005-12-17 13:21:24 +01003222 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003223 /* FIXME: we'll set the client in a wait state while we try to
3224 * connect to the server. Is this really needed ? wouldn't it be
3225 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003226 //FD_CLR(t->cli_fd, StaticReadEvent);
3227 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003228
3229 /* FIXME: if we break here (as up to 1.1.23), having the client
3230 * shutdown its connection can lead to an abort further.
3231 * it's better to either return 1 or even jump directly to the
3232 * data state which will save one schedule.
3233 */
3234 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003235
3236 if (!t->proxy->clitimeout ||
3237 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3238 /* If the client has no timeout, or if the server is not ready yet,
3239 * and we know for sure that it can expire, then it's cleaner to
3240 * disable the timeout on the client side so that too low values
3241 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003242 *
3243 * FIXME-20050705: the server needs a way to re-enable this time-out
3244 * when it switches its state, otherwise a client can stay connected
3245 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003246 */
3247 tv_eternity(&t->crexpire);
3248
willy tarreau197e8ec2005-12-17 14:10:59 +01003249 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003250 }
willy tarreau0f7af912005-12-17 12:21:26 +01003251
Willy TARREAU13032e72006-03-12 17:31:45 +01003252 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3253 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003254 /* this is a partial header, let's wait for more to come */
3255 req->lr = ptr;
3256 break;
3257 }
willy tarreau0f7af912005-12-17 12:21:26 +01003258
willy tarreau5cbea6f2005-12-17 12:48:26 +01003259 /* now we know that *ptr is either \r or \n,
3260 * and that there are at least 1 char after it.
3261 */
3262 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3263 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3264 else
3265 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003266
willy tarreau5cbea6f2005-12-17 12:48:26 +01003267 /*
3268 * now we know that we have a full header ; we can do whatever
3269 * we want with these pointers :
3270 * req->h = beginning of header
3271 * ptr = end of header (first \r or \n)
3272 * req->lr = beginning of next line (next rep->h)
3273 * req->r = end of data (not used at this stage)
3274 */
willy tarreau0f7af912005-12-17 12:21:26 +01003275
willy tarreau12350152005-12-18 01:03:27 +01003276 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3277 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3278 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3279
3280 /* skip ; */
3281 request_line++;
3282
3283 /* look if we have a jsessionid */
3284
3285 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3286
3287 /* skip jsessionid= */
3288 request_line += t->proxy->appsession_name_len + 1;
3289
3290 /* First try if we allready have an appsession */
3291 asession_temp = &local_asession;
3292
3293 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3294 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3295 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3296 return 0;
3297 }
3298
3299 /* Copy the sessionid */
3300 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3301 asession_temp->sessid[t->proxy->appsession_len] = 0;
3302 asession_temp->serverid = NULL;
3303
3304 /* only do insert, if lookup fails */
3305 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3306 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3307 Alert("Not enough memory process_cli():asession:calloc().\n");
3308 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3309 return 0;
3310 }
3311 asession_temp->sessid = local_asession.sessid;
3312 asession_temp->serverid = local_asession.serverid;
3313 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003314 } /* end if (chtbl_lookup()) */
3315 else {
willy tarreau12350152005-12-18 01:03:27 +01003316 /*free wasted memory;*/
3317 pool_free_to(apools.sessid, local_asession.sessid);
3318 }
3319
3320 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3321 asession_temp->request_count++;
3322
3323#if defined(DEBUG_HASH)
3324 print_table(&(t->proxy->htbl_proxy));
3325#endif
3326
3327 if (asession_temp->serverid == NULL) {
3328 Alert("Found Application Session without matching server.\n");
3329 } else {
3330 struct server *srv = t->proxy->srv;
3331 while (srv) {
3332 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3333 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3334 /* we found the server and it's usable */
3335 t->flags &= ~SN_CK_MASK;
3336 t->flags |= SN_CK_VALID | SN_DIRECT;
3337 t->srv = srv;
3338 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003339 } else {
willy tarreau12350152005-12-18 01:03:27 +01003340 t->flags &= ~SN_CK_MASK;
3341 t->flags |= SN_CK_DOWN;
3342 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003343 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003344 srv = srv->next;
3345 }/* end while(srv) */
3346 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003347 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003348 else {
3349 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3350 }
willy tarreau598da412005-12-18 01:07:29 +01003351 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003352 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003353 else{
3354 //printf("No Methode-Header with Session-String\n");
3355 }
3356
willy tarreau8337c6b2005-12-17 13:41:01 +01003357 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003358 /* we have a complete HTTP request that we must log */
3359 int urilen;
3360
willy tarreaua1598082005-12-17 13:08:06 +01003361 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003362 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003363 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003364 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003365 if (!(t->flags & SN_ERR_MASK))
3366 t->flags |= SN_ERR_PRXCOND;
3367 if (!(t->flags & SN_FINST_MASK))
3368 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003369 return 1;
3370 }
3371
3372 urilen = ptr - req->h;
3373 if (urilen >= REQURI_LEN)
3374 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003375 memcpy(t->logs.uri, req->h, urilen);
3376 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003377
willy tarreaua1598082005-12-17 13:08:06 +01003378 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003379 sess_log(t);
3380 }
willy tarreau4302f492005-12-18 01:00:37 +01003381 else if (t->logs.logwait & LW_REQHDR) {
3382 struct cap_hdr *h;
3383 int len;
3384 for (h = t->proxy->req_cap; h; h = h->next) {
3385 if ((h->namelen + 2 <= ptr - req->h) &&
3386 (req->h[h->namelen] == ':') &&
3387 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3388
3389 if (t->req_cap[h->index] == NULL)
3390 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3391
3392 len = ptr - (req->h + h->namelen + 2);
3393 if (len > h->len)
3394 len = h->len;
3395
3396 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3397 t->req_cap[h->index][len]=0;
3398 }
3399 }
3400
3401 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003402
willy tarreau5cbea6f2005-12-17 12:48:26 +01003403 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003404
willy tarreau982249e2005-12-18 00:57:06 +01003405 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003406 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003407 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 +01003408 max = ptr - req->h;
3409 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003410 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003411 trash[len++] = '\n';
3412 write(1, trash, len);
3413 }
willy tarreau0f7af912005-12-17 12:21:26 +01003414
willy tarreau25c4ea52005-12-18 00:49:49 +01003415
3416 /* remove "connection: " if needed */
3417 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3418 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3419 delete_header = 1;
3420 }
3421
willy tarreau5cbea6f2005-12-17 12:48:26 +01003422 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003423 if (!delete_header && t->proxy->req_exp != NULL
3424 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003425 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003426 char term;
3427
3428 term = *ptr;
3429 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003430 exp = t->proxy->req_exp;
3431 do {
3432 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3433 switch (exp->action) {
3434 case ACT_ALLOW:
3435 if (!(t->flags & SN_CLDENY))
3436 t->flags |= SN_CLALLOW;
3437 break;
3438 case ACT_REPLACE:
3439 if (!(t->flags & SN_CLDENY)) {
3440 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3441 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3442 }
3443 break;
3444 case ACT_REMOVE:
3445 if (!(t->flags & SN_CLDENY))
3446 delete_header = 1;
3447 break;
3448 case ACT_DENY:
3449 if (!(t->flags & SN_CLALLOW))
3450 t->flags |= SN_CLDENY;
3451 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003452 case ACT_PASS: /* we simply don't deny this one */
3453 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003454 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003455 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003456 }
willy tarreaue39cd132005-12-17 13:00:18 +01003457 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003458 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003459 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003460
willy tarreau240afa62005-12-17 13:14:35 +01003461 /* Now look for cookies. Conforming to RFC2109, we have to support
3462 * attributes whose name begin with a '$', and associate them with
3463 * the right cookie, if we want to delete this cookie.
3464 * So there are 3 cases for each cookie read :
3465 * 1) it's a special attribute, beginning with a '$' : ignore it.
3466 * 2) it's a server id cookie that we *MAY* want to delete : save
3467 * some pointers on it (last semi-colon, beginning of cookie...)
3468 * 3) it's an application cookie : we *MAY* have to delete a previous
3469 * "special" cookie.
3470 * At the end of loop, if a "special" cookie remains, we may have to
3471 * remove it. If no application cookie persists in the header, we
3472 * *MUST* delete it
3473 */
willy tarreau12350152005-12-18 01:03:27 +01003474 if (!delete_header &&
3475 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003476 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003477 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003478 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003479 char *del_colon, *del_cookie, *colon;
3480 int app_cookies;
3481
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003483 colon = p1;
3484 /* del_cookie == NULL => nothing to be deleted */
3485 del_colon = del_cookie = NULL;
3486 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003487
3488 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003489 /* skip spaces and colons, but keep an eye on these ones */
3490 while (p1 < ptr) {
3491 if (*p1 == ';' || *p1 == ',')
3492 colon = p1;
3493 else if (!isspace((int)*p1))
3494 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003495 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003496 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003497
3498 if (p1 == ptr)
3499 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003500
3501 /* p1 is at the beginning of the cookie name */
3502 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003503 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003504 p2++;
3505
3506 if (p2 == ptr)
3507 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003508
3509 p3 = p2 + 1; /* skips the '=' sign */
3510 if (p3 == ptr)
3511 break;
3512
willy tarreau240afa62005-12-17 13:14:35 +01003513 p4 = p3;
3514 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003515 p4++;
3516
3517 /* here, we have the cookie name between p1 and p2,
3518 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003519 * we can process it :
3520 *
3521 * Cookie: NAME=VALUE;
3522 * | || || |
3523 * | || || +--> p4
3524 * | || |+-------> p3
3525 * | || +--------> p2
3526 * | |+------------> p1
3527 * | +-------------> colon
3528 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003529 */
3530
willy tarreau240afa62005-12-17 13:14:35 +01003531 if (*p1 == '$') {
3532 /* skip this one */
3533 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003534 else {
3535 /* first, let's see if we want to capture it */
3536 if (t->proxy->capture_name != NULL &&
3537 t->logs.cli_cookie == NULL &&
3538 (p4 - p1 >= t->proxy->capture_namelen) &&
3539 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3540 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003541
willy tarreau8337c6b2005-12-17 13:41:01 +01003542 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3543 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003544 } else {
3545 if (log_len > t->proxy->capture_len)
3546 log_len = t->proxy->capture_len;
3547 memcpy(t->logs.cli_cookie, p1, log_len);
3548 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003549 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003550 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003551
3552 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3553 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3554 /* Cool... it's the right one */
3555 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003556 char *delim;
3557
3558 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3559 * have the server ID betweek p3 and delim, and the original cookie between
3560 * delim+1 and p4. Otherwise, delim==p4 :
3561 *
3562 * Cookie: NAME=SRV~VALUE;
3563 * | || || | |
3564 * | || || | +--> p4
3565 * | || || +--------> delim
3566 * | || |+-----------> p3
3567 * | || +------------> p2
3568 * | |+----------------> p1
3569 * | +-----------------> colon
3570 * +------------------------> req->h
3571 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003572
willy tarreau0174f312005-12-18 01:02:42 +01003573 if (t->proxy->options & PR_O_COOK_PFX) {
3574 for (delim = p3; delim < p4; delim++)
3575 if (*delim == COOKIE_DELIM)
3576 break;
3577 }
3578 else
3579 delim = p4;
3580
3581
3582 /* Here, we'll look for the first running server which supports the cookie.
3583 * This allows to share a same cookie between several servers, for example
3584 * to dedicate backup servers to specific servers only.
3585 */
3586 while (srv) {
3587 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3588 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3589 /* we found the server and it's usable */
3590 t->flags &= ~SN_CK_MASK;
3591 t->flags |= SN_CK_VALID | SN_DIRECT;
3592 t->srv = srv;
3593 break;
willy tarreau12350152005-12-18 01:03:27 +01003594 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003595 /* we found a server, but it's down */
3596 t->flags &= ~SN_CK_MASK;
3597 t->flags |= SN_CK_DOWN;
3598 }
3599 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003600 srv = srv->next;
3601 }
3602
willy tarreau0174f312005-12-18 01:02:42 +01003603 if (!srv && !(t->flags & SN_CK_DOWN)) {
3604 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003605 t->flags &= ~SN_CK_MASK;
3606 t->flags |= SN_CK_INVALID;
3607 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003608
willy tarreau0174f312005-12-18 01:02:42 +01003609 /* depending on the cookie mode, we may have to either :
3610 * - delete the complete cookie if we're in insert+indirect mode, so that
3611 * the server never sees it ;
3612 * - remove the server id from the cookie value, and tag the cookie as an
3613 * application cookie so that it does not get accidentely removed later,
3614 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003615 */
willy tarreau0174f312005-12-18 01:02:42 +01003616 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3617 buffer_replace2(req, p3, delim + 1, NULL, 0);
3618 p4 -= (delim + 1 - p3);
3619 ptr -= (delim + 1 - p3);
3620 del_cookie = del_colon = NULL;
3621 app_cookies++; /* protect the header from deletion */
3622 }
3623 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003624 (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 +01003625 del_cookie = p1;
3626 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003627 }
willy tarreau12350152005-12-18 01:03:27 +01003628 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003629 /* now we know that we must keep this cookie since it's
3630 * not ours. But if we wanted to delete our cookie
3631 * earlier, we cannot remove the complete header, but we
3632 * can remove the previous block itself.
3633 */
3634 app_cookies++;
3635
3636 if (del_cookie != NULL) {
3637 buffer_replace2(req, del_cookie, p1, NULL, 0);
3638 p4 -= (p1 - del_cookie);
3639 ptr -= (p1 - del_cookie);
3640 del_cookie = del_colon = NULL;
3641 }
willy tarreau240afa62005-12-17 13:14:35 +01003642 }
willy tarreau12350152005-12-18 01:03:27 +01003643
3644 if ((t->proxy->appsession_name != NULL) &&
3645 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3646 /* first, let's see if the cookie is our appcookie*/
3647
3648 /* Cool... it's the right one */
3649
3650 asession_temp = &local_asession;
3651
3652 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3653 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3654 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3655 return 0;
3656 }
3657
3658 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3659 asession_temp->sessid[t->proxy->appsession_len] = 0;
3660 asession_temp->serverid = NULL;
3661
3662 /* only do insert, if lookup fails */
3663 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3664 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3665 Alert("Not enough memory process_cli():asession:calloc().\n");
3666 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3667 return 0;
3668 }
3669
3670 asession_temp->sessid = local_asession.sessid;
3671 asession_temp->serverid = local_asession.serverid;
3672 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3673 }
3674 else{
3675 /* free wasted memory */
3676 pool_free_to(apools.sessid, local_asession.sessid);
3677 }
3678
3679 if (asession_temp->serverid == NULL) {
3680 Alert("Found Application Session without matching server.\n");
3681 } else {
3682 struct server *srv = t->proxy->srv;
3683 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003684 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003685 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3686 /* we found the server and it's usable */
3687 t->flags &= ~SN_CK_MASK;
3688 t->flags |= SN_CK_VALID | SN_DIRECT;
3689 t->srv = srv;
3690 break;
3691 } else {
3692 t->flags &= ~SN_CK_MASK;
3693 t->flags |= SN_CK_DOWN;
3694 }
3695 }
3696 srv = srv->next;
3697 }/* end while(srv) */
3698 }/* end else if server == NULL */
3699
3700 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003701 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003702 }
willy tarreau240afa62005-12-17 13:14:35 +01003703
willy tarreau5cbea6f2005-12-17 12:48:26 +01003704 /* we'll have to look for another cookie ... */
3705 p1 = p4;
3706 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003707
3708 /* There's no more cookie on this line.
3709 * We may have marked the last one(s) for deletion.
3710 * We must do this now in two ways :
3711 * - if there is no app cookie, we simply delete the header ;
3712 * - if there are app cookies, we must delete the end of the
3713 * string properly, including the colon/semi-colon before
3714 * the cookie name.
3715 */
3716 if (del_cookie != NULL) {
3717 if (app_cookies) {
3718 buffer_replace2(req, del_colon, ptr, NULL, 0);
3719 /* WARNING! <ptr> becomes invalid for now. If some code
3720 * below needs to rely on it before the end of the global
3721 * header loop, we need to correct it with this code :
3722 * ptr = del_colon;
3723 */
3724 }
3725 else
3726 delete_header = 1;
3727 }
3728 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003729
3730 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003731 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003732 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003733 }
willy tarreau240afa62005-12-17 13:14:35 +01003734 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3735
willy tarreau5cbea6f2005-12-17 12:48:26 +01003736 req->h = req->lr;
3737 } /* while (req->lr < req->r) */
3738
3739 /* end of header processing (even if incomplete) */
3740
willy tarreauef900ab2005-12-17 12:52:52 +01003741 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3742 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3743 * full. We cannot loop here since event_cli_read will disable it only if
3744 * req->l == rlim-data
3745 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003746 FD_SET(t->cli_fd, StaticReadEvent);
3747 if (t->proxy->clitimeout)
3748 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3749 else
3750 tv_eternity(&t->crexpire);
3751 }
3752
willy tarreaue39cd132005-12-17 13:00:18 +01003753 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003754 * won't be able to free more later, so the session will never terminate.
3755 */
willy tarreaue39cd132005-12-17 13:00:18 +01003756 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003757 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003758 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003759 if (!(t->flags & SN_ERR_MASK))
3760 t->flags |= SN_ERR_PRXCOND;
3761 if (!(t->flags & SN_FINST_MASK))
3762 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003763 return 1;
3764 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003765 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003766 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003767 tv_eternity(&t->crexpire);
3768 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003769 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003770 if (!(t->flags & SN_ERR_MASK))
3771 t->flags |= SN_ERR_CLICL;
3772 if (!(t->flags & SN_FINST_MASK))
3773 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003774 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003775 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003776 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3777
3778 /* read timeout : give up with an error message.
3779 */
3780 t->logs.status = 408;
3781 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003782 if (!(t->flags & SN_ERR_MASK))
3783 t->flags |= SN_ERR_CLITO;
3784 if (!(t->flags & SN_FINST_MASK))
3785 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003786 return 1;
3787 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003788
3789 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003790 }
3791 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003792 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003793 /* FIXME: this error handling is partly buggy because we always report
3794 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3795 * or HEADER phase. BTW, it's not logical to expire the client while
3796 * we're waiting for the server to connect.
3797 */
willy tarreau0f7af912005-12-17 12:21:26 +01003798 /* read or write error */
3799 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003800 tv_eternity(&t->crexpire);
3801 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003802 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003803 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003804 if (!(t->flags & SN_ERR_MASK))
3805 t->flags |= SN_ERR_CLICL;
3806 if (!(t->flags & SN_FINST_MASK))
3807 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003808 return 1;
3809 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003810 /* last read, or end of server write */
3811 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003812 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003813 tv_eternity(&t->crexpire);
3814 shutdown(t->cli_fd, SHUT_RD);
3815 t->cli_state = CL_STSHUTR;
3816 return 1;
3817 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003818 /* last server read and buffer empty */
3819 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003820 FD_CLR(t->cli_fd, StaticWriteEvent);
3821 tv_eternity(&t->cwexpire);
3822 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003823 /* We must ensure that the read part is still alive when switching
3824 * to shutw */
3825 FD_SET(t->cli_fd, StaticReadEvent);
3826 if (t->proxy->clitimeout)
3827 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003828 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003829 //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 +01003830 return 1;
3831 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003832 /* read timeout */
3833 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3834 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003835 tv_eternity(&t->crexpire);
3836 shutdown(t->cli_fd, SHUT_RD);
3837 t->cli_state = CL_STSHUTR;
3838 if (!(t->flags & SN_ERR_MASK))
3839 t->flags |= SN_ERR_CLITO;
3840 if (!(t->flags & SN_FINST_MASK))
3841 t->flags |= SN_FINST_D;
3842 return 1;
3843 }
3844 /* write timeout */
3845 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3846 FD_CLR(t->cli_fd, StaticWriteEvent);
3847 tv_eternity(&t->cwexpire);
3848 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003849 /* We must ensure that the read part is still alive when switching
3850 * to shutw */
3851 FD_SET(t->cli_fd, StaticReadEvent);
3852 if (t->proxy->clitimeout)
3853 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3854
willy tarreau036e1ce2005-12-17 13:46:33 +01003855 t->cli_state = CL_STSHUTW;
3856 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003857 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003858 if (!(t->flags & SN_FINST_MASK))
3859 t->flags |= SN_FINST_D;
3860 return 1;
3861 }
willy tarreau0f7af912005-12-17 12:21:26 +01003862
willy tarreauc58fc692005-12-17 14:13:08 +01003863 if (req->l >= req->rlim - req->data) {
3864 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003865 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003866 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003867 FD_CLR(t->cli_fd, StaticReadEvent);
3868 tv_eternity(&t->crexpire);
3869 }
3870 }
3871 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003872 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003873 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3874 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003875 if (!t->proxy->clitimeout ||
3876 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3877 /* If the client has no timeout, or if the server not ready yet, and we
3878 * know for sure that it can expire, then it's cleaner to disable the
3879 * timeout on the client side so that too low values cannot make the
3880 * sessions abort too early.
3881 */
willy tarreau0f7af912005-12-17 12:21:26 +01003882 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003883 else
3884 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003885 }
3886 }
3887
3888 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003889 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003890 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3891 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3892 tv_eternity(&t->cwexpire);
3893 }
3894 }
3895 else { /* buffer not empty */
3896 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3897 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003898 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003899 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003900 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3901 t->crexpire = t->cwexpire;
3902 }
willy tarreau0f7af912005-12-17 12:21:26 +01003903 else
3904 tv_eternity(&t->cwexpire);
3905 }
3906 }
3907 return 0; /* other cases change nothing */
3908 }
3909 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003910 if (t->res_cw == RES_ERROR) {
3911 tv_eternity(&t->cwexpire);
3912 fd_delete(t->cli_fd);
3913 t->cli_state = CL_STCLOSE;
3914 if (!(t->flags & SN_ERR_MASK))
3915 t->flags |= SN_ERR_CLICL;
3916 if (!(t->flags & SN_FINST_MASK))
3917 t->flags |= SN_FINST_D;
3918 return 1;
3919 }
3920 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003921 tv_eternity(&t->cwexpire);
3922 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003923 t->cli_state = CL_STCLOSE;
3924 return 1;
3925 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003926 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3927 tv_eternity(&t->cwexpire);
3928 fd_delete(t->cli_fd);
3929 t->cli_state = CL_STCLOSE;
3930 if (!(t->flags & SN_ERR_MASK))
3931 t->flags |= SN_ERR_CLITO;
3932 if (!(t->flags & SN_FINST_MASK))
3933 t->flags |= SN_FINST_D;
3934 return 1;
3935 }
willy tarreau0f7af912005-12-17 12:21:26 +01003936 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003937 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003938 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3939 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3940 tv_eternity(&t->cwexpire);
3941 }
3942 }
3943 else { /* buffer not empty */
3944 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3945 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003946 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003947 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003948 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3949 t->crexpire = t->cwexpire;
3950 }
willy tarreau0f7af912005-12-17 12:21:26 +01003951 else
3952 tv_eternity(&t->cwexpire);
3953 }
3954 }
3955 return 0;
3956 }
3957 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003958 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003959 tv_eternity(&t->crexpire);
3960 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003961 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003962 if (!(t->flags & SN_ERR_MASK))
3963 t->flags |= SN_ERR_CLICL;
3964 if (!(t->flags & SN_FINST_MASK))
3965 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003966 return 1;
3967 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003968 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3969 tv_eternity(&t->crexpire);
3970 fd_delete(t->cli_fd);
3971 t->cli_state = CL_STCLOSE;
3972 return 1;
3973 }
3974 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3975 tv_eternity(&t->crexpire);
3976 fd_delete(t->cli_fd);
3977 t->cli_state = CL_STCLOSE;
3978 if (!(t->flags & SN_ERR_MASK))
3979 t->flags |= SN_ERR_CLITO;
3980 if (!(t->flags & SN_FINST_MASK))
3981 t->flags |= SN_FINST_D;
3982 return 1;
3983 }
willy tarreauef900ab2005-12-17 12:52:52 +01003984 else if (req->l >= req->rlim - req->data) {
3985 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003986
3987 /* FIXME-20050705: is it possible for a client to maintain a session
3988 * after the timeout by sending more data after it receives a close ?
3989 */
3990
willy tarreau0f7af912005-12-17 12:21:26 +01003991 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003992 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003993 FD_CLR(t->cli_fd, StaticReadEvent);
3994 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003995 //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 +01003996 }
3997 }
3998 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003999 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004000 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4001 FD_SET(t->cli_fd, StaticReadEvent);
4002 if (t->proxy->clitimeout)
4003 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4004 else
4005 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004006 //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 +01004007 }
4008 }
4009 return 0;
4010 }
4011 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004012 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004013 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004014 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 +01004015 write(1, trash, len);
4016 }
4017 return 0;
4018 }
4019 return 0;
4020}
4021
4022
4023/*
4024 * manages the server FSM and its socket. It returns 1 if a state has changed
4025 * (and a resync may be needed), 0 else.
4026 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004027int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004028 int s = t->srv_state;
4029 int c = t->cli_state;
4030 struct buffer *req = t->req;
4031 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004032 appsess *asession_temp = NULL;
4033 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004034 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004035
willy tarreau750a4722005-12-17 13:21:24 +01004036#ifdef DEBUG_FULL
4037 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4038#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004039 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4040 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4041 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4042 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004043 if (s == SV_STIDLE) {
4044 if (c == CL_STHEADERS)
4045 return 0; /* stay in idle, waiting for data to reach the client side */
4046 else if (c == CL_STCLOSE ||
4047 c == CL_STSHUTW ||
4048 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4049 tv_eternity(&t->cnexpire);
4050 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004051 if (!(t->flags & SN_ERR_MASK))
4052 t->flags |= SN_ERR_CLICL;
4053 if (!(t->flags & SN_FINST_MASK))
4054 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004055 return 1;
4056 }
4057 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004058 /* initiate a connection to the server */
4059 conn_err = connect_server(t);
4060 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004061 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4062 t->srv_state = SV_STCONN;
4063 }
4064 else { /* try again */
4065 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004066 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004067 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004068 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004069 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4070 t->flags &= ~SN_CK_MASK;
4071 t->flags |= SN_CK_DOWN;
4072 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004073 }
4074
willy tarreaub1285d52005-12-18 01:20:14 +01004075 conn_err = connect_server(t);
4076 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004077 t->srv_state = SV_STCONN;
4078 break;
4079 }
4080 }
4081 if (t->conn_retries < 0) {
4082 /* if conn_retries < 0 or other error, let's abort */
4083 tv_eternity(&t->cnexpire);
4084 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004085 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004086 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004087 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004088 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004089 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004090 if (!(t->flags & SN_FINST_MASK))
4091 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004092 }
4093 }
4094 return 1;
4095 }
4096 }
4097 else if (s == SV_STCONN) { /* connection in progress */
4098 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004099 //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 +01004100 return 0; /* nothing changed */
4101 }
4102 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4103 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4104 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004105 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004106 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004107 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004108 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004109 if (t->conn_retries >= 0) {
4110 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004111 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004112 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004113 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4114 t->flags &= ~SN_CK_MASK;
4115 t->flags |= SN_CK_DOWN;
4116 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004117 }
willy tarreaub1285d52005-12-18 01:20:14 +01004118 conn_err = connect_server(t);
4119 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004120 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004121 }
willy tarreaub1285d52005-12-18 01:20:14 +01004122 else if (t->res_sw == RES_SILENT)
4123 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4124 else
4125 conn_err = SN_ERR_SRVCL; // it was a connect error.
4126
willy tarreau0f7af912005-12-17 12:21:26 +01004127 /* if conn_retries < 0 or other error, let's abort */
4128 tv_eternity(&t->cnexpire);
4129 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004130 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004131 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004132 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004133 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004134 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004135 if (!(t->flags & SN_FINST_MASK))
4136 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004137 return 1;
4138 }
4139 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004140 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004141
willy tarreau0f7af912005-12-17 12:21:26 +01004142 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004143 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004144 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004145 tv_eternity(&t->swexpire);
4146 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004147 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004148 if (t->proxy->srvtimeout) {
4149 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4150 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4151 t->srexpire = t->swexpire;
4152 }
4153 else
4154 tv_eternity(&t->swexpire);
4155 }
willy tarreau0f7af912005-12-17 12:21:26 +01004156
4157 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4158 FD_SET(t->srv_fd, StaticReadEvent);
4159 if (t->proxy->srvtimeout)
4160 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4161 else
4162 tv_eternity(&t->srexpire);
4163
4164 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004165 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004166
4167 /* if the user wants to log as soon as possible, without counting
4168 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004169 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004170 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4171 sess_log(t);
4172 }
willy tarreau0f7af912005-12-17 12:21:26 +01004173 }
willy tarreauef900ab2005-12-17 12:52:52 +01004174 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004175 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004176 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4177 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004178 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004179 return 1;
4180 }
4181 }
4182 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004183 /* now parse the partial (or complete) headers */
4184 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4185 char *ptr;
4186 int delete_header;
4187
4188 ptr = rep->lr;
4189
4190 /* look for the end of the current header */
4191 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4192 ptr++;
4193
4194 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004195 int line, len;
4196
4197 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004198
4199 /* first, we'll block if security checks have caught nasty things */
4200 if (t->flags & SN_CACHEABLE) {
4201 if ((t->flags & SN_CACHE_COOK) &&
4202 (t->flags & SN_SCK_ANY) &&
4203 (t->proxy->options & PR_O_CHK_CACHE)) {
4204
4205 /* we're in presence of a cacheable response containing
4206 * a set-cookie header. We'll block it as requested by
4207 * the 'checkcache' option, and send an alert.
4208 */
4209 tv_eternity(&t->srexpire);
4210 tv_eternity(&t->swexpire);
4211 fd_delete(t->srv_fd);
4212 t->srv_state = SV_STCLOSE;
4213 t->logs.status = 502;
4214 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4215 if (!(t->flags & SN_ERR_MASK))
4216 t->flags |= SN_ERR_PRXCOND;
4217 if (!(t->flags & SN_FINST_MASK))
4218 t->flags |= SN_FINST_H;
4219
4220 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4221 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4222
4223 return 1;
4224 }
4225 }
4226
willy tarreau982249e2005-12-18 00:57:06 +01004227 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4228 if (t->flags & SN_SVDENY) {
4229 tv_eternity(&t->srexpire);
4230 tv_eternity(&t->swexpire);
4231 fd_delete(t->srv_fd);
4232 t->srv_state = SV_STCLOSE;
4233 t->logs.status = 502;
4234 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4235 if (!(t->flags & SN_ERR_MASK))
4236 t->flags |= SN_ERR_PRXCOND;
4237 if (!(t->flags & SN_FINST_MASK))
4238 t->flags |= SN_FINST_H;
4239 return 1;
4240 }
4241
willy tarreau5cbea6f2005-12-17 12:48:26 +01004242 /* we'll have something else to do here : add new headers ... */
4243
willy tarreaucd878942005-12-17 13:27:43 +01004244 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4245 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004246 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004247 * insert a set-cookie here, except if we want to insert only on POST
4248 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004249 */
willy tarreau750a4722005-12-17 13:21:24 +01004250 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004251 t->proxy->cookie_name,
4252 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004253
willy tarreau036e1ce2005-12-17 13:46:33 +01004254 t->flags |= SN_SCK_INSERTED;
4255
willy tarreau750a4722005-12-17 13:21:24 +01004256 /* Here, we will tell an eventual cache on the client side that we don't
4257 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4258 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4259 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4260 */
willy tarreau240afa62005-12-17 13:14:35 +01004261 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004262 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4263 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004264
4265 if (rep->data + rep->l < rep->h)
4266 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4267 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004268 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004269 }
4270
4271 /* headers to be added */
4272 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004273 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4274 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004275 }
4276
willy tarreau25c4ea52005-12-18 00:49:49 +01004277 /* add a "connection: close" line if needed */
4278 if (t->proxy->options & PR_O_HTTP_CLOSE)
4279 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4280
willy tarreau5cbea6f2005-12-17 12:48:26 +01004281 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004282 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004283 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004284
Willy TARREAU767ba712006-03-01 22:40:50 +01004285 /* client connection already closed or option 'httpclose' required :
4286 * we close the server's outgoing connection right now.
4287 */
4288 if ((req->l == 0) &&
4289 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4290 FD_CLR(t->srv_fd, StaticWriteEvent);
4291 tv_eternity(&t->swexpire);
4292
4293 /* We must ensure that the read part is still alive when switching
4294 * to shutw */
4295 FD_SET(t->srv_fd, StaticReadEvent);
4296 if (t->proxy->srvtimeout)
4297 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4298
4299 shutdown(t->srv_fd, SHUT_WR);
4300 t->srv_state = SV_STSHUTW;
4301 }
4302
willy tarreau25c4ea52005-12-18 00:49:49 +01004303 /* if the user wants to log as soon as possible, without counting
4304 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004305 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004306 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4307 t->logs.bytes = rep->h - rep->data;
4308 sess_log(t);
4309 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004310 break;
4311 }
4312
4313 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4314 if (ptr > rep->r - 2) {
4315 /* this is a partial header, let's wait for more to come */
4316 rep->lr = ptr;
4317 break;
4318 }
4319
4320 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4321 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4322
4323 /* now we know that *ptr is either \r or \n,
4324 * and that there are at least 1 char after it.
4325 */
4326 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4327 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4328 else
4329 rep->lr = ptr + 2; /* \r\n or \n\r */
4330
4331 /*
4332 * now we know that we have a full header ; we can do whatever
4333 * we want with these pointers :
4334 * rep->h = beginning of header
4335 * ptr = end of header (first \r or \n)
4336 * rep->lr = beginning of next line (next rep->h)
4337 * rep->r = end of data (not used at this stage)
4338 */
4339
willy tarreaua1598082005-12-17 13:08:06 +01004340
willy tarreau982249e2005-12-18 00:57:06 +01004341 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004342 t->logs.logwait &= ~LW_RESP;
4343 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004344 switch (t->logs.status) {
4345 case 200:
4346 case 203:
4347 case 206:
4348 case 300:
4349 case 301:
4350 case 410:
4351 /* RFC2616 @13.4:
4352 * "A response received with a status code of
4353 * 200, 203, 206, 300, 301 or 410 MAY be stored
4354 * by a cache (...) unless a cache-control
4355 * directive prohibits caching."
4356 *
4357 * RFC2616 @9.5: POST method :
4358 * "Responses to this method are not cacheable,
4359 * unless the response includes appropriate
4360 * Cache-Control or Expires header fields."
4361 */
4362 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4363 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4364 break;
4365 default:
4366 break;
4367 }
willy tarreau4302f492005-12-18 01:00:37 +01004368 }
4369 else if (t->logs.logwait & LW_RSPHDR) {
4370 struct cap_hdr *h;
4371 int len;
4372 for (h = t->proxy->rsp_cap; h; h = h->next) {
4373 if ((h->namelen + 2 <= ptr - rep->h) &&
4374 (rep->h[h->namelen] == ':') &&
4375 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4376
4377 if (t->rsp_cap[h->index] == NULL)
4378 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4379
4380 len = ptr - (rep->h + h->namelen + 2);
4381 if (len > h->len)
4382 len = h->len;
4383
4384 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4385 t->rsp_cap[h->index][len]=0;
4386 }
4387 }
4388
willy tarreaua1598082005-12-17 13:08:06 +01004389 }
4390
willy tarreau5cbea6f2005-12-17 12:48:26 +01004391 delete_header = 0;
4392
willy tarreau982249e2005-12-18 00:57:06 +01004393 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004394 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004395 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 +01004396 max = ptr - rep->h;
4397 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004398 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004399 trash[len++] = '\n';
4400 write(1, trash, len);
4401 }
4402
willy tarreau25c4ea52005-12-18 00:49:49 +01004403 /* remove "connection: " if needed */
4404 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4405 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4406 delete_header = 1;
4407 }
4408
willy tarreau5cbea6f2005-12-17 12:48:26 +01004409 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004410 if (!delete_header && t->proxy->rsp_exp != NULL
4411 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004412 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004413 char term;
4414
4415 term = *ptr;
4416 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004417 exp = t->proxy->rsp_exp;
4418 do {
4419 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4420 switch (exp->action) {
4421 case ACT_ALLOW:
4422 if (!(t->flags & SN_SVDENY))
4423 t->flags |= SN_SVALLOW;
4424 break;
4425 case ACT_REPLACE:
4426 if (!(t->flags & SN_SVDENY)) {
4427 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4428 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4429 }
4430 break;
4431 case ACT_REMOVE:
4432 if (!(t->flags & SN_SVDENY))
4433 delete_header = 1;
4434 break;
4435 case ACT_DENY:
4436 if (!(t->flags & SN_SVALLOW))
4437 t->flags |= SN_SVDENY;
4438 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004439 case ACT_PASS: /* we simply don't deny this one */
4440 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004441 }
4442 break;
4443 }
willy tarreaue39cd132005-12-17 13:00:18 +01004444 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004445 *ptr = term; /* restore the string terminator */
4446 }
4447
willy tarreau97f58572005-12-18 00:53:44 +01004448 /* check for cache-control: or pragma: headers */
4449 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4450 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4451 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4452 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4453 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004454 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004455 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4456 else {
4457 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004458 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004459 t->flags &= ~SN_CACHE_COOK;
4460 }
4461 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004462 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004463 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004464 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004465 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4466 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004467 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004468 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004469 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4470 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4471 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4472 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4473 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4474 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004475 }
4476 }
4477 }
4478
willy tarreau5cbea6f2005-12-17 12:48:26 +01004479 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004480 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004481 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004482 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004483 char *p1, *p2, *p3, *p4;
4484
willy tarreau97f58572005-12-18 00:53:44 +01004485 t->flags |= SN_SCK_ANY;
4486
willy tarreau5cbea6f2005-12-17 12:48:26 +01004487 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4488
4489 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004490 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004491 p1++;
4492
4493 if (p1 == ptr || *p1 == ';') /* end of cookie */
4494 break;
4495
4496 /* p1 is at the beginning of the cookie name */
4497 p2 = p1;
4498
4499 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4500 p2++;
4501
4502 if (p2 == ptr || *p2 == ';') /* next cookie */
4503 break;
4504
4505 p3 = p2 + 1; /* skips the '=' sign */
4506 if (p3 == ptr)
4507 break;
4508
4509 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004510 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004511 p4++;
4512
4513 /* here, we have the cookie name between p1 and p2,
4514 * and its value between p3 and p4.
4515 * we can process it.
4516 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004517
4518 /* first, let's see if we want to capture it */
4519 if (t->proxy->capture_name != NULL &&
4520 t->logs.srv_cookie == NULL &&
4521 (p4 - p1 >= t->proxy->capture_namelen) &&
4522 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4523 int log_len = p4 - p1;
4524
4525 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4526 Alert("HTTP logging : out of memory.\n");
4527 }
4528
4529 if (log_len > t->proxy->capture_len)
4530 log_len = t->proxy->capture_len;
4531 memcpy(t->logs.srv_cookie, p1, log_len);
4532 t->logs.srv_cookie[log_len] = 0;
4533 }
4534
4535 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4536 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004537 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004538 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004539
4540 /* If the cookie is in insert mode on a known server, we'll delete
4541 * this occurrence because we'll insert another one later.
4542 * We'll delete it too if the "indirect" option is set and we're in
4543 * a direct access. */
4544 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004545 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004546 /* this header must be deleted */
4547 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004548 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004549 }
4550 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4551 /* replace bytes p3->p4 with the cookie name associated
4552 * with this server since we know it.
4553 */
4554 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004555 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004556 }
willy tarreau0174f312005-12-18 01:02:42 +01004557 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4558 /* insert the cookie name associated with this server
4559 * before existing cookie, and insert a delimitor between them..
4560 */
4561 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4562 p3[t->srv->cklen] = COOKIE_DELIM;
4563 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4564 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004565 break;
4566 }
willy tarreau12350152005-12-18 01:03:27 +01004567
4568 /* first, let's see if the cookie is our appcookie*/
4569 if ((t->proxy->appsession_name != NULL) &&
4570 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4571
4572 /* Cool... it's the right one */
4573
willy tarreaub952e1d2005-12-18 01:31:20 +01004574 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004575 asession_temp = &local_asession;
4576
willy tarreaub952e1d2005-12-18 01:31:20 +01004577 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004578 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4579 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4580 }
4581 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4582 asession_temp->sessid[t->proxy->appsession_len] = 0;
4583 asession_temp->serverid = NULL;
4584
4585 /* only do insert, if lookup fails */
4586 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4587 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4588 Alert("Not enought Memory process_srv():asession:calloc().\n");
4589 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4590 return 0;
4591 }
4592 asession_temp->sessid = local_asession.sessid;
4593 asession_temp->serverid = local_asession.serverid;
4594 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004595 }/* end if (chtbl_lookup()) */
4596 else {
willy tarreau12350152005-12-18 01:03:27 +01004597 /* free wasted memory */
4598 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004599 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004600
willy tarreaub952e1d2005-12-18 01:31:20 +01004601 if (asession_temp->serverid == NULL) {
4602 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004603 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4604 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4605 }
4606 asession_temp->serverid[0] = '\0';
4607 }
4608
willy tarreaub952e1d2005-12-18 01:31:20 +01004609 if (asession_temp->serverid[0] == '\0')
4610 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004611
4612 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4613
4614#if defined(DEBUG_HASH)
4615 print_table(&(t->proxy->htbl_proxy));
4616#endif
4617 break;
4618 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004619 else {
4620 // fprintf(stderr,"Ignoring unknown cookie : ");
4621 // write(2, p1, p2-p1);
4622 // fprintf(stderr," = ");
4623 // write(2, p3, p4-p3);
4624 // fprintf(stderr,"\n");
4625 }
4626 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4627 } /* we're now at the end of the cookie value */
4628 } /* end of cookie processing */
4629
willy tarreau97f58572005-12-18 00:53:44 +01004630 /* check for any set-cookie in case we check for cacheability */
4631 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4632 (t->proxy->options & PR_O_CHK_CACHE) &&
4633 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4634 t->flags |= SN_SCK_ANY;
4635 }
4636
willy tarreau5cbea6f2005-12-17 12:48:26 +01004637 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004638 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004639 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004640
willy tarreau5cbea6f2005-12-17 12:48:26 +01004641 rep->h = rep->lr;
4642 } /* while (rep->lr < rep->r) */
4643
4644 /* end of header processing (even if incomplete) */
4645
willy tarreauef900ab2005-12-17 12:52:52 +01004646 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4647 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4648 * full. We cannot loop here since event_srv_read will disable it only if
4649 * rep->l == rlim-data
4650 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004651 FD_SET(t->srv_fd, StaticReadEvent);
4652 if (t->proxy->srvtimeout)
4653 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4654 else
4655 tv_eternity(&t->srexpire);
4656 }
willy tarreau0f7af912005-12-17 12:21:26 +01004657
willy tarreau8337c6b2005-12-17 13:41:01 +01004658 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004659 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004660 tv_eternity(&t->srexpire);
4661 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004662 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004663 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004664 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004665 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004666 if (!(t->flags & SN_ERR_MASK))
4667 t->flags |= SN_ERR_SRVCL;
4668 if (!(t->flags & SN_FINST_MASK))
4669 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004670 return 1;
4671 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004672 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004673 * since we are in header mode, if there's no space left for headers, we
4674 * won't be able to free more later, so the session will never terminate.
4675 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004676 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 +01004677 FD_CLR(t->srv_fd, StaticReadEvent);
4678 tv_eternity(&t->srexpire);
4679 shutdown(t->srv_fd, SHUT_RD);
4680 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004681 //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 +01004682 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004683 }
4684 /* read timeout : return a 504 to the client.
4685 */
4686 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4687 tv_eternity(&t->srexpire);
4688 tv_eternity(&t->swexpire);
4689 fd_delete(t->srv_fd);
4690 t->srv_state = SV_STCLOSE;
4691 t->logs.status = 504;
4692 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004693 if (!(t->flags & SN_ERR_MASK))
4694 t->flags |= SN_ERR_SRVTO;
4695 if (!(t->flags & SN_FINST_MASK))
4696 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004697 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004698
4699 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004700 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004701 /* FIXME!!! here, we don't want to switch to SHUTW if the
4702 * client shuts read too early, because we may still have
4703 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004704 * The side-effect is that if the client completely closes its
4705 * connection during SV_STHEADER, the connection to the server
4706 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004707 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004708 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004709 FD_CLR(t->srv_fd, StaticWriteEvent);
4710 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004711
4712 /* We must ensure that the read part is still alive when switching
4713 * to shutw */
4714 FD_SET(t->srv_fd, StaticReadEvent);
4715 if (t->proxy->srvtimeout)
4716 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4717
willy tarreau0f7af912005-12-17 12:21:26 +01004718 shutdown(t->srv_fd, SHUT_WR);
4719 t->srv_state = SV_STSHUTW;
4720 return 1;
4721 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004722 /* write timeout */
4723 /* FIXME!!! here, we don't want to switch to SHUTW if the
4724 * client shuts read too early, because we may still have
4725 * some work to do on the headers.
4726 */
4727 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4728 FD_CLR(t->srv_fd, StaticWriteEvent);
4729 tv_eternity(&t->swexpire);
4730 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004731 /* We must ensure that the read part is still alive when switching
4732 * to shutw */
4733 FD_SET(t->srv_fd, StaticReadEvent);
4734 if (t->proxy->srvtimeout)
4735 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4736
4737 /* We must ensure that the read part is still alive when switching
4738 * to shutw */
4739 FD_SET(t->srv_fd, StaticReadEvent);
4740 if (t->proxy->srvtimeout)
4741 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4742
willy tarreau036e1ce2005-12-17 13:46:33 +01004743 t->srv_state = SV_STSHUTW;
4744 if (!(t->flags & SN_ERR_MASK))
4745 t->flags |= SN_ERR_SRVTO;
4746 if (!(t->flags & SN_FINST_MASK))
4747 t->flags |= SN_FINST_H;
4748 return 1;
4749 }
willy tarreau0f7af912005-12-17 12:21:26 +01004750
4751 if (req->l == 0) {
4752 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4753 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4754 tv_eternity(&t->swexpire);
4755 }
4756 }
4757 else { /* client buffer not empty */
4758 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4759 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004760 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004761 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004762 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4763 t->srexpire = t->swexpire;
4764 }
willy tarreau0f7af912005-12-17 12:21:26 +01004765 else
4766 tv_eternity(&t->swexpire);
4767 }
4768 }
4769
willy tarreau5cbea6f2005-12-17 12:48:26 +01004770 /* be nice with the client side which would like to send a complete header
4771 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4772 * would read all remaining data at once ! The client should not write past rep->lr
4773 * when the server is in header state.
4774 */
4775 //return header_processed;
4776 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004777 }
4778 else if (s == SV_STDATA) {
4779 /* read or write error */
4780 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004781 tv_eternity(&t->srexpire);
4782 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004783 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004784 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004785 if (!(t->flags & SN_ERR_MASK))
4786 t->flags |= SN_ERR_SRVCL;
4787 if (!(t->flags & SN_FINST_MASK))
4788 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004789 return 1;
4790 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004791 /* last read, or end of client write */
4792 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004793 FD_CLR(t->srv_fd, StaticReadEvent);
4794 tv_eternity(&t->srexpire);
4795 shutdown(t->srv_fd, SHUT_RD);
4796 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004797 //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 +01004798 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004799 }
4800 /* end of client read and no more data to send */
4801 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4802 FD_CLR(t->srv_fd, StaticWriteEvent);
4803 tv_eternity(&t->swexpire);
4804 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004805 /* We must ensure that the read part is still alive when switching
4806 * to shutw */
4807 FD_SET(t->srv_fd, StaticReadEvent);
4808 if (t->proxy->srvtimeout)
4809 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4810
willy tarreaua41a8b42005-12-17 14:02:24 +01004811 t->srv_state = SV_STSHUTW;
4812 return 1;
4813 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004814 /* read timeout */
4815 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4816 FD_CLR(t->srv_fd, StaticReadEvent);
4817 tv_eternity(&t->srexpire);
4818 shutdown(t->srv_fd, SHUT_RD);
4819 t->srv_state = SV_STSHUTR;
4820 if (!(t->flags & SN_ERR_MASK))
4821 t->flags |= SN_ERR_SRVTO;
4822 if (!(t->flags & SN_FINST_MASK))
4823 t->flags |= SN_FINST_D;
4824 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004825 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004826 /* write timeout */
4827 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004828 FD_CLR(t->srv_fd, StaticWriteEvent);
4829 tv_eternity(&t->swexpire);
4830 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004831 /* We must ensure that the read part is still alive when switching
4832 * to shutw */
4833 FD_SET(t->srv_fd, StaticReadEvent);
4834 if (t->proxy->srvtimeout)
4835 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004836 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004837 if (!(t->flags & SN_ERR_MASK))
4838 t->flags |= SN_ERR_SRVTO;
4839 if (!(t->flags & SN_FINST_MASK))
4840 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004841 return 1;
4842 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004843
4844 /* recompute request time-outs */
4845 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004846 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4847 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4848 tv_eternity(&t->swexpire);
4849 }
4850 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004851 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004852 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4853 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004854 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004855 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004856 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4857 t->srexpire = t->swexpire;
4858 }
willy tarreau0f7af912005-12-17 12:21:26 +01004859 else
4860 tv_eternity(&t->swexpire);
4861 }
4862 }
4863
willy tarreaub1ff9db2005-12-17 13:51:03 +01004864 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004865 if (rep->l == BUFSIZE) { /* no room to read more data */
4866 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4867 FD_CLR(t->srv_fd, StaticReadEvent);
4868 tv_eternity(&t->srexpire);
4869 }
4870 }
4871 else {
4872 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4873 FD_SET(t->srv_fd, StaticReadEvent);
4874 if (t->proxy->srvtimeout)
4875 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4876 else
4877 tv_eternity(&t->srexpire);
4878 }
4879 }
4880
4881 return 0; /* other cases change nothing */
4882 }
4883 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004884 if (t->res_sw == RES_ERROR) {
4885 //FD_CLR(t->srv_fd, StaticWriteEvent);
4886 tv_eternity(&t->swexpire);
4887 fd_delete(t->srv_fd);
4888 //close(t->srv_fd);
4889 t->srv_state = SV_STCLOSE;
4890 if (!(t->flags & SN_ERR_MASK))
4891 t->flags |= SN_ERR_SRVCL;
4892 if (!(t->flags & SN_FINST_MASK))
4893 t->flags |= SN_FINST_D;
4894 return 1;
4895 }
4896 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004897 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004898 tv_eternity(&t->swexpire);
4899 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004900 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004901 t->srv_state = SV_STCLOSE;
4902 return 1;
4903 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004904 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4905 //FD_CLR(t->srv_fd, StaticWriteEvent);
4906 tv_eternity(&t->swexpire);
4907 fd_delete(t->srv_fd);
4908 //close(t->srv_fd);
4909 t->srv_state = SV_STCLOSE;
4910 if (!(t->flags & SN_ERR_MASK))
4911 t->flags |= SN_ERR_SRVTO;
4912 if (!(t->flags & SN_FINST_MASK))
4913 t->flags |= SN_FINST_D;
4914 return 1;
4915 }
willy tarreau0f7af912005-12-17 12:21:26 +01004916 else if (req->l == 0) {
4917 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4918 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4919 tv_eternity(&t->swexpire);
4920 }
4921 }
4922 else { /* buffer not empty */
4923 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4924 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004925 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004926 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004927 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4928 t->srexpire = t->swexpire;
4929 }
willy tarreau0f7af912005-12-17 12:21:26 +01004930 else
4931 tv_eternity(&t->swexpire);
4932 }
4933 }
4934 return 0;
4935 }
4936 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004937 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004938 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004939 tv_eternity(&t->srexpire);
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;
willy tarreau036e1ce2005-12-17 13:46:33 +01004943 if (!(t->flags & SN_ERR_MASK))
4944 t->flags |= SN_ERR_SRVCL;
4945 if (!(t->flags & SN_FINST_MASK))
4946 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004947 return 1;
4948 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004949 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4950 //FD_CLR(t->srv_fd, StaticReadEvent);
4951 tv_eternity(&t->srexpire);
4952 fd_delete(t->srv_fd);
4953 //close(t->srv_fd);
4954 t->srv_state = SV_STCLOSE;
4955 return 1;
4956 }
4957 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4958 //FD_CLR(t->srv_fd, StaticReadEvent);
4959 tv_eternity(&t->srexpire);
4960 fd_delete(t->srv_fd);
4961 //close(t->srv_fd);
4962 t->srv_state = SV_STCLOSE;
4963 if (!(t->flags & SN_ERR_MASK))
4964 t->flags |= SN_ERR_SRVTO;
4965 if (!(t->flags & SN_FINST_MASK))
4966 t->flags |= SN_FINST_D;
4967 return 1;
4968 }
willy tarreau0f7af912005-12-17 12:21:26 +01004969 else if (rep->l == BUFSIZE) { /* no room to read more data */
4970 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4971 FD_CLR(t->srv_fd, StaticReadEvent);
4972 tv_eternity(&t->srexpire);
4973 }
4974 }
4975 else {
4976 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4977 FD_SET(t->srv_fd, StaticReadEvent);
4978 if (t->proxy->srvtimeout)
4979 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4980 else
4981 tv_eternity(&t->srexpire);
4982 }
4983 }
4984 return 0;
4985 }
4986 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004987 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004988 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004989 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 +01004990 write(1, trash, len);
4991 }
4992 return 0;
4993 }
4994 return 0;
4995}
4996
4997
willy tarreau5cbea6f2005-12-17 12:48:26 +01004998/* Processes the client and server jobs of a session task, then
4999 * puts it back to the wait queue in a clean state, or
5000 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005001 * the time the task accepts to wait, or TIME_ETERNITY for
5002 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005003 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005004int process_session(struct task *t) {
5005 struct session *s = t->context;
5006 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005007
willy tarreau5cbea6f2005-12-17 12:48:26 +01005008 do {
5009 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005010 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005011 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005012 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005013 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005014 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005015 } while (fsm_resync);
5016
5017 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005018 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005019 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005020
willy tarreau5cbea6f2005-12-17 12:48:26 +01005021 tv_min(&min1, &s->crexpire, &s->cwexpire);
5022 tv_min(&min2, &s->srexpire, &s->swexpire);
5023 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005024 tv_min(&t->expire, &min1, &min2);
5025
5026 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005027 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005028
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005029#ifdef DEBUG_FULL
5030 /* DEBUG code : this should never ever happen, otherwise it indicates
5031 * that a task still has something to do and will provoke a quick loop.
5032 */
5033 if (tv_remain2(&now, &t->expire) <= 0)
5034 exit(100);
5035#endif
5036
willy tarreaub952e1d2005-12-18 01:31:20 +01005037 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005038 }
5039
willy tarreau5cbea6f2005-12-17 12:48:26 +01005040 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005041 actconn--;
5042
willy tarreau982249e2005-12-18 00:57:06 +01005043 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005044 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005045 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 +01005046 write(1, trash, len);
5047 }
5048
willy tarreau750a4722005-12-17 13:21:24 +01005049 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005050 if (s->rep != NULL)
5051 s->logs.bytes = s->rep->total;
5052
willy tarreau9fe663a2005-12-17 13:02:59 +01005053 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005054 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005055 sess_log(s);
5056
willy tarreau0f7af912005-12-17 12:21:26 +01005057 /* the task MUST not be in the run queue anymore */
5058 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005059 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005060 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005061 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005062}
5063
5064
5065
5066/*
5067 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005068 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005069 */
5070int process_chk(struct task *t) {
5071 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005072 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005073 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005074
willy tarreauef900ab2005-12-17 12:52:52 +01005075 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005076
willy tarreau25424f82006-03-19 19:37:48 +01005077 new_chk:
5078 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005079 if (fd < 0) { /* no check currently running */
5080 //fprintf(stderr, "process_chk: 2\n");
5081 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5082 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005083 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005084 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005085
5086 /* we don't send any health-checks when the proxy is stopped or when
5087 * the server should not be checked.
5088 */
5089 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005090 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5091 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005092 task_queue(t); /* restore t to its place in the task list */
5093 return tv_remain2(&now, &t->expire);
5094 }
5095
willy tarreau5cbea6f2005-12-17 12:48:26 +01005096 /* we'll initiate a new check */
5097 s->result = 0; /* no result yet */
5098 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005099 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005100 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5101 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5102 //fprintf(stderr, "process_chk: 3\n");
5103
willy tarreaua41a8b42005-12-17 14:02:24 +01005104 /* we'll connect to the check port on the server */
5105 sa = s->addr;
5106 sa.sin_port = htons(s->check_port);
5107
willy tarreau0174f312005-12-18 01:02:42 +01005108 /* allow specific binding :
5109 * - server-specific at first
5110 * - proxy-specific next
5111 */
5112 if (s->state & SRV_BIND_SRC) {
5113 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5114 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5115 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5116 s->proxy->id, s->id);
5117 s->result = -1;
5118 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005119 }
willy tarreau0174f312005-12-18 01:02:42 +01005120 else if (s->proxy->options & PR_O_BIND_SRC) {
5121 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5122 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5123 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5124 s->proxy->id);
5125 s->result = -1;
5126 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005127 }
willy tarreau0174f312005-12-18 01:02:42 +01005128
5129 if (!s->result) {
5130 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5131 /* OK, connection in progress or established */
5132
5133 //fprintf(stderr, "process_chk: 4\n");
5134
5135 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5136 fdtab[fd].owner = t;
5137 fdtab[fd].read = &event_srv_chk_r;
5138 fdtab[fd].write = &event_srv_chk_w;
5139 fdtab[fd].state = FD_STCONN; /* connection in progress */
5140 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005141#ifdef DEBUG_FULL
5142 assert (!FD_ISSET(fd, StaticReadEvent));
5143#endif
willy tarreau0174f312005-12-18 01:02:42 +01005144 fd_insert(fd);
5145 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5146 tv_delayfrom(&t->expire, &now, s->inter);
5147 task_queue(t); /* restore t to its place in the task list */
5148 return tv_remain(&now, &t->expire);
5149 }
5150 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5151 s->result = -1; /* a real error */
5152 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005153 }
5154 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005155 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005156 }
5157
5158 if (!s->result) { /* nothing done */
5159 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005160 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5161 tv_delayfrom(&t->expire, &t->expire, s->inter);
5162 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005163 }
5164
5165 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005166 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005167 s->health--; /* still good */
5168 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005169 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005170 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005171 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005172 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005173
willy tarreaudd07e972005-12-18 00:48:48 +01005174 if (find_server(s->proxy) == NULL) {
5175 Alert("Proxy %s has no server available !\n", s->proxy->id);
5176 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5177 }
5178 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005179 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005180 }
5181
5182 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005183 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005184 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5185 tv_delayfrom(&t->expire, &t->expire, s->inter);
5186 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005187 }
5188 else {
5189 //fprintf(stderr, "process_chk: 8\n");
5190 /* there was a test running */
5191 if (s->result > 0) { /* good server detected */
5192 //fprintf(stderr, "process_chk: 9\n");
5193 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005194 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005195 if (s->health == s->rise) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005196 Warning("Server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005197 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005198 }
willy tarreauef900ab2005-12-17 12:52:52 +01005199
willy tarreaue47c8d72005-12-17 12:55:52 +01005200 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005201 s->state |= SRV_RUNNING;
5202 }
willy tarreauef900ab2005-12-17 12:52:52 +01005203 s->curfd = -1; /* no check running anymore */
5204 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005205 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005206 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5207 tv_delayfrom(&t->expire, &t->expire, s->inter);
5208 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005209 }
5210 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5211 //fprintf(stderr, "process_chk: 10\n");
5212 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005213 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005214 s->health--; /* still good */
5215 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005216 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005217
willy tarreaudd07e972005-12-18 00:48:48 +01005218 if (s->health == s->rise) {
5219 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005220 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005221
5222 if (find_server(s->proxy) == NULL) {
5223 Alert("Proxy %s has no server available !\n", s->proxy->id);
5224 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5225 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005226 }
willy tarreauef900ab2005-12-17 12:52:52 +01005227
willy tarreau5cbea6f2005-12-17 12:48:26 +01005228 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005229 }
5230 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005231 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005232 fd_delete(fd);
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 /* if result is 0 and there's no timeout, we have to wait again */
5238 }
5239 //fprintf(stderr, "process_chk: 11\n");
5240 s->result = 0;
5241 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005242 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005243}
5244
5245
willy tarreau5cbea6f2005-12-17 12:48:26 +01005246
willy tarreau0f7af912005-12-17 12:21:26 +01005247#if STATTIME > 0
5248int stats(void);
5249#endif
5250
5251/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005252 * This does 4 things :
5253 * - wake up all expired tasks
5254 * - call all runnable tasks
5255 * - call maintain_proxies() to enable/disable the listeners
5256 * - return the delay till next event in ms, -1 = wait indefinitely
5257 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5258 *
willy tarreau0f7af912005-12-17 12:21:26 +01005259 */
5260
willy tarreau1c2ad212005-12-18 01:11:29 +01005261int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005262 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005263 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005264 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005265
willy tarreaub952e1d2005-12-18 01:31:20 +01005266 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005267
willy tarreau1c2ad212005-12-18 01:11:29 +01005268 /* look for expired tasks and add them to the run queue.
5269 */
5270 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5271 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5272 tnext = t->next;
5273 if (t->state & TASK_RUNNING)
5274 continue;
5275
willy tarreaub952e1d2005-12-18 01:31:20 +01005276 if (tv_iseternity(&t->expire))
5277 continue;
5278
willy tarreau1c2ad212005-12-18 01:11:29 +01005279 /* wakeup expired entries. It doesn't matter if they are
5280 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005281 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005282 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005283 task_wakeup(&rq, t);
5284 }
5285 else {
5286 /* first non-runnable task. Use its expiration date as an upper bound */
5287 int temp_time = tv_remain(&now, &t->expire);
5288 if (temp_time)
5289 next_time = temp_time;
5290 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005291 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005292 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005293
willy tarreau1c2ad212005-12-18 01:11:29 +01005294 /* process each task in the run queue now. Each task may be deleted
5295 * since we only use tnext.
5296 */
5297 tnext = rq;
5298 while ((t = tnext) != NULL) {
5299 int temp_time;
5300
5301 tnext = t->rqnext;
5302 task_sleep(&rq, t);
5303 temp_time = t->process(t);
5304 next_time = MINTIME(temp_time, next_time);
5305 }
5306
5307 /* maintain all proxies in a consistent state. This should quickly become a task */
5308 time2 = maintain_proxies();
5309 return MINTIME(time2, next_time);
5310}
5311
5312
5313#if defined(ENABLE_EPOLL)
5314
5315/*
5316 * Main epoll() loop.
5317 */
5318
5319/* does 3 actions :
5320 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5321 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5322 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5323 *
5324 * returns 0 if initialization failed, !0 otherwise.
5325 */
5326
5327int epoll_loop(int action) {
5328 int next_time;
5329 int status;
5330 int fd;
5331
5332 int fds, count;
5333 int pr, pw, sr, sw;
5334 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5335 struct epoll_event ev;
5336
5337 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005338 static struct epoll_event *epoll_events = NULL;
5339 static int epoll_fd;
5340
5341 if (action == POLL_LOOP_ACTION_INIT) {
5342 epoll_fd = epoll_create(global.maxsock + 1);
5343 if (epoll_fd < 0)
5344 return 0;
5345 else {
5346 epoll_events = (struct epoll_event*)
5347 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5348 PrevReadEvent = (fd_set *)
5349 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5350 PrevWriteEvent = (fd_set *)
5351 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005352 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005353 return 1;
5354 }
5355 else if (action == POLL_LOOP_ACTION_CLEAN) {
5356 if (PrevWriteEvent) free(PrevWriteEvent);
5357 if (PrevReadEvent) free(PrevReadEvent);
5358 if (epoll_events) free(epoll_events);
5359 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005360 epoll_fd = 0;
5361 return 1;
5362 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005363
willy tarreau1c2ad212005-12-18 01:11:29 +01005364 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005365
willy tarreau1c2ad212005-12-18 01:11:29 +01005366 tv_now(&now);
5367
5368 while (1) {
5369 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005370
5371 /* stop when there's no connection left and we don't allow them anymore */
5372 if (!actconn && listeners == 0)
5373 break;
5374
willy tarreau0f7af912005-12-17 12:21:26 +01005375#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005376 {
5377 int time2;
5378 time2 = stats();
5379 next_time = MINTIME(time2, next_time);
5380 }
willy tarreau0f7af912005-12-17 12:21:26 +01005381#endif
5382
willy tarreau1c2ad212005-12-18 01:11:29 +01005383 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5384
5385 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5386 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5387
5388 if ((ro^rn) | (wo^wn)) {
5389 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5390#define FDSETS_ARE_INT_ALIGNED
5391#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005392
willy tarreauad90a0c2005-12-18 01:09:15 +01005393#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5394#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005395 pr = (ro >> count) & 1;
5396 pw = (wo >> count) & 1;
5397 sr = (rn >> count) & 1;
5398 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005399#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005400 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5401 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5402 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5403 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005404#endif
5405#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005406 pr = FD_ISSET(fd, PrevReadEvent);
5407 pw = FD_ISSET(fd, PrevWriteEvent);
5408 sr = FD_ISSET(fd, StaticReadEvent);
5409 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005410#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005411 if (!((sr^pr) | (sw^pw)))
5412 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005413
willy tarreau1c2ad212005-12-18 01:11:29 +01005414 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5415 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005416
willy tarreaub952e1d2005-12-18 01:31:20 +01005417#ifdef EPOLL_CTL_MOD_WORKAROUND
5418 /* I encountered a rarely reproducible problem with
5419 * EPOLL_CTL_MOD where a modified FD (systematically
5420 * the one in epoll_events[0], fd#7) would sometimes
5421 * be set EPOLL_OUT while asked for a read ! This is
5422 * with the 2.4 epoll patch. The workaround is to
5423 * delete then recreate in case of modification.
5424 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5425 * nor RHEL kernels.
5426 */
5427
5428 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5429 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5430
5431 if ((sr | sw))
5432 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5433#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005434 if ((pr | pw)) {
5435 /* the file-descriptor already exists... */
5436 if ((sr | sw)) {
5437 /* ...and it will still exist */
5438 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5439 // perror("epoll_ctl(MOD)");
5440 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005441 }
5442 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005443 /* ...and it will be removed */
5444 if (fdtab[fd].state != FD_STCLOSE &&
5445 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5446 // perror("epoll_ctl(DEL)");
5447 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005448 }
5449 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005450 } else {
5451 /* the file-descriptor did not exist, let's add it */
5452 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5453 // perror("epoll_ctl(ADD)");
5454 // exit(1);
5455 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005456 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005457#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005458 }
5459 ((int*)PrevReadEvent)[fds] = rn;
5460 ((int*)PrevWriteEvent)[fds] = wn;
5461 }
5462 }
5463
5464 /* now let's wait for events */
5465 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5466 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005467
willy tarreau1c2ad212005-12-18 01:11:29 +01005468 for (count = 0; count < status; count++) {
5469 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005470
5471 if (FD_ISSET(fd, StaticReadEvent)) {
5472 if (fdtab[fd].state == FD_STCLOSE)
5473 continue;
5474 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5475 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005476 }
willy tarreau05be12b2006-03-19 19:35:00 +01005477
5478 if (FD_ISSET(fd, StaticWriteEvent)) {
5479 if (fdtab[fd].state == FD_STCLOSE)
5480 continue;
5481 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5482 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005483 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005484 }
5485 }
5486 return 1;
5487}
5488#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005489
willy tarreauad90a0c2005-12-18 01:09:15 +01005490
willy tarreau5cbea6f2005-12-17 12:48:26 +01005491
willy tarreau1c2ad212005-12-18 01:11:29 +01005492#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005493
willy tarreau1c2ad212005-12-18 01:11:29 +01005494/*
5495 * Main poll() loop.
5496 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005497
willy tarreau1c2ad212005-12-18 01:11:29 +01005498/* does 3 actions :
5499 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5500 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5501 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5502 *
5503 * returns 0 if initialization failed, !0 otherwise.
5504 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005505
willy tarreau1c2ad212005-12-18 01:11:29 +01005506int poll_loop(int action) {
5507 int next_time;
5508 int status;
5509 int fd, nbfd;
5510
5511 int fds, count;
5512 int sr, sw;
5513 unsigned rn, wn; /* read new, write new */
5514
5515 /* private data */
5516 static struct pollfd *poll_events = NULL;
5517
5518 if (action == POLL_LOOP_ACTION_INIT) {
5519 poll_events = (struct pollfd*)
5520 calloc(1, sizeof(struct pollfd) * global.maxsock);
5521 return 1;
5522 }
5523 else if (action == POLL_LOOP_ACTION_CLEAN) {
5524 if (poll_events)
5525 free(poll_events);
5526 return 1;
5527 }
5528
5529 /* OK, it's POLL_LOOP_ACTION_RUN */
5530
5531 tv_now(&now);
5532
5533 while (1) {
5534 next_time = process_runnable_tasks();
5535
5536 /* stop when there's no connection left and we don't allow them anymore */
5537 if (!actconn && listeners == 0)
5538 break;
5539
5540#if STATTIME > 0
5541 {
5542 int time2;
5543 time2 = stats();
5544 next_time = MINTIME(time2, next_time);
5545 }
5546#endif
5547
5548
5549 nbfd = 0;
5550 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5551
5552 rn = ((int*)StaticReadEvent)[fds];
5553 wn = ((int*)StaticWriteEvent)[fds];
5554
5555 if ((rn|wn)) {
5556 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5557#define FDSETS_ARE_INT_ALIGNED
5558#ifdef FDSETS_ARE_INT_ALIGNED
5559
5560#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5561#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5562 sr = (rn >> count) & 1;
5563 sw = (wn >> count) & 1;
5564#else
5565 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5566 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5567#endif
5568#else
5569 sr = FD_ISSET(fd, StaticReadEvent);
5570 sw = FD_ISSET(fd, StaticWriteEvent);
5571#endif
5572 if ((sr|sw)) {
5573 poll_events[nbfd].fd = fd;
5574 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5575 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005576 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005577 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005578 }
5579 }
5580
5581 /* now let's wait for events */
5582 status = poll(poll_events, nbfd, next_time);
5583 tv_now(&now);
5584
5585 for (count = 0; status > 0 && count < nbfd; count++) {
5586 fd = poll_events[count].fd;
5587
5588 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5589 continue;
5590
5591 /* ok, we found one active fd */
5592 status--;
5593
willy tarreau05be12b2006-03-19 19:35:00 +01005594 if (FD_ISSET(fd, StaticReadEvent)) {
5595 if (fdtab[fd].state == FD_STCLOSE)
5596 continue;
5597 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5598 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005599 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005600
willy tarreau05be12b2006-03-19 19:35:00 +01005601 if (FD_ISSET(fd, StaticWriteEvent)) {
5602 if (fdtab[fd].state == FD_STCLOSE)
5603 continue;
5604 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5605 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005606 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005607 }
5608 }
5609 return 1;
5610}
willy tarreauad90a0c2005-12-18 01:09:15 +01005611#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005612
willy tarreauad90a0c2005-12-18 01:09:15 +01005613
willy tarreauad90a0c2005-12-18 01:09:15 +01005614
willy tarreau1c2ad212005-12-18 01:11:29 +01005615/*
5616 * Main select() loop.
5617 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005618
willy tarreau1c2ad212005-12-18 01:11:29 +01005619/* does 3 actions :
5620 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5621 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5622 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5623 *
5624 * returns 0 if initialization failed, !0 otherwise.
5625 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005626
willy tarreauad90a0c2005-12-18 01:09:15 +01005627
willy tarreau1c2ad212005-12-18 01:11:29 +01005628int select_loop(int action) {
5629 int next_time;
5630 int status;
5631 int fd,i;
5632 struct timeval delta;
5633 int readnotnull, writenotnull;
5634 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005635
willy tarreau1c2ad212005-12-18 01:11:29 +01005636 if (action == POLL_LOOP_ACTION_INIT) {
5637 ReadEvent = (fd_set *)
5638 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5639 WriteEvent = (fd_set *)
5640 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5641 return 1;
5642 }
5643 else if (action == POLL_LOOP_ACTION_CLEAN) {
5644 if (WriteEvent) free(WriteEvent);
5645 if (ReadEvent) free(ReadEvent);
5646 return 1;
5647 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005648
willy tarreau1c2ad212005-12-18 01:11:29 +01005649 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005650
willy tarreau1c2ad212005-12-18 01:11:29 +01005651 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005652
willy tarreau1c2ad212005-12-18 01:11:29 +01005653 while (1) {
5654 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005655
willy tarreau1c2ad212005-12-18 01:11:29 +01005656 /* stop when there's no connection left and we don't allow them anymore */
5657 if (!actconn && listeners == 0)
5658 break;
5659
5660#if STATTIME > 0
5661 {
5662 int time2;
5663 time2 = stats();
5664 next_time = MINTIME(time2, next_time);
5665 }
5666#endif
5667
willy tarreau1c2ad212005-12-18 01:11:29 +01005668 if (next_time > 0) { /* FIXME */
5669 /* Convert to timeval */
5670 /* to avoid eventual select loops due to timer precision */
5671 next_time += SCHEDULER_RESOLUTION;
5672 delta.tv_sec = next_time / 1000;
5673 delta.tv_usec = (next_time % 1000) * 1000;
5674 }
5675 else if (next_time == 0) { /* allow select to return immediately when needed */
5676 delta.tv_sec = delta.tv_usec = 0;
5677 }
5678
5679
5680 /* let's restore fdset state */
5681
5682 readnotnull = 0; writenotnull = 0;
5683 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5684 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5685 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5686 }
5687
5688 // /* just a verification code, needs to be removed for performance */
5689 // for (i=0; i<maxfd; i++) {
5690 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5691 // abort();
5692 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5693 // abort();
5694 //
5695 // }
5696
5697 status = select(maxfd,
5698 readnotnull ? ReadEvent : NULL,
5699 writenotnull ? WriteEvent : NULL,
5700 NULL,
5701 (next_time >= 0) ? &delta : NULL);
5702
5703 /* this is an experiment on the separation of the select work */
5704 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5705 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5706
5707 tv_now(&now);
5708
5709 if (status > 0) { /* must proceed with events */
5710
5711 int fds;
5712 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005713
willy tarreau1c2ad212005-12-18 01:11:29 +01005714 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5715 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5716 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5717
5718 /* if we specify read first, the accepts and zero reads will be
5719 * seen first. Moreover, system buffers will be flushed faster.
5720 */
willy tarreau05be12b2006-03-19 19:35:00 +01005721 if (FD_ISSET(fd, ReadEvent)) {
5722 if (fdtab[fd].state == FD_STCLOSE)
5723 continue;
5724 fdtab[fd].read(fd);
5725 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005726
willy tarreau05be12b2006-03-19 19:35:00 +01005727 if (FD_ISSET(fd, WriteEvent)) {
5728 if (fdtab[fd].state == FD_STCLOSE)
5729 continue;
5730 fdtab[fd].write(fd);
5731 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005732 }
5733 }
5734 else {
5735 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005736 }
willy tarreau0f7af912005-12-17 12:21:26 +01005737 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005738 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005739}
5740
5741
5742#if STATTIME > 0
5743/*
5744 * Display proxy statistics regularly. It is designed to be called from the
5745 * select_loop().
5746 */
5747int stats(void) {
5748 static int lines;
5749 static struct timeval nextevt;
5750 static struct timeval lastevt;
5751 static struct timeval starttime = {0,0};
5752 unsigned long totaltime, deltatime;
5753 int ret;
5754
willy tarreau750a4722005-12-17 13:21:24 +01005755 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005756 deltatime = (tv_diff(&lastevt, &now)?:1);
5757 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005758
willy tarreau9fe663a2005-12-17 13:02:59 +01005759 if (global.mode & MODE_STATS) {
5760 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005761 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005762 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5763 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005764 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005765 actconn, totalconn,
5766 stats_tsk_new, stats_tsk_good,
5767 stats_tsk_left, stats_tsk_right,
5768 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5769 }
5770 }
5771
5772 tv_delayfrom(&nextevt, &now, STATTIME);
5773
5774 lastevt=now;
5775 }
5776 ret = tv_remain(&now, &nextevt);
5777 return ret;
5778}
5779#endif
5780
5781
5782/*
5783 * this function enables proxies when there are enough free sessions,
5784 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005785 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005786 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005787 */
5788static int maintain_proxies(void) {
5789 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005790 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005791 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005792
5793 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005794 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005795
5796 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005797 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005798 while (p) {
5799 if (p->nbconn < p->maxconn) {
5800 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005801 for (l = p->listen; l != NULL; l = l->next) {
5802 FD_SET(l->fd, StaticReadEvent);
5803 }
willy tarreau0f7af912005-12-17 12:21:26 +01005804 p->state = PR_STRUN;
5805 }
5806 }
5807 else {
5808 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005809 for (l = p->listen; l != NULL; l = l->next) {
5810 FD_CLR(l->fd, StaticReadEvent);
5811 }
willy tarreau0f7af912005-12-17 12:21:26 +01005812 p->state = PR_STIDLE;
5813 }
5814 }
5815 p = p->next;
5816 }
5817 }
5818 else { /* block all proxies */
5819 while (p) {
5820 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005821 for (l = p->listen; l != NULL; l = l->next) {
5822 FD_CLR(l->fd, StaticReadEvent);
5823 }
willy tarreau0f7af912005-12-17 12:21:26 +01005824 p->state = PR_STIDLE;
5825 }
5826 p = p->next;
5827 }
5828 }
5829
willy tarreau5cbea6f2005-12-17 12:48:26 +01005830 if (stopping) {
5831 p = proxy;
5832 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005833 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005834 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005835 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005836 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005837 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005838 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005839
willy tarreaua41a8b42005-12-17 14:02:24 +01005840 for (l = p->listen; l != NULL; l = l->next) {
5841 fd_delete(l->fd);
5842 listeners--;
5843 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005844 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005845 }
5846 else {
5847 tleft = MINTIME(t, tleft);
5848 }
5849 }
5850 p = p->next;
5851 }
5852 }
5853 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005854}
5855
5856/*
5857 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01005858 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
5859 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01005860 */
5861static void soft_stop(void) {
5862 struct proxy *p;
5863
5864 stopping = 1;
5865 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005866 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005867 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01005868 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005869 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005870 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005871 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005872 }
willy tarreau0f7af912005-12-17 12:21:26 +01005873 p = p->next;
5874 }
5875}
5876
willy tarreaudbd3bef2006-01-20 19:35:18 +01005877static void pause_proxy(struct proxy *p) {
5878 struct listener *l;
5879 for (l = p->listen; l != NULL; l = l->next) {
5880 shutdown(l->fd, SHUT_RD);
5881 FD_CLR(l->fd, StaticReadEvent);
5882 p->state = PR_STPAUSED;
5883 }
5884}
5885
5886/*
5887 * This function temporarily disables listening so that another new instance
5888 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01005889 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01005890 * the proxy, or a SIGTTIN can be sent to listen again.
5891 */
5892static void pause_proxies(void) {
5893 struct proxy *p;
5894
5895 p = proxy;
5896 tv_now(&now); /* else, the old time before select will be used */
5897 while (p) {
5898 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
5899 Warning("Pausing proxy %s.\n", p->id);
5900 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
5901 pause_proxy(p);
5902 }
5903 p = p->next;
5904 }
5905}
5906
5907
5908/*
5909 * This function reactivates listening. This can be used after a call to
5910 * sig_pause(), for example when a new instance has failed starting up.
5911 * It is designed to be called upon reception of a SIGTTIN.
5912 */
5913static void listen_proxies(void) {
5914 struct proxy *p;
5915 struct listener *l;
5916
5917 p = proxy;
5918 tv_now(&now); /* else, the old time before select will be used */
5919 while (p) {
5920 if (p->state == PR_STPAUSED) {
5921 Warning("Enabling proxy %s.\n", p->id);
5922 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
5923
5924 for (l = p->listen; l != NULL; l = l->next) {
5925 if (listen(l->fd, p->maxconn) == 0) {
5926 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
5927 FD_SET(l->fd, StaticReadEvent);
5928 p->state = PR_STRUN;
5929 }
5930 else
5931 p->state = PR_STIDLE;
5932 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01005933 int port;
5934
5935 if (l->addr.ss_family == AF_INET6)
5936 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
5937 else
5938 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
5939
willy tarreaudbd3bef2006-01-20 19:35:18 +01005940 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005941 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005942 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005943 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005944 /* Another port might have been enabled. Let's stop everything. */
5945 pause_proxy(p);
5946 break;
5947 }
5948 }
5949 }
5950 p = p->next;
5951 }
5952}
5953
5954
willy tarreau0f7af912005-12-17 12:21:26 +01005955/*
5956 * upon SIGUSR1, let's have a soft stop.
5957 */
5958void sig_soft_stop(int sig) {
5959 soft_stop();
5960 signal(sig, SIG_IGN);
5961}
5962
willy tarreaudbd3bef2006-01-20 19:35:18 +01005963/*
5964 * upon SIGTTOU, we pause everything
5965 */
5966void sig_pause(int sig) {
5967 pause_proxies();
5968 signal(sig, sig_pause);
5969}
willy tarreau0f7af912005-12-17 12:21:26 +01005970
willy tarreau8337c6b2005-12-17 13:41:01 +01005971/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01005972 * upon SIGTTIN, let's have a soft stop.
5973 */
5974void sig_listen(int sig) {
5975 listen_proxies();
5976 signal(sig, sig_listen);
5977}
5978
5979/*
willy tarreau8337c6b2005-12-17 13:41:01 +01005980 * this function dumps every server's state when the process receives SIGHUP.
5981 */
5982void sig_dump_state(int sig) {
5983 struct proxy *p = proxy;
5984
5985 Warning("SIGHUP received, dumping servers states.\n");
5986 while (p) {
5987 struct server *s = p->srv;
5988
5989 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5990 while (s) {
5991 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005992 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
5993 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01005994 }
5995 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01005996 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
5997 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01005998 }
5999 s = s->next;
6000 }
willy tarreaudd07e972005-12-18 00:48:48 +01006001
6002 if (find_server(p) == NULL) {
willy tarreau1fb34932006-03-23 11:22:10 +01006003 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6004 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
willy tarreaudd07e972005-12-18 00:48:48 +01006005 }
6006
willy tarreau8337c6b2005-12-17 13:41:01 +01006007 p = p->next;
6008 }
6009 signal(sig, sig_dump_state);
6010}
6011
willy tarreau0f7af912005-12-17 12:21:26 +01006012void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006013 struct task *t, *tnext;
6014 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006015
willy tarreau5cbea6f2005-12-17 12:48:26 +01006016 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6017 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6018 tnext = t->next;
6019 s = t->context;
6020 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6021 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6022 "req=%d, rep=%d, clifd=%d\n",
6023 s, tv_remain(&now, &t->expire),
6024 s->cli_state,
6025 s->srv_state,
6026 FD_ISSET(s->cli_fd, StaticReadEvent),
6027 FD_ISSET(s->cli_fd, StaticWriteEvent),
6028 FD_ISSET(s->srv_fd, StaticReadEvent),
6029 FD_ISSET(s->srv_fd, StaticWriteEvent),
6030 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6031 );
willy tarreau0f7af912005-12-17 12:21:26 +01006032 }
willy tarreau12350152005-12-18 01:03:27 +01006033}
6034
willy tarreau64a3cc32005-12-18 01:13:11 +01006035#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006036static void fast_stop(void)
6037{
6038 struct proxy *p;
6039 p = proxy;
6040 while (p) {
6041 p->grace = 0;
6042 p = p->next;
6043 }
6044 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006045}
6046
willy tarreau12350152005-12-18 01:03:27 +01006047void sig_int(int sig) {
6048 /* This would normally be a hard stop,
6049 but we want to be sure about deallocation,
6050 and so on, so we do a soft stop with
6051 0 GRACE time
6052 */
6053 fast_stop();
6054 /* If we are killed twice, we decide to die*/
6055 signal(sig, SIG_DFL);
6056}
6057
6058void sig_term(int sig) {
6059 /* This would normally be a hard stop,
6060 but we want to be sure about deallocation,
6061 and so on, so we do a soft stop with
6062 0 GRACE time
6063 */
6064 fast_stop();
6065 /* If we are killed twice, we decide to die*/
6066 signal(sig, SIG_DFL);
6067}
willy tarreau64a3cc32005-12-18 01:13:11 +01006068#endif
willy tarreau12350152005-12-18 01:03:27 +01006069
willy tarreauc1f47532005-12-18 01:08:26 +01006070/* returns the pointer to an error in the replacement string, or NULL if OK */
6071char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006072 struct hdr_exp *exp;
6073
willy tarreauc1f47532005-12-18 01:08:26 +01006074 if (replace != NULL) {
6075 char *err;
6076 err = check_replace_string(replace);
6077 if (err)
6078 return err;
6079 }
6080
willy tarreaue39cd132005-12-17 13:00:18 +01006081 while (*head != NULL)
6082 head = &(*head)->next;
6083
6084 exp = calloc(1, sizeof(struct hdr_exp));
6085
6086 exp->preg = preg;
6087 exp->replace = replace;
6088 exp->action = action;
6089 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006090
6091 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006092}
6093
willy tarreau9fe663a2005-12-17 13:02:59 +01006094
willy tarreau0f7af912005-12-17 12:21:26 +01006095/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006096 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006097 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006098int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006099
willy tarreau9fe663a2005-12-17 13:02:59 +01006100 if (!strcmp(args[0], "global")) { /* new section */
6101 /* no option, nothing special to do */
6102 return 0;
6103 }
6104 else if (!strcmp(args[0], "daemon")) {
6105 global.mode |= MODE_DAEMON;
6106 }
6107 else if (!strcmp(args[0], "debug")) {
6108 global.mode |= MODE_DEBUG;
6109 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006110 else if (!strcmp(args[0], "noepoll")) {
6111 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6112 }
6113 else if (!strcmp(args[0], "nopoll")) {
6114 cfg_polling_mechanism &= ~POLL_USE_POLL;
6115 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006116 else if (!strcmp(args[0], "quiet")) {
6117 global.mode |= MODE_QUIET;
6118 }
6119 else if (!strcmp(args[0], "stats")) {
6120 global.mode |= MODE_STATS;
6121 }
6122 else if (!strcmp(args[0], "uid")) {
6123 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006124 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006125 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006126 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006127 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006128 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006129 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006130 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006131 global.uid = atol(args[1]);
6132 }
6133 else if (!strcmp(args[0], "gid")) {
6134 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006135 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006136 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006137 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006138 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006139 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006140 return -1;
6141 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006142 global.gid = atol(args[1]);
6143 }
6144 else if (!strcmp(args[0], "nbproc")) {
6145 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006146 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006147 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006148 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006149 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006150 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006151 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006152 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006153 global.nbproc = atol(args[1]);
6154 }
6155 else if (!strcmp(args[0], "maxconn")) {
6156 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006157 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006158 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006159 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006160 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006161 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006162 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006163 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006164 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006165#ifdef SYSTEM_MAXCONN
6166 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6167 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);
6168 global.maxconn = DEFAULT_MAXCONN;
6169 }
6170#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006171 }
willy tarreaub1285d52005-12-18 01:20:14 +01006172 else if (!strcmp(args[0], "ulimit-n")) {
6173 if (global.rlimit_nofile != 0) {
6174 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6175 return 0;
6176 }
6177 if (*(args[1]) == 0) {
6178 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6179 return -1;
6180 }
6181 global.rlimit_nofile = atol(args[1]);
6182 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006183 else if (!strcmp(args[0], "chroot")) {
6184 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006185 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006186 return 0;
6187 }
6188 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006189 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006190 return -1;
6191 }
6192 global.chroot = strdup(args[1]);
6193 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006194 else if (!strcmp(args[0], "pidfile")) {
6195 if (global.pidfile != NULL) {
6196 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6197 return 0;
6198 }
6199 if (*(args[1]) == 0) {
6200 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6201 return -1;
6202 }
6203 global.pidfile = strdup(args[1]);
6204 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006205 else if (!strcmp(args[0], "log")) { /* syslog server address */
6206 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006207 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006208
6209 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006210 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006211 return -1;
6212 }
6213
6214 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6215 if (!strcmp(log_facilities[facility], args[2]))
6216 break;
6217
6218 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006219 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006220 exit(1);
6221 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006222
6223 level = 7; /* max syslog level = debug */
6224 if (*(args[3])) {
6225 while (level >= 0 && strcmp(log_levels[level], args[3]))
6226 level--;
6227 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006228 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006229 exit(1);
6230 }
6231 }
6232
willy tarreau9fe663a2005-12-17 13:02:59 +01006233 sa = str2sa(args[1]);
6234 if (!sa->sin_port)
6235 sa->sin_port = htons(SYSLOG_PORT);
6236
6237 if (global.logfac1 == -1) {
6238 global.logsrv1 = *sa;
6239 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006240 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006241 }
6242 else if (global.logfac2 == -1) {
6243 global.logsrv2 = *sa;
6244 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006245 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006246 }
6247 else {
6248 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6249 return -1;
6250 }
6251
6252 }
6253 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006254 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006255 return -1;
6256 }
6257 return 0;
6258}
6259
6260
willy tarreaua41a8b42005-12-17 14:02:24 +01006261void init_default_instance() {
6262 memset(&defproxy, 0, sizeof(defproxy));
6263 defproxy.mode = PR_MODE_TCP;
6264 defproxy.state = PR_STNEW;
6265 defproxy.maxconn = cfg_maxpconn;
6266 defproxy.conn_retries = CONN_RETRIES;
6267 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6268}
6269
willy tarreau9fe663a2005-12-17 13:02:59 +01006270/*
6271 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6272 */
6273int cfg_parse_listen(char *file, int linenum, char **args) {
6274 static struct proxy *curproxy = NULL;
6275 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006276 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006277 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006278
6279 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006280 if (!*args[1]) {
6281 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6282 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006283 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006284 return -1;
6285 }
6286
6287 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006288 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006289 return -1;
6290 }
6291 curproxy->next = proxy;
6292 proxy = curproxy;
6293 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006294
6295 /* parse the listener address if any */
6296 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006297 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006298 if (!curproxy->listen)
6299 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006300 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006301 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006302
willy tarreau9fe663a2005-12-17 13:02:59 +01006303 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006304 curproxy->state = defproxy.state;
6305 curproxy->maxconn = defproxy.maxconn;
6306 curproxy->conn_retries = defproxy.conn_retries;
6307 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006308
6309 if (defproxy.check_req)
6310 curproxy->check_req = strdup(defproxy.check_req);
6311 curproxy->check_len = defproxy.check_len;
6312
6313 if (defproxy.cookie_name)
6314 curproxy->cookie_name = strdup(defproxy.cookie_name);
6315 curproxy->cookie_len = defproxy.cookie_len;
6316
6317 if (defproxy.capture_name)
6318 curproxy->capture_name = strdup(defproxy.capture_name);
6319 curproxy->capture_namelen = defproxy.capture_namelen;
6320 curproxy->capture_len = defproxy.capture_len;
6321
6322 if (defproxy.errmsg.msg400)
6323 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6324 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6325
6326 if (defproxy.errmsg.msg403)
6327 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6328 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6329
6330 if (defproxy.errmsg.msg408)
6331 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6332 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6333
6334 if (defproxy.errmsg.msg500)
6335 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6336 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6337
6338 if (defproxy.errmsg.msg502)
6339 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6340 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6341
6342 if (defproxy.errmsg.msg503)
6343 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6344 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6345
6346 if (defproxy.errmsg.msg504)
6347 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6348 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6349
willy tarreaua41a8b42005-12-17 14:02:24 +01006350 curproxy->clitimeout = defproxy.clitimeout;
6351 curproxy->contimeout = defproxy.contimeout;
6352 curproxy->srvtimeout = defproxy.srvtimeout;
6353 curproxy->mode = defproxy.mode;
6354 curproxy->logfac1 = defproxy.logfac1;
6355 curproxy->logsrv1 = defproxy.logsrv1;
6356 curproxy->loglev1 = defproxy.loglev1;
6357 curproxy->logfac2 = defproxy.logfac2;
6358 curproxy->logsrv2 = defproxy.logsrv2;
6359 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006360 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006361 curproxy->grace = defproxy.grace;
6362 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006363 curproxy->mon_net = defproxy.mon_net;
6364 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006365 return 0;
6366 }
6367 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006368 /* some variables may have already been initialized earlier */
6369 if (defproxy.check_req) free(defproxy.check_req);
6370 if (defproxy.cookie_name) free(defproxy.cookie_name);
6371 if (defproxy.capture_name) free(defproxy.capture_name);
6372 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6373 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6374 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6375 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6376 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6377 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6378 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6379
6380 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006381 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006382 return 0;
6383 }
6384 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006385 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006386 return -1;
6387 }
6388
willy tarreaua41a8b42005-12-17 14:02:24 +01006389 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6390 if (curproxy == &defproxy) {
6391 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6392 return -1;
6393 }
6394
6395 if (strchr(args[1], ':') == NULL) {
6396 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6397 file, linenum, args[0]);
6398 return -1;
6399 }
6400 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006401 if (!curproxy->listen)
6402 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006403 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006404 return 0;
6405 }
willy tarreaub1285d52005-12-18 01:20:14 +01006406 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6407 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6408 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6409 file, linenum, args[0]);
6410 return -1;
6411 }
6412 /* flush useless bits */
6413 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6414 return 0;
6415 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006416 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006417 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6418 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6419 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6420 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006421 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006422 return -1;
6423 }
6424 }
6425 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006426 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006427 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006428 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6429 curproxy->state = PR_STNEW;
6430 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006431 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6432 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006433// if (curproxy == &defproxy) {
6434// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6435// return -1;
6436// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006437
willy tarreau9fe663a2005-12-17 13:02:59 +01006438 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006439// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6440// file, linenum);
6441// return 0;
6442 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006443 }
6444
6445 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006446 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6447 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006448 return -1;
6449 }
6450 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006451 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006452
6453 cur_arg = 2;
6454 while (*(args[cur_arg])) {
6455 if (!strcmp(args[cur_arg], "rewrite")) {
6456 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006457 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006458 else if (!strcmp(args[cur_arg], "indirect")) {
6459 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006460 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006461 else if (!strcmp(args[cur_arg], "insert")) {
6462 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006463 }
willy tarreau240afa62005-12-17 13:14:35 +01006464 else if (!strcmp(args[cur_arg], "nocache")) {
6465 curproxy->options |= PR_O_COOK_NOC;
6466 }
willy tarreaucd878942005-12-17 13:27:43 +01006467 else if (!strcmp(args[cur_arg], "postonly")) {
6468 curproxy->options |= PR_O_COOK_POST;
6469 }
willy tarreau0174f312005-12-18 01:02:42 +01006470 else if (!strcmp(args[cur_arg], "prefix")) {
6471 curproxy->options |= PR_O_COOK_PFX;
6472 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006473 else {
willy tarreau0174f312005-12-18 01:02:42 +01006474 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006475 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006476 return -1;
6477 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006478 cur_arg++;
6479 }
willy tarreau0174f312005-12-18 01:02:42 +01006480 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6481 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6482 file, linenum);
6483 return -1;
6484 }
6485
6486 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6487 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006488 file, linenum);
6489 return -1;
6490 }
willy tarreau12350152005-12-18 01:03:27 +01006491 }/* end else if (!strcmp(args[0], "cookie")) */
6492 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6493// if (curproxy == &defproxy) {
6494// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6495// return -1;
6496// }
6497
6498 if (curproxy->appsession_name != NULL) {
6499// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6500// file, linenum);
6501// return 0;
6502 free(curproxy->appsession_name);
6503 }
6504
6505 if (*(args[5]) == 0) {
6506 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6507 file, linenum, args[0]);
6508 return -1;
6509 }
6510 have_appsession = 1;
6511 curproxy->appsession_name = strdup(args[1]);
6512 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6513 curproxy->appsession_len = atoi(args[3]);
6514 curproxy->appsession_timeout = atoi(args[5]);
6515 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6516 if (rc) {
6517 Alert("Error Init Appsession Hashtable.\n");
6518 return -1;
6519 }
6520 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006521 else if (!strcmp(args[0], "capture")) {
6522 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6523 // if (curproxy == &defproxy) {
6524 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6525 // return -1;
6526 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006527
willy tarreau4302f492005-12-18 01:00:37 +01006528 if (curproxy->capture_name != NULL) {
6529 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6530 // file, linenum, args[0]);
6531 // return 0;
6532 free(curproxy->capture_name);
6533 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006534
willy tarreau4302f492005-12-18 01:00:37 +01006535 if (*(args[4]) == 0) {
6536 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6537 file, linenum, args[0]);
6538 return -1;
6539 }
6540 curproxy->capture_name = strdup(args[2]);
6541 curproxy->capture_namelen = strlen(curproxy->capture_name);
6542 curproxy->capture_len = atol(args[4]);
6543 if (curproxy->capture_len >= CAPTURE_LEN) {
6544 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6545 file, linenum, CAPTURE_LEN - 1);
6546 curproxy->capture_len = CAPTURE_LEN - 1;
6547 }
6548 curproxy->to_log |= LW_COOKIE;
6549 }
6550 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6551 struct cap_hdr *hdr;
6552
6553 if (curproxy == &defproxy) {
6554 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6555 return -1;
6556 }
6557
6558 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6559 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6560 file, linenum, args[0], args[1]);
6561 return -1;
6562 }
6563
6564 hdr = calloc(sizeof(struct cap_hdr), 1);
6565 hdr->next = curproxy->req_cap;
6566 hdr->name = strdup(args[3]);
6567 hdr->namelen = strlen(args[3]);
6568 hdr->len = atol(args[5]);
6569 hdr->index = curproxy->nb_req_cap++;
6570 curproxy->req_cap = hdr;
6571 curproxy->to_log |= LW_REQHDR;
6572 }
6573 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6574 struct cap_hdr *hdr;
6575
6576 if (curproxy == &defproxy) {
6577 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6578 return -1;
6579 }
6580
6581 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6582 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6583 file, linenum, args[0], args[1]);
6584 return -1;
6585 }
6586 hdr = calloc(sizeof(struct cap_hdr), 1);
6587 hdr->next = curproxy->rsp_cap;
6588 hdr->name = strdup(args[3]);
6589 hdr->namelen = strlen(args[3]);
6590 hdr->len = atol(args[5]);
6591 hdr->index = curproxy->nb_rsp_cap++;
6592 curproxy->rsp_cap = hdr;
6593 curproxy->to_log |= LW_RSPHDR;
6594 }
6595 else {
6596 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006597 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006598 return -1;
6599 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006600 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006601 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006602 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006603 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006604 return 0;
6605 }
6606 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006607 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6608 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006609 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006610 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006611 curproxy->contimeout = atol(args[1]);
6612 }
6613 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006614 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006615 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6616 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006617 return 0;
6618 }
6619 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006620 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6621 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006622 return -1;
6623 }
6624 curproxy->clitimeout = atol(args[1]);
6625 }
6626 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006627 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006628 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 return 0;
6630 }
6631 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006632 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6633 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006634 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006635 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006636 curproxy->srvtimeout = atol(args[1]);
6637 }
6638 else if (!strcmp(args[0], "retries")) { /* connection retries */
6639 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006640 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6641 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006642 return -1;
6643 }
6644 curproxy->conn_retries = atol(args[1]);
6645 }
6646 else if (!strcmp(args[0], "option")) {
6647 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006648 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006649 return -1;
6650 }
6651 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006652 /* enable reconnections to dispatch */
6653 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006654#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006655 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006656 /* enable transparent proxy connections */
6657 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006658#endif
6659 else if (!strcmp(args[1], "keepalive"))
6660 /* enable keep-alive */
6661 curproxy->options |= PR_O_KEEPALIVE;
6662 else if (!strcmp(args[1], "forwardfor"))
6663 /* insert x-forwarded-for field */
6664 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006665 else if (!strcmp(args[1], "logasap"))
6666 /* log as soon as possible, without waiting for the session to complete */
6667 curproxy->options |= PR_O_LOGASAP;
6668 else if (!strcmp(args[1], "httpclose"))
6669 /* force connection: close in both directions in HTTP mode */
6670 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006671 else if (!strcmp(args[1], "forceclose"))
6672 /* force connection: close in both directions in HTTP mode and enforce end of session */
6673 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006674 else if (!strcmp(args[1], "checkcache"))
6675 /* require examination of cacheability of the 'set-cookie' field */
6676 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006677 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006678 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006679 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006680 else if (!strcmp(args[1], "tcplog"))
6681 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006682 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006683 else if (!strcmp(args[1], "dontlognull")) {
6684 /* don't log empty requests */
6685 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006686 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006687 else if (!strcmp(args[1], "tcpka")) {
6688 /* enable TCP keep-alives on client and server sessions */
6689 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6690 }
6691 else if (!strcmp(args[1], "clitcpka")) {
6692 /* enable TCP keep-alives on client sessions */
6693 curproxy->options |= PR_O_TCP_CLI_KA;
6694 }
6695 else if (!strcmp(args[1], "srvtcpka")) {
6696 /* enable TCP keep-alives on server sessions */
6697 curproxy->options |= PR_O_TCP_SRV_KA;
6698 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006699 else if (!strcmp(args[1], "allbackups")) {
6700 /* Use all backup servers simultaneously */
6701 curproxy->options |= PR_O_USE_ALL_BK;
6702 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006703 else if (!strcmp(args[1], "httpchk")) {
6704 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006705 if (curproxy->check_req != NULL) {
6706 free(curproxy->check_req);
6707 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006708 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006709 if (!*args[2]) { /* no argument */
6710 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6711 curproxy->check_len = strlen(DEF_CHECK_REQ);
6712 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006713 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6714 curproxy->check_req = (char *)malloc(reqlen);
6715 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6716 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006717 } else { /* more arguments : METHOD URI [HTTP_VER] */
6718 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6719 if (*args[4])
6720 reqlen += strlen(args[4]);
6721 else
6722 reqlen += strlen("HTTP/1.0");
6723
6724 curproxy->check_req = (char *)malloc(reqlen);
6725 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6726 "%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 +01006727 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006728 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006729 else if (!strcmp(args[1], "persist")) {
6730 /* persist on using the server specified by the cookie, even when it's down */
6731 curproxy->options |= PR_O_PERSIST;
6732 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006733 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006734 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006735 return -1;
6736 }
6737 return 0;
6738 }
6739 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6740 /* enable reconnections to dispatch */
6741 curproxy->options |= PR_O_REDISP;
6742 }
willy tarreaua1598082005-12-17 13:08:06 +01006743#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006744 else if (!strcmp(args[0], "transparent")) {
6745 /* enable transparent proxy connections */
6746 curproxy->options |= PR_O_TRANSP;
6747 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006748#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006749 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6750 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006751 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006752 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006753 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006754 curproxy->maxconn = atol(args[1]);
6755 }
6756 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6757 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006758 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006759 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006760 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006761 curproxy->grace = atol(args[1]);
6762 }
6763 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006764 if (curproxy == &defproxy) {
6765 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6766 return -1;
6767 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006768 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006769 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006770 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006771 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006772 curproxy->dispatch_addr = *str2sa(args[1]);
6773 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006774 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006775 if (*(args[1])) {
6776 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006777 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006778 }
6779 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006780 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006781 return -1;
6782 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006783 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006784 else /* if no option is set, use round-robin by default */
6785 curproxy->options |= PR_O_BALANCE_RR;
6786 }
6787 else if (!strcmp(args[0], "server")) { /* server address */
6788 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006789 char *rport;
6790 char *raddr;
6791 short realport;
6792 int do_check;
6793
6794 if (curproxy == &defproxy) {
6795 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6796 return -1;
6797 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006798
willy tarreaua41a8b42005-12-17 14:02:24 +01006799 if (!*args[2]) {
6800 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006801 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006802 return -1;
6803 }
6804 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6805 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6806 return -1;
6807 }
willy tarreau0174f312005-12-18 01:02:42 +01006808
6809 if (curproxy->srv == NULL)
6810 curproxy->srv = newsrv;
6811 else
6812 curproxy->cursrv->next = newsrv;
6813 curproxy->cursrv = newsrv;
6814
6815 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006816 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006817
6818 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006819 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006820 newsrv->id = strdup(args[1]);
6821
6822 /* several ways to check the port component :
6823 * - IP => port=+0, relative
6824 * - IP: => port=+0, relative
6825 * - IP:N => port=N, absolute
6826 * - IP:+N => port=+N, relative
6827 * - IP:-N => port=-N, relative
6828 */
6829 raddr = strdup(args[2]);
6830 rport = strchr(raddr, ':');
6831 if (rport) {
6832 *rport++ = 0;
6833 realport = atol(rport);
6834 if (!isdigit((int)*rport))
6835 newsrv->state |= SRV_MAPPORTS;
6836 } else {
6837 realport = 0;
6838 newsrv->state |= SRV_MAPPORTS;
6839 }
6840
6841 newsrv->addr = *str2sa(raddr);
6842 newsrv->addr.sin_port = htons(realport);
6843 free(raddr);
6844
willy tarreau9fe663a2005-12-17 13:02:59 +01006845 newsrv->curfd = -1; /* no health-check in progress */
6846 newsrv->inter = DEF_CHKINTR;
6847 newsrv->rise = DEF_RISETIME;
6848 newsrv->fall = DEF_FALLTIME;
6849 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6850 cur_arg = 3;
6851 while (*args[cur_arg]) {
6852 if (!strcmp(args[cur_arg], "cookie")) {
6853 newsrv->cookie = strdup(args[cur_arg + 1]);
6854 newsrv->cklen = strlen(args[cur_arg + 1]);
6855 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006856 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006857 else if (!strcmp(args[cur_arg], "rise")) {
6858 newsrv->rise = atol(args[cur_arg + 1]);
6859 newsrv->health = newsrv->rise;
6860 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006861 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006862 else if (!strcmp(args[cur_arg], "fall")) {
6863 newsrv->fall = atol(args[cur_arg + 1]);
6864 cur_arg += 2;
6865 }
6866 else if (!strcmp(args[cur_arg], "inter")) {
6867 newsrv->inter = atol(args[cur_arg + 1]);
6868 cur_arg += 2;
6869 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006870 else if (!strcmp(args[cur_arg], "port")) {
6871 newsrv->check_port = atol(args[cur_arg + 1]);
6872 cur_arg += 2;
6873 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006874 else if (!strcmp(args[cur_arg], "backup")) {
6875 newsrv->state |= SRV_BACKUP;
6876 cur_arg ++;
6877 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006878 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01006879 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006880 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006881 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006882 }
willy tarreau0174f312005-12-18 01:02:42 +01006883 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6884 if (!*args[cur_arg + 1]) {
6885 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6886 file, linenum, "source");
6887 return -1;
6888 }
6889 newsrv->state |= SRV_BIND_SRC;
6890 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6891 cur_arg += 2;
6892 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006893 else {
willy tarreau0174f312005-12-18 01:02:42 +01006894 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 +01006895 file, linenum, newsrv->id);
6896 return -1;
6897 }
6898 }
6899
6900 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006901 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6902 newsrv->check_port = realport; /* by default */
6903 if (!newsrv->check_port) {
6904 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 +01006905 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006906 return -1;
6907 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006908 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006909 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006910
willy tarreau9fe663a2005-12-17 13:02:59 +01006911 curproxy->nbservers++;
6912 }
6913 else if (!strcmp(args[0], "log")) { /* syslog server address */
6914 struct sockaddr_in *sa;
6915 int facility;
6916
6917 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6918 curproxy->logfac1 = global.logfac1;
6919 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006920 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006921 curproxy->logfac2 = global.logfac2;
6922 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006923 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006924 }
6925 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006926 int level;
6927
willy tarreau0f7af912005-12-17 12:21:26 +01006928 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6929 if (!strcmp(log_facilities[facility], args[2]))
6930 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006931
willy tarreau0f7af912005-12-17 12:21:26 +01006932 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006933 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006934 exit(1);
6935 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006936
willy tarreau8337c6b2005-12-17 13:41:01 +01006937 level = 7; /* max syslog level = debug */
6938 if (*(args[3])) {
6939 while (level >= 0 && strcmp(log_levels[level], args[3]))
6940 level--;
6941 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006942 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006943 exit(1);
6944 }
6945 }
6946
willy tarreau0f7af912005-12-17 12:21:26 +01006947 sa = str2sa(args[1]);
6948 if (!sa->sin_port)
6949 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006950
willy tarreau0f7af912005-12-17 12:21:26 +01006951 if (curproxy->logfac1 == -1) {
6952 curproxy->logsrv1 = *sa;
6953 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006954 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006955 }
6956 else if (curproxy->logfac2 == -1) {
6957 curproxy->logsrv2 = *sa;
6958 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006959 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006960 }
6961 else {
6962 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006964 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006965 }
6966 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006967 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006968 file, linenum);
6969 return -1;
6970 }
6971 }
willy tarreaua1598082005-12-17 13:08:06 +01006972 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006973 if (!*args[1]) {
6974 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006975 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006976 return -1;
6977 }
6978
6979 curproxy->source_addr = *str2sa(args[1]);
6980 curproxy->options |= PR_O_BIND_SRC;
6981 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006982 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6983 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006984 if (curproxy == &defproxy) {
6985 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6986 return -1;
6987 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006988
6989 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006990 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6991 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006992 return -1;
6993 }
6994
6995 preg = calloc(1, sizeof(regex_t));
6996 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006997 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006998 return -1;
6999 }
7000
willy tarreauc1f47532005-12-18 01:08:26 +01007001 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7002 if (err) {
7003 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7004 file, linenum, *err);
7005 return -1;
7006 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007007 }
7008 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7009 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007010 if (curproxy == &defproxy) {
7011 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7012 return -1;
7013 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007014
7015 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007016 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007017 return -1;
7018 }
7019
7020 preg = calloc(1, sizeof(regex_t));
7021 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007022 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007023 return -1;
7024 }
7025
7026 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7027 }
7028 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7029 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007030 if (curproxy == &defproxy) {
7031 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7032 return -1;
7033 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007034
7035 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007036 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007037 return -1;
7038 }
7039
7040 preg = calloc(1, sizeof(regex_t));
7041 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007042 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007043 return -1;
7044 }
7045
7046 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7047 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007048 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7049 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007050 if (curproxy == &defproxy) {
7051 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7052 return -1;
7053 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007054
7055 if (*(args[1]) == 0) {
7056 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7057 return -1;
7058 }
7059
7060 preg = calloc(1, sizeof(regex_t));
7061 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7062 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7063 return -1;
7064 }
7065
7066 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7067 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007068 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7069 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007070 if (curproxy == &defproxy) {
7071 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7072 return -1;
7073 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007074
7075 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007076 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007077 return -1;
7078 }
7079
7080 preg = calloc(1, sizeof(regex_t));
7081 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007082 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007083 return -1;
7084 }
7085
7086 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7087 }
7088 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7089 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007090 if (curproxy == &defproxy) {
7091 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7092 return -1;
7093 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007094
7095 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007096 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7097 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007098 return -1;
7099 }
7100
7101 preg = calloc(1, sizeof(regex_t));
7102 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007103 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007104 return -1;
7105 }
7106
willy tarreauc1f47532005-12-18 01:08:26 +01007107 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7108 if (err) {
7109 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7110 file, linenum, *err);
7111 return -1;
7112 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007113 }
7114 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7115 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007116 if (curproxy == &defproxy) {
7117 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7118 return -1;
7119 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007120
7121 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007122 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007123 return -1;
7124 }
7125
7126 preg = calloc(1, sizeof(regex_t));
7127 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007128 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007129 return -1;
7130 }
7131
7132 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7133 }
7134 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7135 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007136 if (curproxy == &defproxy) {
7137 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7138 return -1;
7139 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007140
7141 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007142 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007143 return -1;
7144 }
7145
7146 preg = calloc(1, sizeof(regex_t));
7147 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007148 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007149 return -1;
7150 }
7151
7152 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7153 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007154 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7155 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007156 if (curproxy == &defproxy) {
7157 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7158 return -1;
7159 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007160
7161 if (*(args[1]) == 0) {
7162 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7163 return -1;
7164 }
7165
7166 preg = calloc(1, sizeof(regex_t));
7167 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7168 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7169 return -1;
7170 }
7171
7172 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7173 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007174 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7175 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007176 if (curproxy == &defproxy) {
7177 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7178 return -1;
7179 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007180
7181 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007182 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007183 return -1;
7184 }
7185
7186 preg = calloc(1, sizeof(regex_t));
7187 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007188 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007189 return -1;
7190 }
7191
7192 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7193 }
7194 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007195 if (curproxy == &defproxy) {
7196 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7197 return -1;
7198 }
7199
willy tarreau9fe663a2005-12-17 13:02:59 +01007200 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007201 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007202 return 0;
7203 }
7204
7205 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007206 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007207 return -1;
7208 }
7209
willy tarreau4302f492005-12-18 01:00:37 +01007210 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7211 }
7212 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7213 regex_t *preg;
7214
7215 if (*(args[1]) == 0 || *(args[2]) == 0) {
7216 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7217 file, linenum, args[0]);
7218 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007219 }
willy tarreau4302f492005-12-18 01:00:37 +01007220
7221 preg = calloc(1, sizeof(regex_t));
7222 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7223 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7224 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007225 }
willy tarreau4302f492005-12-18 01:00:37 +01007226
willy tarreauc1f47532005-12-18 01:08:26 +01007227 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7228 if (err) {
7229 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7230 file, linenum, *err);
7231 return -1;
7232 }
willy tarreau4302f492005-12-18 01:00:37 +01007233 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007234 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7235 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007236 if (curproxy == &defproxy) {
7237 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7238 return -1;
7239 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007240
7241 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007242 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007243 return -1;
7244 }
willy tarreaue39cd132005-12-17 13:00:18 +01007245
willy tarreau9fe663a2005-12-17 13:02:59 +01007246 preg = calloc(1, sizeof(regex_t));
7247 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007248 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007249 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007250 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007251
willy tarreauc1f47532005-12-18 01:08:26 +01007252 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7253 if (err) {
7254 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7255 file, linenum, *err);
7256 return -1;
7257 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007258 }
willy tarreau982249e2005-12-18 00:57:06 +01007259 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7260 regex_t *preg;
7261 if (curproxy == &defproxy) {
7262 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7263 return -1;
7264 }
7265
7266 if (*(args[1]) == 0) {
7267 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7268 return -1;
7269 }
7270
7271 preg = calloc(1, sizeof(regex_t));
7272 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7273 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7274 return -1;
7275 }
7276
willy tarreauc1f47532005-12-18 01:08:26 +01007277 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7278 if (err) {
7279 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7280 file, linenum, *err);
7281 return -1;
7282 }
willy tarreau982249e2005-12-18 00:57:06 +01007283 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007284 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007285 regex_t *preg;
7286 if (curproxy == &defproxy) {
7287 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7288 return -1;
7289 }
willy tarreaue39cd132005-12-17 13:00:18 +01007290
willy tarreaua41a8b42005-12-17 14:02:24 +01007291 if (*(args[1]) == 0 || *(args[2]) == 0) {
7292 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7293 file, linenum, args[0]);
7294 return -1;
7295 }
willy tarreaue39cd132005-12-17 13:00:18 +01007296
willy tarreaua41a8b42005-12-17 14:02:24 +01007297 preg = calloc(1, sizeof(regex_t));
7298 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7299 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7300 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007301 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007302
willy tarreauc1f47532005-12-18 01:08:26 +01007303 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7304 if (err) {
7305 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7306 file, linenum, *err);
7307 return -1;
7308 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007309 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007310 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7311 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007312 if (curproxy == &defproxy) {
7313 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7314 return -1;
7315 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007316
7317 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007318 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007319 return -1;
7320 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007321
willy tarreau9fe663a2005-12-17 13:02:59 +01007322 preg = calloc(1, sizeof(regex_t));
7323 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007324 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007325 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007326 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007327
willy tarreauc1f47532005-12-18 01:08:26 +01007328 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7329 if (err) {
7330 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7331 file, linenum, *err);
7332 return -1;
7333 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007334 }
willy tarreau982249e2005-12-18 00:57:06 +01007335 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7336 regex_t *preg;
7337 if (curproxy == &defproxy) {
7338 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7339 return -1;
7340 }
7341
7342 if (*(args[1]) == 0) {
7343 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7344 return -1;
7345 }
7346
7347 preg = calloc(1, sizeof(regex_t));
7348 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7349 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7350 return -1;
7351 }
7352
willy tarreauc1f47532005-12-18 01:08:26 +01007353 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7354 if (err) {
7355 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7356 file, linenum, *err);
7357 return -1;
7358 }
willy tarreau982249e2005-12-18 00:57:06 +01007359 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007360 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007361 if (curproxy == &defproxy) {
7362 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7363 return -1;
7364 }
7365
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007367 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007368 return 0;
7369 }
7370
7371 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007372 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007373 return -1;
7374 }
7375
7376 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7377 }
willy tarreauc1f47532005-12-18 01:08:26 +01007378 else if (!strcmp(args[0], "errorloc") ||
7379 !strcmp(args[0], "errorloc302") ||
7380 !strcmp(args[0], "errorloc303")) { /* error location */
7381 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007382 char *err;
7383
willy tarreaueedaa9f2005-12-17 14:08:03 +01007384 // if (curproxy == &defproxy) {
7385 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7386 // return -1;
7387 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007388
willy tarreau8337c6b2005-12-17 13:41:01 +01007389 if (*(args[2]) == 0) {
7390 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7391 return -1;
7392 }
7393
7394 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007395 if (!strcmp(args[0], "errorloc303")) {
7396 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7397 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7398 } else {
7399 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7400 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7401 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007402
7403 if (errnum == 400) {
7404 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007405 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007406 free(curproxy->errmsg.msg400);
7407 }
7408 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007409 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007410 }
7411 else if (errnum == 403) {
7412 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007413 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007414 free(curproxy->errmsg.msg403);
7415 }
7416 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007417 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007418 }
7419 else if (errnum == 408) {
7420 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007421 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007422 free(curproxy->errmsg.msg408);
7423 }
7424 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007425 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007426 }
7427 else if (errnum == 500) {
7428 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007429 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007430 free(curproxy->errmsg.msg500);
7431 }
7432 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007433 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007434 }
7435 else if (errnum == 502) {
7436 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007437 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007438 free(curproxy->errmsg.msg502);
7439 }
7440 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007441 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007442 }
7443 else if (errnum == 503) {
7444 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007445 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007446 free(curproxy->errmsg.msg503);
7447 }
7448 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007449 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007450 }
7451 else if (errnum == 504) {
7452 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007453 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007454 free(curproxy->errmsg.msg504);
7455 }
7456 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007457 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007458 }
7459 else {
7460 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7461 free(err);
7462 }
7463 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007464 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007465 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007466 return -1;
7467 }
7468 return 0;
7469}
willy tarreaue39cd132005-12-17 13:00:18 +01007470
willy tarreau5cbea6f2005-12-17 12:48:26 +01007471
willy tarreau9fe663a2005-12-17 13:02:59 +01007472/*
7473 * This function reads and parses the configuration file given in the argument.
7474 * returns 0 if OK, -1 if error.
7475 */
7476int readcfgfile(char *file) {
7477 char thisline[256];
7478 char *line;
7479 FILE *f;
7480 int linenum = 0;
7481 char *end;
7482 char *args[MAX_LINE_ARGS];
7483 int arg;
7484 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007485 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007486 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007487
willy tarreau9fe663a2005-12-17 13:02:59 +01007488 struct proxy *curproxy = NULL;
7489 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007490
willy tarreau9fe663a2005-12-17 13:02:59 +01007491 if ((f=fopen(file,"r")) == NULL)
7492 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007493
willy tarreaueedaa9f2005-12-17 14:08:03 +01007494 init_default_instance();
7495
willy tarreau9fe663a2005-12-17 13:02:59 +01007496 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7497 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007498
willy tarreau9fe663a2005-12-17 13:02:59 +01007499 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007500
willy tarreau9fe663a2005-12-17 13:02:59 +01007501 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007502 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007503 line++;
7504
7505 arg = 0;
7506 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007507
willy tarreau9fe663a2005-12-17 13:02:59 +01007508 while (*line && arg < MAX_LINE_ARGS) {
7509 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7510 * C equivalent value. Other combinations left unchanged (eg: \1).
7511 */
7512 if (*line == '\\') {
7513 int skip = 0;
7514 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7515 *line = line[1];
7516 skip = 1;
7517 }
7518 else if (line[1] == 'r') {
7519 *line = '\r';
7520 skip = 1;
7521 }
7522 else if (line[1] == 'n') {
7523 *line = '\n';
7524 skip = 1;
7525 }
7526 else if (line[1] == 't') {
7527 *line = '\t';
7528 skip = 1;
7529 }
willy tarreauc1f47532005-12-18 01:08:26 +01007530 else if (line[1] == 'x') {
7531 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7532 unsigned char hex1, hex2;
7533 hex1 = toupper(line[2]) - '0';
7534 hex2 = toupper(line[3]) - '0';
7535 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7536 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7537 *line = (hex1<<4) + hex2;
7538 skip = 3;
7539 }
7540 else {
7541 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7542 return -1;
7543 }
7544 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007545 if (skip) {
7546 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7547 end -= skip;
7548 }
7549 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007550 }
willy tarreaua1598082005-12-17 13:08:06 +01007551 else if (*line == '#' || *line == '\n' || *line == '\r') {
7552 /* end of string, end of loop */
7553 *line = 0;
7554 break;
7555 }
willy tarreauc29948c2005-12-17 13:10:27 +01007556 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007557 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007558 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007559 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007560 line++;
7561 args[++arg] = line;
7562 }
7563 else {
7564 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007565 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007566 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007567
willy tarreau9fe663a2005-12-17 13:02:59 +01007568 /* empty line */
7569 if (!**args)
7570 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007571
willy tarreau9fe663a2005-12-17 13:02:59 +01007572 /* zero out remaining args */
7573 while (++arg < MAX_LINE_ARGS) {
7574 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007575 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007576
willy tarreaua41a8b42005-12-17 14:02:24 +01007577 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007578 confsect = CFG_LISTEN;
7579 else if (!strcmp(args[0], "global")) /* global config */
7580 confsect = CFG_GLOBAL;
7581 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007582
willy tarreau9fe663a2005-12-17 13:02:59 +01007583 switch (confsect) {
7584 case CFG_LISTEN:
7585 if (cfg_parse_listen(file, linenum, args) < 0)
7586 return -1;
7587 break;
7588 case CFG_GLOBAL:
7589 if (cfg_parse_global(file, linenum, args) < 0)
7590 return -1;
7591 break;
7592 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007593 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007594 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007595 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007596
7597
willy tarreau0f7af912005-12-17 12:21:26 +01007598 }
7599 fclose(f);
7600
7601 /*
7602 * Now, check for the integrity of all that we have collected.
7603 */
7604
Willy TARREAU3759f982006-03-01 22:44:17 +01007605 /* will be needed further to delay some tasks */
7606 tv_now(&now);
7607
willy tarreau0f7af912005-12-17 12:21:26 +01007608 if ((curproxy = proxy) == NULL) {
7609 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7610 file);
7611 return -1;
7612 }
7613
7614 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007615 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007616 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007617 curproxy = curproxy->next;
7618 continue;
7619 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007620
7621 if (curproxy->listen == NULL) {
7622 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);
7623 cfgerr++;
7624 }
7625 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007626 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007627 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007628 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7629 file, curproxy->id);
7630 cfgerr++;
7631 }
7632 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7633 if (curproxy->options & PR_O_TRANSP) {
7634 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7635 file, curproxy->id);
7636 cfgerr++;
7637 }
7638 else if (curproxy->srv == NULL) {
7639 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7640 file, curproxy->id);
7641 cfgerr++;
7642 }
willy tarreaua1598082005-12-17 13:08:06 +01007643 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007644 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7645 file, curproxy->id);
7646 }
7647 }
7648 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007649 if (curproxy->cookie_name != NULL) {
7650 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7651 file, curproxy->id);
7652 }
7653 if ((newsrv = curproxy->srv) != NULL) {
7654 Warning("parsing %s : servers will be ignored for listener %s.\n",
7655 file, curproxy->id);
7656 }
willy tarreaue39cd132005-12-17 13:00:18 +01007657 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007658 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7659 file, curproxy->id);
7660 }
willy tarreaue39cd132005-12-17 13:00:18 +01007661 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007662 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7663 file, curproxy->id);
7664 }
7665 }
7666 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7667 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7668 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7669 file, curproxy->id);
7670 cfgerr++;
7671 }
7672 else {
7673 while (newsrv != NULL) {
7674 /* nothing to check for now */
7675 newsrv = newsrv->next;
7676 }
7677 }
7678 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007679
7680 if (curproxy->options & PR_O_LOGASAP)
7681 curproxy->to_log &= ~LW_BYTES;
7682
willy tarreau8337c6b2005-12-17 13:41:01 +01007683 if (curproxy->errmsg.msg400 == NULL) {
7684 curproxy->errmsg.msg400 = (char *)HTTP_400;
7685 curproxy->errmsg.len400 = strlen(HTTP_400);
7686 }
7687 if (curproxy->errmsg.msg403 == NULL) {
7688 curproxy->errmsg.msg403 = (char *)HTTP_403;
7689 curproxy->errmsg.len403 = strlen(HTTP_403);
7690 }
7691 if (curproxy->errmsg.msg408 == NULL) {
7692 curproxy->errmsg.msg408 = (char *)HTTP_408;
7693 curproxy->errmsg.len408 = strlen(HTTP_408);
7694 }
7695 if (curproxy->errmsg.msg500 == NULL) {
7696 curproxy->errmsg.msg500 = (char *)HTTP_500;
7697 curproxy->errmsg.len500 = strlen(HTTP_500);
7698 }
7699 if (curproxy->errmsg.msg502 == NULL) {
7700 curproxy->errmsg.msg502 = (char *)HTTP_502;
7701 curproxy->errmsg.len502 = strlen(HTTP_502);
7702 }
7703 if (curproxy->errmsg.msg503 == NULL) {
7704 curproxy->errmsg.msg503 = (char *)HTTP_503;
7705 curproxy->errmsg.len503 = strlen(HTTP_503);
7706 }
7707 if (curproxy->errmsg.msg504 == NULL) {
7708 curproxy->errmsg.msg504 = (char *)HTTP_504;
7709 curproxy->errmsg.len504 = strlen(HTTP_504);
7710 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007711
7712 /* now we'll start this proxy's health checks if any */
7713 /* 1- count the checkers to run simultaneously */
7714 nbchk = 0;
7715 mininter = 0;
7716 newsrv = curproxy->srv;
7717 while (newsrv != NULL) {
7718 if (newsrv->state & SRV_CHECKED) {
7719 if (!mininter || mininter > newsrv->inter)
7720 mininter = newsrv->inter;
7721 nbchk++;
7722 }
7723 newsrv = newsrv->next;
7724 }
7725
7726 /* 2- start them as far as possible from each others while respecting
7727 * their own intervals. For this, we will start them after their own
7728 * interval added to the min interval divided by the number of servers,
7729 * weighted by the server's position in the list.
7730 */
7731 if (nbchk > 0) {
7732 struct task *t;
7733 int srvpos;
7734
7735 newsrv = curproxy->srv;
7736 srvpos = 0;
7737 while (newsrv != NULL) {
7738 /* should this server be checked ? */
7739 if (newsrv->state & SRV_CHECKED) {
7740 if ((t = pool_alloc(task)) == NULL) {
7741 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7742 return -1;
7743 }
7744
7745 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7746 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7747 t->state = TASK_IDLE;
7748 t->process = process_chk;
7749 t->context = newsrv;
7750
7751 /* check this every ms */
7752 tv_delayfrom(&t->expire, &now,
7753 newsrv->inter + mininter * srvpos / nbchk);
7754 task_queue(t);
7755 //task_wakeup(&rq, t);
7756 srvpos++;
7757 }
7758 newsrv = newsrv->next;
7759 }
7760 }
7761
willy tarreau0f7af912005-12-17 12:21:26 +01007762 curproxy = curproxy->next;
7763 }
7764 if (cfgerr > 0) {
7765 Alert("Errors found in configuration file, aborting.\n");
7766 return -1;
7767 }
7768 else
7769 return 0;
7770}
7771
7772
7773/*
7774 * This function initializes all the necessary variables. It only returns
7775 * if everything is OK. If something fails, it exits.
7776 */
7777void init(int argc, char **argv) {
7778 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007779 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007780 char *old_argv = *argv;
7781 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007782 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007783
7784 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007785 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007786 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007787 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007788 exit(1);
7789 }
7790
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007791 /* initialize the libc's localtime structures once for all so that we
7792 * won't be missing memory if we want to send alerts under OOM conditions.
7793 */
7794 tv_now(&now);
7795 localtime(&now.tv_sec);
7796
willy tarreau4302f492005-12-18 01:00:37 +01007797 /* initialize the log header encoding map : '{|}"#' should be encoded with
7798 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7799 * URL encoding only requires '"', '#' to be encoded as well as non-
7800 * printable characters above.
7801 */
7802 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7803 memset(url_encode_map, 0, sizeof(url_encode_map));
7804 for (i = 0; i < 32; i++) {
7805 FD_SET(i, hdr_encode_map);
7806 FD_SET(i, url_encode_map);
7807 }
7808 for (i = 127; i < 256; i++) {
7809 FD_SET(i, hdr_encode_map);
7810 FD_SET(i, url_encode_map);
7811 }
7812
7813 tmp = "\"#{|}";
7814 while (*tmp) {
7815 FD_SET(*tmp, hdr_encode_map);
7816 tmp++;
7817 }
7818
7819 tmp = "\"#";
7820 while (*tmp) {
7821 FD_SET(*tmp, url_encode_map);
7822 tmp++;
7823 }
7824
willy tarreau64a3cc32005-12-18 01:13:11 +01007825 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7826#if defined(ENABLE_POLL)
7827 cfg_polling_mechanism |= POLL_USE_POLL;
7828#endif
7829#if defined(ENABLE_EPOLL)
7830 cfg_polling_mechanism |= POLL_USE_EPOLL;
7831#endif
7832
willy tarreau0f7af912005-12-17 12:21:26 +01007833 pid = getpid();
7834 progname = *argv;
7835 while ((tmp = strchr(progname, '/')) != NULL)
7836 progname = tmp + 1;
7837
7838 argc--; argv++;
7839 while (argc > 0) {
7840 char *flag;
7841
7842 if (**argv == '-') {
7843 flag = *argv+1;
7844
7845 /* 1 arg */
7846 if (*flag == 'v') {
7847 display_version();
7848 exit(0);
7849 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007850#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007851 else if (*flag == 'd' && flag[1] == 'e')
7852 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007853#endif
7854#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007855 else if (*flag == 'd' && flag[1] == 'p')
7856 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007857#endif
willy tarreau982249e2005-12-18 00:57:06 +01007858 else if (*flag == 'V')
7859 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007860 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007861 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007862 else if (*flag == 'c')
7863 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007864 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007865 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007866 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007867 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007868#if STATTIME > 0
7869 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007870 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007871 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007872 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007873#endif
7874 else { /* >=2 args */
7875 argv++; argc--;
7876 if (argc == 0)
7877 usage(old_argv);
7878
7879 switch (*flag) {
7880 case 'n' : cfg_maxconn = atol(*argv); break;
7881 case 'N' : cfg_maxpconn = atol(*argv); break;
7882 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007883 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007884 default: usage(old_argv);
7885 }
7886 }
7887 }
7888 else
7889 usage(old_argv);
7890 argv++; argc--;
7891 }
7892
willy tarreaud0fb4652005-12-18 01:32:04 +01007893 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7894 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007895
willy tarreau0f7af912005-12-17 12:21:26 +01007896 if (!cfg_cfgfile)
7897 usage(old_argv);
7898
7899 gethostname(hostname, MAX_HOSTNAME_LEN);
7900
willy tarreau12350152005-12-18 01:03:27 +01007901 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007902 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01007903 if (readcfgfile(cfg_cfgfile) < 0) {
7904 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7905 exit(1);
7906 }
willy tarreau12350152005-12-18 01:03:27 +01007907 if (have_appsession)
7908 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007909
willy tarreau982249e2005-12-18 00:57:06 +01007910 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007911 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7912 exit(0);
7913 }
7914
willy tarreau9fe663a2005-12-17 13:02:59 +01007915 if (cfg_maxconn > 0)
7916 global.maxconn = cfg_maxconn;
7917
willy tarreaufe2c5c12005-12-17 14:14:34 +01007918 if (cfg_pidfile) {
7919 if (global.pidfile)
7920 free(global.pidfile);
7921 global.pidfile = strdup(cfg_pidfile);
7922 }
7923
willy tarreau9fe663a2005-12-17 13:02:59 +01007924 if (global.maxconn == 0)
7925 global.maxconn = DEFAULT_MAXCONN;
7926
Willy TARREAU203b0b62006-03-12 18:00:28 +01007927 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01007928
7929 if (arg_mode & MODE_DEBUG) {
7930 /* command line debug mode inhibits configuration mode */
7931 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7932 }
willy tarreau982249e2005-12-18 00:57:06 +01007933 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7934 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007935
7936 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7937 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7938 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7939 }
7940
7941 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7942 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7943 global.nbproc = 1;
7944 }
7945
7946 if (global.nbproc < 1)
7947 global.nbproc = 1;
7948
willy tarreau0f7af912005-12-17 12:21:26 +01007949 StaticReadEvent = (fd_set *)calloc(1,
7950 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007951 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007952 StaticWriteEvent = (fd_set *)calloc(1,
7953 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007954 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007955
7956 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007957 sizeof(struct fdtab) * (global.maxsock));
7958 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007959 fdtab[i].state = FD_STCLOSE;
7960 }
7961}
7962
7963/*
7964 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7965 */
7966int start_proxies() {
7967 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007968 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007969 int fd;
7970
7971 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007972 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01007973 continue;
7974
willy tarreaua41a8b42005-12-17 14:02:24 +01007975 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7976 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007977 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007978 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7979 curproxy->id);
7980 return -1;
7981 }
willy tarreau0f7af912005-12-17 12:21:26 +01007982
willy tarreaua41a8b42005-12-17 14:02:24 +01007983 if (fd >= global.maxsock) {
7984 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7985 curproxy->id);
7986 close(fd);
7987 return -1;
7988 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007989
willy tarreaua41a8b42005-12-17 14:02:24 +01007990 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7991 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7992 (char *) &one, sizeof(one)) == -1)) {
7993 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7994 curproxy->id);
7995 close(fd);
7996 return -1;
7997 }
willy tarreau0f7af912005-12-17 12:21:26 +01007998
willy tarreaua41a8b42005-12-17 14:02:24 +01007999 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8000 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8001 curproxy->id);
8002 }
willy tarreau0f7af912005-12-17 12:21:26 +01008003
willy tarreaua41a8b42005-12-17 14:02:24 +01008004 if (bind(fd,
8005 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008006 listener->addr.ss_family == AF_INET6 ?
8007 sizeof(struct sockaddr_in6) :
8008 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01008009 Alert("cannot bind socket for proxy %s. Aborting.\n",
8010 curproxy->id);
8011 close(fd);
8012 return -1;
8013 }
willy tarreau0f7af912005-12-17 12:21:26 +01008014
willy tarreaua41a8b42005-12-17 14:02:24 +01008015 if (listen(fd, curproxy->maxconn) == -1) {
8016 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8017 curproxy->id);
8018 close(fd);
8019 return -1;
8020 }
willy tarreau0f7af912005-12-17 12:21:26 +01008021
willy tarreaua41a8b42005-12-17 14:02:24 +01008022 /* the function for the accept() event */
8023 fdtab[fd].read = &event_accept;
8024 fdtab[fd].write = NULL; /* never called */
8025 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
8026 curproxy->state = PR_STRUN;
8027 fdtab[fd].state = FD_STLISTEN;
8028 FD_SET(fd, StaticReadEvent);
8029 fd_insert(fd);
8030 listeners++;
8031 }
willy tarreaua1598082005-12-17 13:08:06 +01008032 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01008033 }
8034 return 0;
8035}
8036
willy tarreaub952e1d2005-12-18 01:31:20 +01008037int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008038
8039 appsess *temp1,*temp2;
8040 temp1 = (appsess *)key1;
8041 temp2 = (appsess *)key2;
8042
8043 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8044 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8045
8046 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8047}/* end match_str */
8048
willy tarreaub952e1d2005-12-18 01:31:20 +01008049void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008050 appsess *temp1;
8051
8052 //printf("destroy called\n");
8053 temp1 = (appsess *)data;
8054
8055 if (temp1->sessid)
8056 pool_free_to(apools.sessid, temp1->sessid);
8057
8058 if (temp1->serverid)
8059 pool_free_to(apools.serverid, temp1->serverid);
8060
8061 pool_free(appsess, temp1);
8062} /* end destroy */
8063
8064void appsession_cleanup( void )
8065{
8066 struct proxy *p = proxy;
8067
8068 while(p) {
8069 chtbl_destroy(&(p->htbl_proxy));
8070 p = p->next;
8071 }
8072}/* end appsession_cleanup() */
8073
8074void pool_destroy(void **pool)
8075{
8076 void *temp, *next;
8077 next = pool;
8078 while (next) {
8079 temp = next;
8080 next = *(void **)temp;
8081 free(temp);
8082 }
8083}/* end pool_destroy() */
8084
willy tarreaub952e1d2005-12-18 01:31:20 +01008085void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008086 struct proxy *p = proxy;
8087 struct cap_hdr *h,*h_next;
8088 struct server *s,*s_next;
8089 struct listener *l,*l_next;
8090
8091 while (p) {
8092 if (p->id)
8093 free(p->id);
8094
8095 if (p->check_req)
8096 free(p->check_req);
8097
8098 if (p->cookie_name)
8099 free(p->cookie_name);
8100
8101 if (p->capture_name)
8102 free(p->capture_name);
8103
8104 /* only strup if the user have set in config.
8105 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008106 if (p->errmsg.msg400) free(p->errmsg.msg400);
8107 if (p->errmsg.msg403) free(p->errmsg.msg403);
8108 if (p->errmsg.msg408) free(p->errmsg.msg408);
8109 if (p->errmsg.msg500) free(p->errmsg.msg500);
8110 if (p->errmsg.msg502) free(p->errmsg.msg502);
8111 if (p->errmsg.msg503) free(p->errmsg.msg503);
8112 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008113 */
8114 if (p->appsession_name)
8115 free(p->appsession_name);
8116
8117 h = p->req_cap;
8118 while (h) {
8119 h_next = h->next;
8120 if (h->name)
8121 free(h->name);
8122 pool_destroy(h->pool);
8123 free(h);
8124 h = h_next;
8125 }/* end while(h) */
8126
8127 h = p->rsp_cap;
8128 while (h) {
8129 h_next = h->next;
8130 if (h->name)
8131 free(h->name);
8132
8133 pool_destroy(h->pool);
8134 free(h);
8135 h = h_next;
8136 }/* end while(h) */
8137
8138 s = p->srv;
8139 while (s) {
8140 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008141 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008142 free(s->id);
8143
willy tarreaub952e1d2005-12-18 01:31:20 +01008144 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008145 free(s->cookie);
8146
8147 free(s);
8148 s = s_next;
8149 }/* end while(s) */
8150
8151 l = p->listen;
8152 while (l) {
8153 l_next = l->next;
8154 free(l);
8155 l = l_next;
8156 }/* end while(l) */
8157
8158 pool_destroy((void **) p->req_cap_pool);
8159 pool_destroy((void **) p->rsp_cap_pool);
8160 p = p->next;
8161 }/* end while(p) */
8162
8163 if (global.chroot) free(global.chroot);
8164 if (global.pidfile) free(global.pidfile);
8165
willy tarreau12350152005-12-18 01:03:27 +01008166 if (StaticReadEvent) free(StaticReadEvent);
8167 if (StaticWriteEvent) free(StaticWriteEvent);
8168 if (fdtab) free(fdtab);
8169
8170 pool_destroy(pool_session);
8171 pool_destroy(pool_buffer);
8172 pool_destroy(pool_fdtab);
8173 pool_destroy(pool_requri);
8174 pool_destroy(pool_task);
8175 pool_destroy(pool_capture);
8176 pool_destroy(pool_appsess);
8177
8178 if (have_appsession) {
8179 pool_destroy(apools.serverid);
8180 pool_destroy(apools.sessid);
8181 }
8182} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008183
8184int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008185 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008186 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008187 init(argc, argv);
8188
willy tarreau0f7af912005-12-17 12:21:26 +01008189 signal(SIGQUIT, dump);
8190 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008191 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008192#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008193 signal(SIGINT, sig_int);
8194 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008195#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008196
8197 /* on very high loads, a sigpipe sometimes happen just between the
8198 * getsockopt() which tells "it's OK to write", and the following write :-(
8199 */
willy tarreau3242e862005-12-17 12:27:53 +01008200#ifndef MSG_NOSIGNAL
8201 signal(SIGPIPE, SIG_IGN);
8202#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008203
willy tarreaud0fb4652005-12-18 01:32:04 +01008204 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008205 if (start_proxies() < 0)
8206 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008207
8208 if (listeners == 0) {
8209 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8210 exit(1);
8211 }
8212
willy tarreaudbd3bef2006-01-20 19:35:18 +01008213 /* prepare pause/play signals */
8214 signal(SIGTTOU, sig_pause);
8215 signal(SIGTTIN, sig_listen);
8216
Willy TARREAUe3283d12006-03-01 22:15:29 +01008217 if (global.mode & MODE_DAEMON) {
8218 global.mode &= ~MODE_VERBOSE;
8219 global.mode |= MODE_QUIET;
8220 }
8221
willy tarreaud0fb4652005-12-18 01:32:04 +01008222 /* MODE_QUIET can inhibit alerts and warnings below this line */
8223
8224 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008225 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008226 /* detach from the tty */
8227 fclose(stdin); fclose(stdout); fclose(stderr);
8228 close(0); close(1); close(2);
8229 }
willy tarreau0f7af912005-12-17 12:21:26 +01008230
willy tarreaufe2c5c12005-12-17 14:14:34 +01008231 /* open log & pid files before the chroot */
8232 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8233 int pidfd;
8234 unlink(global.pidfile);
8235 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8236 if (pidfd < 0) {
8237 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8238 exit(1);
8239 }
8240 pidfile = fdopen(pidfd, "w");
8241 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008242
8243 /* chroot if needed */
8244 if (global.chroot != NULL) {
8245 if (chroot(global.chroot) == -1) {
8246 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8247 exit(1);
8248 }
8249 chdir("/");
8250 }
8251
willy tarreaub1285d52005-12-18 01:20:14 +01008252 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008253 if (!global.rlimit_nofile)
8254 global.rlimit_nofile = global.maxsock;
8255
willy tarreaub1285d52005-12-18 01:20:14 +01008256 if (global.rlimit_nofile) {
8257 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8258 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8259 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8260 }
8261 }
8262
willy tarreau9fe663a2005-12-17 13:02:59 +01008263 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008264 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008265 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8266 exit(1);
8267 }
8268
willy tarreau036e1ce2005-12-17 13:46:33 +01008269 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008270 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8271 exit(1);
8272 }
8273
willy tarreaub1285d52005-12-18 01:20:14 +01008274 /* check ulimits */
8275 limit.rlim_cur = limit.rlim_max = 0;
8276 getrlimit(RLIMIT_NOFILE, &limit);
8277 if (limit.rlim_cur < global.maxsock) {
8278 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",
8279 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8280 }
8281
willy tarreau9fe663a2005-12-17 13:02:59 +01008282 if (global.mode & MODE_DAEMON) {
8283 int ret = 0;
8284 int proc;
8285
8286 /* the father launches the required number of processes */
8287 for (proc = 0; proc < global.nbproc; proc++) {
8288 ret = fork();
8289 if (ret < 0) {
8290 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8291 exit(1); /* there has been an error */
8292 }
8293 else if (ret == 0) /* child breaks here */
8294 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008295 if (pidfile != NULL) {
8296 fprintf(pidfile, "%d\n", ret);
8297 fflush(pidfile);
8298 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008299 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008300 /* close the pidfile both in children and father */
8301 if (pidfile != NULL)
8302 fclose(pidfile);
8303 free(global.pidfile);
8304
willy tarreau9fe663a2005-12-17 13:02:59 +01008305 if (proc == global.nbproc)
8306 exit(0); /* parent must leave */
8307
willy tarreau750a4722005-12-17 13:21:24 +01008308 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8309 * that we can detach from the TTY. We MUST NOT do it in other cases since
8310 * it would have already be done, and 0-2 would have been affected to listening
8311 * sockets
8312 */
8313 if (!(global.mode & MODE_QUIET)) {
8314 /* detach from the tty */
8315 fclose(stdin); fclose(stdout); fclose(stderr);
8316 close(0); close(1); close(2); /* close all fd's */
8317 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8318 }
willy tarreaua1598082005-12-17 13:08:06 +01008319 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008320 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008321 }
8322
willy tarreau1c2ad212005-12-18 01:11:29 +01008323#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008324 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008325 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8326 epoll_loop(POLL_LOOP_ACTION_RUN);
8327 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008328 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008329 }
8330 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008331 Warning("epoll() is not available. Using poll()/select() instead.\n");
8332 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008333 }
8334 }
8335#endif
8336
8337#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008338 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008339 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8340 poll_loop(POLL_LOOP_ACTION_RUN);
8341 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008342 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008343 }
8344 else {
8345 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008346 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008347 }
8348 }
8349#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008350 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008351 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8352 select_loop(POLL_LOOP_ACTION_RUN);
8353 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008354 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008355 }
8356 }
8357
willy tarreau0f7af912005-12-17 12:21:26 +01008358
willy tarreau12350152005-12-18 01:03:27 +01008359 /* Free all Hash Keys and all Hash elements */
8360 appsession_cleanup();
8361 /* Do some cleanup */
8362 deinit();
8363
willy tarreau0f7af912005-12-17 12:21:26 +01008364 exit(0);
8365}
willy tarreau12350152005-12-18 01:03:27 +01008366
8367#if defined(DEBUG_HASH)
8368static void print_table(const CHTbl *htbl) {
8369
8370 ListElmt *element;
8371 int i;
8372 appsess *asession;
8373
8374 /*****************************************************************************
8375 * *
8376 * Display the chained hash table. *
8377 * *
8378 *****************************************************************************/
8379
8380 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8381
8382 for (i = 0; i < TBLSIZ; i++) {
8383 fprintf(stdout, "Bucket[%03d]\n", i);
8384
8385 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8386 //fprintf(stdout, "%c", *(char *)list_data(element));
8387 asession = (appsess *)list_data(element);
8388 fprintf(stdout, "ELEM :%s:", asession->sessid);
8389 fprintf(stdout, " Server :%s: \n", asession->serverid);
8390 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8391 }
8392
8393 fprintf(stdout, "\n");
8394 }
8395 return;
8396} /* end print_table */
8397#endif
8398
8399static int appsession_init(void)
8400{
8401 static int initialized = 0;
8402 int idlen;
8403 struct server *s;
8404 struct proxy *p = proxy;
8405
8406 if (!initialized) {
8407 if (!appsession_task_init()) {
8408 apools.sessid = NULL;
8409 apools.serverid = NULL;
8410 apools.ser_waste = 0;
8411 apools.ser_use = 0;
8412 apools.ser_msize = sizeof(void *);
8413 apools.ses_waste = 0;
8414 apools.ses_use = 0;
8415 apools.ses_msize = sizeof(void *);
8416 while (p) {
8417 s = p->srv;
8418 if (apools.ses_msize < p->appsession_len)
8419 apools.ses_msize = p->appsession_len;
8420 while (s) {
8421 idlen = strlen(s->id);
8422 if (apools.ser_msize < idlen)
8423 apools.ser_msize = idlen;
8424 s = s->next;
8425 }
8426 p = p->next;
8427 }
8428 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8429 apools.ses_msize ++;
8430 }
8431 else {
8432 fprintf(stderr, "appsession_task_init failed\n");
8433 return -1;
8434 }
8435 initialized ++;
8436 }
8437 return 0;
8438}
8439
8440static int appsession_task_init(void)
8441{
8442 static int initialized = 0;
8443 struct task *t;
8444 if (!initialized) {
8445 if ((t = pool_alloc(task)) == NULL)
8446 return -1;
8447 t->next = t->prev = t->rqnext = NULL;
8448 t->wq = LIST_HEAD(wait_queue);
8449 t->state = TASK_IDLE;
8450 t->context = NULL;
8451 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8452 task_queue(t);
8453 t->process = appsession_refresh;
8454 initialized ++;
8455 }
8456 return 0;
8457}
8458
8459static int appsession_refresh(struct task *t) {
8460 struct proxy *p = proxy;
8461 CHTbl *htbl;
8462 ListElmt *element, *last;
8463 int i;
8464 appsess *asession;
8465 void *data;
8466
8467 while (p) {
8468 if (p->appsession_name != NULL) {
8469 htbl = &p->htbl_proxy;
8470 /* if we ever give up the use of TBLSIZ, we need to change this */
8471 for (i = 0; i < TBLSIZ; i++) {
8472 last = NULL;
8473 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8474 asession = (appsess *)list_data(element);
8475 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8476 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8477 int len;
8478 /*
8479 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8480 */
8481 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8482 asession->sessid, asession->serverid?asession->serverid:"(null)");
8483 write(1, trash, len);
8484 }
8485 /* delete the expired element from within the hash table */
8486 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8487 && (htbl->table[i].destroy != NULL)) {
8488 htbl->table[i].destroy(data);
8489 }
8490 if (last == NULL) {/* patient lost his head, get a new one */
8491 element = list_head(&htbl->table[i]);
8492 if (element == NULL) break; /* no heads left, go to next patient */
8493 }
8494 else
8495 element = last;
8496 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8497 else
8498 last = element;
8499 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8500 }
8501 }
8502 p = p->next;
8503 }
8504 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8505 return TBLCHKINT;
8506} /* end appsession_refresh */
8507