blob: b6682b43b4f989785a80861d966832f28562e963 [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 tarreau0174f312005-12-18 01:02:42 +01003 * 2000-2005 - 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 tarreau0f7af912005-12-17 12:21:26 +010033 *
34 */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <unistd.h>
39#include <string.h>
40#include <ctype.h>
41#include <sys/time.h>
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <netinet/tcp.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <netdb.h>
48#include <fcntl.h>
49#include <errno.h>
50#include <signal.h>
51#include <stdarg.h>
52#include <sys/resource.h>
53#include <time.h>
54#include <regex.h>
55#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010056#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010057#include <linux/netfilter_ipv4.h>
58#endif
willy tarreau0f7af912005-12-17 12:21:26 +010059
willy tarreau0174f312005-12-18 01:02:42 +010060#define HAPROXY_VERSION "1.2.3"
61#define HAPROXY_DATE "2005/01/22"
willy tarreau0f7af912005-12-17 12:21:26 +010062
63/* this is for libc5 for example */
64#ifndef TCP_NODELAY
65#define TCP_NODELAY 1
66#endif
67
68#ifndef SHUT_RD
69#define SHUT_RD 0
70#endif
71
72#ifndef SHUT_WR
73#define SHUT_WR 1
74#endif
75
willy tarreau0174f312005-12-18 01:02:42 +010076/*
77 * BUFSIZE defines the size of a read and write buffer. It is the maximum
78 * amount of bytes which can be stored by the proxy for each session. However,
79 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
80 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
81 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
82 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
83 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
84 */
85#ifndef BUFSIZE
86#define BUFSIZE 16384
87#endif
willy tarreau0f7af912005-12-17 12:21:26 +010088
89// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +010090#ifndef MAXREWRITE
91#define MAXREWRITE (BUFSIZE / 2)
92#endif
93
willy tarreau9fe663a2005-12-17 13:02:59 +010094#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +010095#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +010096
willy tarreau5cbea6f2005-12-17 12:48:26 +010097// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +010098#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +010099
willy tarreaue39cd132005-12-17 13:00:18 +0100100// max # of added headers per request
101#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100102
103// max # of matches per regexp
104#define MAX_MATCH 10
105
willy tarreau0174f312005-12-18 01:02:42 +0100106// cookie delimitor in "prefix" mode. This character is inserted between the
107// persistence cookie and the original value. The '~' is allowed by RFC2965,
108// and should not be too common in server names.
109#ifndef COOKIE_DELIM
110#define COOKIE_DELIM '~'
111#endif
112
willy tarreau0f7af912005-12-17 12:21:26 +0100113#define CONN_RETRIES 3
114
willy tarreau5cbea6f2005-12-17 12:48:26 +0100115#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100116#define DEF_CHKINTR 2000
117#define DEF_FALLTIME 3
118#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100119#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100120
willy tarreau9fe663a2005-12-17 13:02:59 +0100121/* default connections limit */
122#define DEFAULT_MAXCONN 2000
123
willy tarreau0f7af912005-12-17 12:21:26 +0100124/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
125#define INTBITS 5
126
127/* show stats this every millisecond, 0 to disable */
128#ifndef STATTIME
129#define STATTIME 2000
130#endif
131
willy tarreau5cbea6f2005-12-17 12:48:26 +0100132/* this reduces the number of calls to select() by choosing appropriate
133 * sheduler precision in milliseconds. It should be near the minimum
134 * time that is needed by select() to collect all events. All timeouts
135 * are rounded up by adding this value prior to pass it to select().
136 */
137#define SCHEDULER_RESOLUTION 9
138
willy tarreau0f7af912005-12-17 12:21:26 +0100139#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
140#define SETNOW(a) (*a=now)
141
willy tarreau9da061b2005-12-17 12:29:56 +0100142/****** string-specific macros and functions ******/
143/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
144#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
145
146/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
147#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
148
willy tarreau0174f312005-12-18 01:02:42 +0100149/* returns 1 only if only zero or one bit is set in X, which means that X is a
150 * power of 2, and 0 otherwise */
151#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100152/*
153 * copies at most <size-1> chars from <src> to <dst>. Last char is always
154 * set to 0, unless <size> is 0. The number of chars copied is returned
155 * (excluding the terminating zero).
156 * This code has been optimized for size and speed : on x86, it's 45 bytes
157 * long, uses only registers, and consumes only 4 cycles per char.
158 */
willy tarreau750a4722005-12-17 13:21:24 +0100159int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100160 char *orig = dst;
161 if (size) {
162 while (--size && (*dst = *src)) {
163 src++; dst++;
164 }
165 *dst = 0;
166 }
167 return dst - orig;
168}
willy tarreau9da061b2005-12-17 12:29:56 +0100169
willy tarreau4302f492005-12-18 01:00:37 +0100170/*
171 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
172 * dynamically allocated. In the first case, <__pool> is updated to point to
173 * the next element in the list.
174 */
175#define pool_alloc_from(__pool, __len) ({ \
176 void *__p; \
177 if ((__p = (__pool)) == NULL) \
178 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
179 else { \
180 __pool = *(void **)(__pool); \
181 } \
182 __p; \
183})
184
185/*
186 * Puts a memory area back to the corresponding pool.
187 * Items are chained directly through a pointer that
188 * is written in the beginning of the memory area, so
189 * there's no need for any carrier cell. This implies
190 * that each memory area is at least as big as one
191 * pointer.
192 */
193#define pool_free_to(__pool, __ptr) ({ \
194 *(void **)(__ptr) = (void *)(__pool); \
195 __pool = (void *)(__ptr); \
196})
197
198
willy tarreau0f7af912005-12-17 12:21:26 +0100199#define MEM_OPTIM
200#ifdef MEM_OPTIM
201/*
202 * Returns a pointer to type <type> taken from the
203 * pool <pool_type> or dynamically allocated. In the
204 * first case, <pool_type> is updated to point to the
205 * next element in the list.
206 */
207#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100208 void *__p; \
209 if ((__p = pool_##type) == NULL) \
210 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100211 else { \
212 pool_##type = *(void **)pool_##type; \
213 } \
willy tarreau4302f492005-12-18 01:00:37 +0100214 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100215})
216
217/*
218 * Puts a memory area back to the corresponding pool.
219 * Items are chained directly through a pointer that
220 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100221 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100222 * that each memory area is at least as big as one
223 * pointer.
224 */
225#define pool_free(type, ptr) ({ \
226 *(void **)ptr = (void *)pool_##type; \
227 pool_##type = (void *)ptr; \
228})
229
230#else
231#define pool_alloc(type) (calloc(1,sizeof_##type));
232#define pool_free(type, ptr) (free(ptr));
233#endif /* MEM_OPTIM */
234
willy tarreau5cbea6f2005-12-17 12:48:26 +0100235#define sizeof_task sizeof(struct task)
236#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100237#define sizeof_buffer sizeof(struct buffer)
238#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100239#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100240#define sizeof_capture CAPTURE_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100241
willy tarreau5cbea6f2005-12-17 12:48:26 +0100242/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100243#define FD_STCLOSE 0
244#define FD_STLISTEN 1
245#define FD_STCONN 2
246#define FD_STREADY 3
247#define FD_STERROR 4
248
willy tarreau5cbea6f2005-12-17 12:48:26 +0100249/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100250#define TASK_IDLE 0
251#define TASK_RUNNING 1
252
willy tarreau5cbea6f2005-12-17 12:48:26 +0100253/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100254#define PR_STNEW 0
255#define PR_STIDLE 1
256#define PR_STRUN 2
257#define PR_STDISABLED 3
258
willy tarreau5cbea6f2005-12-17 12:48:26 +0100259/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100260#define PR_MODE_TCP 0
261#define PR_MODE_HTTP 1
262#define PR_MODE_HEALTH 2
263
willy tarreau5cbea6f2005-12-17 12:48:26 +0100264/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100265#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
266#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
267#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
268#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
269#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
270#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
271#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
272#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100273#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100274#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
275#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
276#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
277#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
278#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
279#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
280#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
281#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
282#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
283#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
284#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100285
willy tarreaue39cd132005-12-17 13:00:18 +0100286/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100287#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
288#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
289#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
290#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
291#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
292#define SN_POST 0x00000020 /* the request was an HTTP POST */
293
294#define SN_CK_NONE 0x00000000 /* this session had no cookie */
295#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
296#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
297#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
298#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
299#define SN_CK_SHIFT 6 /* bit shift */
300
301#define SN_ERR_CLITO 0x00000100 /* client time-out */
302#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
303#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
304#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
305#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
306#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
307#define SN_ERR_SHIFT 8 /* bit shift */
308
309#define SN_FINST_R 0x00001000 /* session ended during client request */
310#define SN_FINST_C 0x00002000 /* session ended during server connect */
311#define SN_FINST_H 0x00003000 /* session ended during server headers */
312#define SN_FINST_D 0x00004000 /* session ended during data phase */
313#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
314#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
315#define SN_FINST_SHIFT 12 /* bit shift */
316
317#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
318#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
319#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
320#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
321#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100322#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100323#define SN_SCK_SHIFT 16 /* bit shift */
324
willy tarreau97f58572005-12-18 00:53:44 +0100325#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
326#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
327#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328
329/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100330#define CL_STHEADERS 0
331#define CL_STDATA 1
332#define CL_STSHUTR 2
333#define CL_STSHUTW 3
334#define CL_STCLOSE 4
335
willy tarreau5cbea6f2005-12-17 12:48:26 +0100336/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100337#define SV_STIDLE 0
338#define SV_STCONN 1
339#define SV_STHEADERS 2
340#define SV_STDATA 3
341#define SV_STSHUTR 4
342#define SV_STSHUTW 5
343#define SV_STCLOSE 6
344
345/* result of an I/O event */
346#define RES_SILENT 0 /* didn't happen */
347#define RES_DATA 1 /* data were sent or received */
348#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
349#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
350
willy tarreau9fe663a2005-12-17 13:02:59 +0100351/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100352#define MODE_DEBUG 1
353#define MODE_STATS 2
354#define MODE_LOG 4
355#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100356#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100357#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100358#define MODE_VERBOSE 64
willy tarreau5cbea6f2005-12-17 12:48:26 +0100359
360/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100361#define SRV_RUNNING 1 /* the server is UP */
362#define SRV_BACKUP 2 /* this server is a backup server */
363#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100364#define SRV_BIND_SRC 8 /* this server uses a specific source address */
willy tarreau0f7af912005-12-17 12:21:26 +0100365
willy tarreaue39cd132005-12-17 13:00:18 +0100366/* what to do when a header matches a regex */
367#define ACT_ALLOW 0 /* allow the request */
368#define ACT_REPLACE 1 /* replace the matching header */
369#define ACT_REMOVE 2 /* remove the matching header */
370#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100371#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100372
willy tarreau9fe663a2005-12-17 13:02:59 +0100373/* configuration sections */
374#define CFG_NONE 0
375#define CFG_GLOBAL 1
376#define CFG_LISTEN 2
377
willy tarreaua1598082005-12-17 13:08:06 +0100378/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100379#define LW_DATE 1 /* date */
380#define LW_CLIP 2 /* CLient IP */
381#define LW_SVIP 4 /* SerVer IP */
382#define LW_SVID 8 /* server ID */
383#define LW_REQ 16 /* http REQuest */
384#define LW_RESP 32 /* http RESPonse */
385#define LW_PXIP 64 /* proxy IP */
386#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100387#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100388#define LW_COOKIE 512 /* captured cookie */
389#define LW_REQHDR 1024 /* request header(s) */
390#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100391
willy tarreau0f7af912005-12-17 12:21:26 +0100392/*********************************************************************/
393
394#define LIST_HEAD(a) ((void *)(&(a)))
395
396/*********************************************************************/
397
willy tarreau4302f492005-12-18 01:00:37 +0100398struct cap_hdr {
399 struct cap_hdr *next;
400 char *name; /* header name, case insensitive */
401 int namelen; /* length of the header name, to speed-up lookups */
402 int len; /* capture length, not including terminal zero */
403 int index; /* index in the output array */
404 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
405};
406
willy tarreau0f7af912005-12-17 12:21:26 +0100407struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100408 struct hdr_exp *next;
409 regex_t *preg; /* expression to look for */
410 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
411 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100412};
413
414struct buffer {
415 unsigned int l; /* data length */
416 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100417 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100418 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100419 char data[BUFSIZE];
420};
421
422struct server {
423 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100424 int state; /* server state (SRV_*) */
425 int cklen; /* the len of the cookie, to speed up checks */
426 char *cookie; /* the id set in the cookie */
427 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100428 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100429 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100430 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100431 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100432 int rise, fall; /* time in iterations */
433 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100434 int result; /* 0 = connect OK, -1 = connect KO */
435 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100436 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100437};
438
willy tarreau5cbea6f2005-12-17 12:48:26 +0100439/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100440struct task {
441 struct task *next, *prev; /* chaining ... */
442 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100443 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100444 int state; /* task state : IDLE or RUNNING */
445 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100446 int (*process)(struct task *t); /* the function which processes the task */
447 void *context; /* the task's context */
448};
449
450/* WARNING: if new fields are added, they must be initialized in event_accept() */
451struct session {
452 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100453 /* application specific below */
454 struct timeval crexpire; /* expiration date for a client read */
455 struct timeval cwexpire; /* expiration date for a client write */
456 struct timeval srexpire; /* expiration date for a server read */
457 struct timeval swexpire; /* expiration date for a server write */
458 struct timeval cnexpire; /* expiration date for a connect */
459 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
460 struct proxy *proxy; /* the proxy this socket belongs to */
461 int cli_fd; /* the client side fd */
462 int srv_fd; /* the server side fd */
463 int cli_state; /* state of the client side */
464 int srv_state; /* state of the server side */
465 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100466 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100467 struct buffer *req; /* request buffer */
468 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100469 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100470 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100471 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100472 char **req_cap; /* array of captured request headers (may be NULL) */
473 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100474 struct {
475 int logwait; /* log fields waiting to be collected : LW_* */
476 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
477 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
478 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
479 long t_data; /* delay before the first data byte from the server ... */
480 unsigned long t_close; /* total session duration */
481 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100482 char *cli_cookie; /* cookie presented by the client, in capture mode */
483 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100484 int status; /* HTTP status from the server, negative if from proxy */
485 long long bytes; /* number of bytes transferred from the server */
486 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100487 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100488};
489
willy tarreaua41a8b42005-12-17 14:02:24 +0100490struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100491 int fd; /* the listen socket */
492 struct sockaddr_storage addr; /* the address we listen to */
493 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100494};
495
496
willy tarreau0f7af912005-12-17 12:21:26 +0100497struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100498 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100499 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100500 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100501 struct server *srv, *cursrv; /* known servers, current server */
502 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100503 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100504 int cookie_len; /* strlen(cookie_len), computed only once */
505 char *capture_name; /* beginning of the name of the cookie to capture */
506 int capture_namelen; /* length of the cookie name to match */
507 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100508 int clitimeout; /* client I/O timeout (in milliseconds) */
509 int srvtimeout; /* server I/O timeout (in milliseconds) */
510 int contimeout; /* connect timeout (in milliseconds) */
511 char *id; /* proxy id */
512 int nbconn; /* # of active sessions */
513 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100514 int conn_retries; /* maximum number of connect retries */
515 int options; /* PR_O_REDISP, PR_O_TRANSP */
516 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100517 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100518 struct proxy *next;
519 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
520 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100521 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100522 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100523 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100524 int nb_reqadd, nb_rspadd;
525 struct hdr_exp *req_exp; /* regular expressions for request headers */
526 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100527 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
528 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
529 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
530 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100531 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100532 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100533 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
534 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100535 struct {
536 char *msg400; /* message for error 400 */
537 int len400; /* message length for error 400 */
538 char *msg403; /* message for error 403 */
539 int len403; /* message length for error 403 */
540 char *msg408; /* message for error 408 */
541 int len408; /* message length for error 408 */
542 char *msg500; /* message for error 500 */
543 int len500; /* message length for error 500 */
544 char *msg502; /* message for error 502 */
545 int len502; /* message length for error 502 */
546 char *msg503; /* message for error 503 */
547 int len503; /* message length for error 503 */
548 char *msg504; /* message for error 504 */
549 int len504; /* message length for error 504 */
550 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100551};
552
553/* info about one given fd */
554struct fdtab {
555 int (*read)(int fd); /* read function */
556 int (*write)(int fd); /* write function */
557 struct task *owner; /* the session (or proxy) associated with this fd */
558 int state; /* the state of this fd */
559};
560
561/*********************************************************************/
562
willy tarreau0f7af912005-12-17 12:21:26 +0100563int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100564char *cfg_cfgfile = NULL; /* configuration file */
565char *progname = NULL; /* program name */
566int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100567
568/* global options */
569static struct {
570 int uid;
571 int gid;
572 int nbproc;
573 int maxconn;
574 int maxsock; /* max # of sockets */
575 int mode;
576 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100577 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100578 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100579 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100580 struct sockaddr_in logsrv1, logsrv2;
581} global = {
582 logfac1 : -1,
583 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100584 loglev1 : 7, /* max syslog level : debug */
585 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100586 /* others NULL OK */
587};
588
willy tarreau0f7af912005-12-17 12:21:26 +0100589/*********************************************************************/
590
591fd_set *ReadEvent,
592 *WriteEvent,
593 *StaticReadEvent,
594 *StaticWriteEvent;
595
596void **pool_session = NULL,
597 **pool_buffer = NULL,
598 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100599 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100600 **pool_task = NULL,
601 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100602
603struct proxy *proxy = NULL; /* list of all existing proxies */
604struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100605struct task *rq = NULL; /* global run queue */
606struct task wait_queue = { /* global wait queue */
607 prev:LIST_HEAD(wait_queue),
608 next:LIST_HEAD(wait_queue)
609};
willy tarreau0f7af912005-12-17 12:21:26 +0100610
willy tarreau0f7af912005-12-17 12:21:26 +0100611static int totalconn = 0; /* total # of terminated sessions */
612static int actconn = 0; /* # of active sessions */
613static int maxfd = 0; /* # of the highest fd + 1 */
614static int listeners = 0; /* # of listeners */
615static int stopping = 0; /* non zero means stopping in progress */
616static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100617static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100618
619static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100620/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100621static char trash[BUFSIZE];
622
willy tarreaudd07e972005-12-18 00:48:48 +0100623const int zero = 0;
624const int one = 1;
625
willy tarreau0f7af912005-12-17 12:21:26 +0100626/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100627 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100628 */
629
630#define MAX_SYSLOG_LEN 1024
631#define NB_LOG_FACILITIES 24
632const char *log_facilities[NB_LOG_FACILITIES] = {
633 "kern", "user", "mail", "daemon",
634 "auth", "syslog", "lpr", "news",
635 "uucp", "cron", "auth2", "ftp",
636 "ntp", "audit", "alert", "cron2",
637 "local0", "local1", "local2", "local3",
638 "local4", "local5", "local6", "local7"
639};
640
641
642#define NB_LOG_LEVELS 8
643const char *log_levels[NB_LOG_LEVELS] = {
644 "emerg", "alert", "crit", "err",
645 "warning", "notice", "info", "debug"
646};
647
648#define SYSLOG_PORT 514
649
650const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
651 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100652
653const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
654const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
655const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
656const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
657 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
658 unknown, Set-cookie Rewritten */
659
willy tarreau0f7af912005-12-17 12:21:26 +0100660#define MAX_HOSTNAME_LEN 32
661static char hostname[MAX_HOSTNAME_LEN] = "";
662
willy tarreau8337c6b2005-12-17 13:41:01 +0100663const char *HTTP_302 =
664 "HTTP/1.0 302 Found\r\n"
665 "Cache-Control: no-cache\r\n"
666 "Connection: close\r\n"
667 "Location: "; /* not terminated since it will be concatenated with the URL */
668
willy tarreaua1598082005-12-17 13:08:06 +0100669const char *HTTP_400 =
670 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100671 "Cache-Control: no-cache\r\n"
672 "Connection: close\r\n"
673 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100674 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100675
willy tarreaua1598082005-12-17 13:08:06 +0100676const char *HTTP_403 =
677 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100678 "Cache-Control: no-cache\r\n"
679 "Connection: close\r\n"
680 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100681 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
682
willy tarreau8337c6b2005-12-17 13:41:01 +0100683const char *HTTP_408 =
684 "HTTP/1.0 408 Request Time-out\r\n"
685 "Cache-Control: no-cache\r\n"
686 "Connection: close\r\n"
687 "\r\n"
688 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
689
willy tarreau750a4722005-12-17 13:21:24 +0100690const char *HTTP_500 =
691 "HTTP/1.0 500 Server Error\r\n"
692 "Cache-Control: no-cache\r\n"
693 "Connection: close\r\n"
694 "\r\n"
695 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100696
697const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100698 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100699 "Cache-Control: no-cache\r\n"
700 "Connection: close\r\n"
701 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100702 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
703
704const char *HTTP_503 =
705 "HTTP/1.0 503 Service Unavailable\r\n"
706 "Cache-Control: no-cache\r\n"
707 "Connection: close\r\n"
708 "\r\n"
709 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
710
711const char *HTTP_504 =
712 "HTTP/1.0 504 Gateway Time-out\r\n"
713 "Cache-Control: no-cache\r\n"
714 "Connection: close\r\n"
715 "\r\n"
716 "<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 +0100717
willy tarreau0f7af912005-12-17 12:21:26 +0100718/*********************************************************************/
719/* statistics ******************************************************/
720/*********************************************************************/
721
willy tarreau750a4722005-12-17 13:21:24 +0100722#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100723static int stats_tsk_lsrch, stats_tsk_rsrch,
724 stats_tsk_good, stats_tsk_right, stats_tsk_left,
725 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100726#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100727
728
729/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100730/* debugging *******************************************************/
731/*********************************************************************/
732#ifdef DEBUG_FULL
733static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
734static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
735#endif
736
737/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100738/* function prototypes *********************************************/
739/*********************************************************************/
740
741int event_accept(int fd);
742int event_cli_read(int fd);
743int event_cli_write(int fd);
744int event_srv_read(int fd);
745int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100746int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100747
748/*********************************************************************/
749/* general purpose functions ***************************************/
750/*********************************************************************/
751
752void display_version() {
753 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau0174f312005-12-18 01:02:42 +0100754 printf("Copyright 2000-2005 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100755}
756
757/*
758 * This function prints the command line usage and exits
759 */
760void usage(char *name) {
761 display_version();
762 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100763 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100764#if STATTIME > 0
765 "sl"
766#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100767 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100768 " -v displays version\n"
769 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100770 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100771#if STATTIME > 0
772 " -s enables statistics output\n"
773 " -l enables long statistics format\n"
774#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100775 " -D goes daemon ; implies -q\n"
776 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100777 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100778 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100779 " -N sets the default, per-proxy maximum # of connections (%d)\n"
780 " -p writes pids of all children to this file\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100781 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100782 exit(1);
783}
784
785
786/*
787 * Displays the message on stderr with the date and pid.
788 */
789void Alert(char *fmt, ...) {
790 va_list argp;
791 struct timeval tv;
792 struct tm *tm;
793
willy tarreau982249e2005-12-18 00:57:06 +0100794 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100795 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100796
willy tarreau5cbea6f2005-12-17 12:48:26 +0100797 gettimeofday(&tv, NULL);
798 tm=localtime(&tv.tv_sec);
799 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100800 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100801 vfprintf(stderr, fmt, argp);
802 fflush(stderr);
803 va_end(argp);
804 }
willy tarreau0f7af912005-12-17 12:21:26 +0100805}
806
807
808/*
809 * Displays the message on stderr with the date and pid.
810 */
811void Warning(char *fmt, ...) {
812 va_list argp;
813 struct timeval tv;
814 struct tm *tm;
815
willy tarreau982249e2005-12-18 00:57:06 +0100816 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100817 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100818
willy tarreau5cbea6f2005-12-17 12:48:26 +0100819 gettimeofday(&tv, NULL);
820 tm=localtime(&tv.tv_sec);
821 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100822 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100823 vfprintf(stderr, fmt, argp);
824 fflush(stderr);
825 va_end(argp);
826 }
827}
828
829/*
830 * Displays the message on <out> only if quiet mode is not set.
831 */
832void qfprintf(FILE *out, char *fmt, ...) {
833 va_list argp;
834
willy tarreau982249e2005-12-18 00:57:06 +0100835 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100836 va_start(argp, fmt);
837 vfprintf(out, fmt, argp);
838 fflush(out);
839 va_end(argp);
840 }
willy tarreau0f7af912005-12-17 12:21:26 +0100841}
842
843
844/*
845 * converts <str> to a struct sockaddr_in* which is locally allocated.
846 * The format is "addr:port", where "addr" can be empty or "*" to indicate
847 * INADDR_ANY.
848 */
849struct sockaddr_in *str2sa(char *str) {
850 static struct sockaddr_in sa;
851 char *c;
852 int port;
853
willy tarreaua1598082005-12-17 13:08:06 +0100854 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100855 str=strdup(str);
856
857 if ((c=strrchr(str,':')) != NULL) {
858 *c++=0;
859 port=atol(c);
860 }
861 else
862 port=0;
863
864 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
865 sa.sin_addr.s_addr = INADDR_ANY;
866 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100867 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100868 struct hostent *he;
869
870 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100871 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100872 }
873 else
874 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
875 }
876 sa.sin_port=htons(port);
877 sa.sin_family=AF_INET;
878
879 free(str);
880 return &sa;
881}
882
willy tarreau9fe663a2005-12-17 13:02:59 +0100883
884/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100885 * converts <str> to a list of listeners which are dynamically allocated.
886 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
887 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
888 * - <port> is a numerical port from 1 to 65535 ;
889 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
890 * This can be repeated as many times as necessary, separated by a coma.
891 * The <tail> argument is a pointer to a current list which should be appended
892 * to the tail of the new list. The pointer to the new list is returned.
893 */
894struct listener *str2listener(char *str, struct listener *tail) {
895 struct listener *l;
896 char *c, *next, *range, *dupstr;
897 int port, end;
898
899 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +0100900
willy tarreaua41a8b42005-12-17 14:02:24 +0100901 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100902 struct sockaddr_storage ss;
903
willy tarreaua41a8b42005-12-17 14:02:24 +0100904 str = next;
905 /* 1) look for the end of the first address */
906 if ((next = strrchr(str, ',')) != NULL) {
907 *next++ = 0;
908 }
909
willy tarreau8a86dbf2005-12-18 00:45:59 +0100910 /* 2) look for the addr/port delimiter, it's the last colon. */
911 if ((range = strrchr(str, ':')) == NULL) {
912 Alert("Missing port number: '%s'\n", str);
913 }
914
915 *range++ = 0;
916
917 if (strrchr(str, ':') != NULL) {
918 /* IPv6 address contains ':' */
919 memset(&ss, 0, sizeof(ss));
920 ss.ss_family = AF_INET6;
921
922 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
923 Alert("Invalid server address: '%s'\n", str);
924 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100925 }
926 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100927 memset(&ss, 0, sizeof(ss));
928 ss.ss_family = AF_INET;
929
930 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
931 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
932 }
933 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
934 struct hostent *he;
935
936 if ((he = gethostbyname(str)) == NULL) {
937 Alert("Invalid server name: '%s'\n", str);
938 }
939 else
940 ((struct sockaddr_in *)&ss)->sin_addr =
941 *(struct in_addr *) *(he->h_addr_list);
942 }
943 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100944
945 /* 3) look for the port-end delimiter */
946 if ((c = strchr(range, '-')) != NULL) {
947 *c++ = 0;
948 end = atol(c);
949 }
950 else {
951 end = atol(range);
952 }
953
954 for (port = atol(range); port <= end; port++) {
955 l = (struct listener *)calloc(1, sizeof(struct listener));
956 l->next = tail;
957 tail = l;
958
willy tarreau8a86dbf2005-12-18 00:45:59 +0100959 l->addr = ss;
960 if (ss.ss_family == AF_INET6)
961 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
962 else
963 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
964
willy tarreaua41a8b42005-12-17 14:02:24 +0100965 } /* end for(port) */
966 } /* end while(next) */
967 free(dupstr);
968 return tail;
969}
970
willy tarreau4302f492005-12-18 01:00:37 +0100971
972#define FD_SETS_ARE_BITFIELDS
973#ifdef FD_SETS_ARE_BITFIELDS
974/*
975 * This map is used with all the FD_* macros to check whether a particular bit
976 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
977 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
978 * byte should be encoded. Be careful to always pass bytes from 0 to 255
979 * exclusively to the macros.
980 */
981fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
982fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
983
984#else
985#error "Check if your OS uses bitfields for fd_sets"
986#endif
987
988/* will try to encode the string <string> replacing all characters tagged in
989 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
990 * prefixed by <escape>, and will store the result between <start> (included
991 *) and <stop> (excluded), and will always terminate the string with a '\0'
992 * before <stop>. The position of the '\0' is returned if the conversion
993 * completes. If bytes are missing between <start> and <stop>, then the
994 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
995 * cannot even be stored so we return <start> without writing the 0.
996 * The input string must also be zero-terminated.
997 */
998char hextab[16] = "0123456789ABCDEF";
999char *encode_string(char *start, char *stop,
1000 const char escape, const fd_set *map,
1001 const char *string)
1002{
1003 if (start < stop) {
1004 stop--; /* reserve one byte for the final '\0' */
1005 while (start < stop && *string != 0) {
1006 if (!FD_ISSET((unsigned char)(*string), map))
1007 *start++ = *string;
1008 else {
1009 if (start + 3 >= stop)
1010 break;
1011 *start++ = escape;
1012 *start++ = hextab[(*string >> 4) & 15];
1013 *start++ = hextab[*string & 15];
1014 }
1015 string++;
1016 }
1017 *start = '\0';
1018 }
1019 return start;
1020}
willy tarreaua41a8b42005-12-17 14:02:24 +01001021
1022/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001023 * This function sends a syslog message to both log servers of a proxy,
1024 * or to global log servers if the proxy is NULL.
1025 * It also tries not to waste too much time computing the message header.
1026 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001027 */
1028void send_log(struct proxy *p, int level, char *message, ...) {
1029 static int logfd = -1; /* syslog UDP socket */
1030 static long tvsec = -1; /* to force the string to be initialized */
1031 struct timeval tv;
1032 va_list argp;
1033 static char logmsg[MAX_SYSLOG_LEN];
1034 static char *dataptr = NULL;
1035 int fac_level;
1036 int hdr_len, data_len;
1037 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001038 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001039 int nbloggers = 0;
1040 char *log_ptr;
1041
1042 if (logfd < 0) {
1043 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1044 return;
1045 }
1046
1047 if (level < 0 || progname == NULL || message == NULL)
1048 return;
1049
1050 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001051 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001052 /* this string is rebuild only once a second */
1053 struct tm *tm = localtime(&tv.tv_sec);
1054 tvsec = tv.tv_sec;
1055
willy tarreauc29948c2005-12-17 13:10:27 +01001056 hdr_len = snprintf(logmsg, sizeof(logmsg),
1057 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1058 monthname[tm->tm_mon],
1059 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1060 progname, pid);
1061 /* WARNING: depending upon implementations, snprintf may return
1062 * either -1 or the number of bytes that would be needed to store
1063 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001064 */
willy tarreauc29948c2005-12-17 13:10:27 +01001065 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1066 hdr_len = sizeof(logmsg);
1067
1068 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001069 }
1070
1071 va_start(argp, message);
1072 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001073 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1074 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001075 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001076 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001077
1078 if (p == NULL) {
1079 if (global.logfac1 >= 0) {
1080 sa[nbloggers] = &global.logsrv1;
1081 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001082 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001083 nbloggers++;
1084 }
1085 if (global.logfac2 >= 0) {
1086 sa[nbloggers] = &global.logsrv2;
1087 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001088 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001089 nbloggers++;
1090 }
1091 } else {
1092 if (p->logfac1 >= 0) {
1093 sa[nbloggers] = &p->logsrv1;
1094 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001095 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001096 nbloggers++;
1097 }
1098 if (p->logfac2 >= 0) {
1099 sa[nbloggers] = &p->logsrv2;
1100 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001101 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001102 nbloggers++;
1103 }
1104 }
1105
1106 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001107 /* we can filter the level of the messages that are sent to each logger */
1108 if (level > loglevel[nbloggers])
1109 continue;
1110
willy tarreauc29948c2005-12-17 13:10:27 +01001111 /* For each target, we may have a different facility.
1112 * We can also have a different log level for each message.
1113 * This induces variations in the message header length.
1114 * Since we don't want to recompute it each time, nor copy it every
1115 * time, we only change the facility in the pre-computed header,
1116 * and we change the pointer to the header accordingly.
1117 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001118 fac_level = (facilities[nbloggers] << 3) + level;
1119 log_ptr = logmsg + 3; /* last digit of the log level */
1120 do {
1121 *log_ptr = '0' + fac_level % 10;
1122 fac_level /= 10;
1123 log_ptr--;
1124 } while (fac_level && log_ptr > logmsg);
1125 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001126
willy tarreauc29948c2005-12-17 13:10:27 +01001127 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001128
1129#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001130 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001131 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1132#else
willy tarreauc29948c2005-12-17 13:10:27 +01001133 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001134 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1135#endif
1136 }
willy tarreau0f7af912005-12-17 12:21:26 +01001137}
1138
1139
1140/* sets <tv> to the current time */
1141static inline struct timeval *tv_now(struct timeval *tv) {
1142 if (tv)
1143 gettimeofday(tv, NULL);
1144 return tv;
1145}
1146
1147/*
1148 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1149 */
1150static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1151 if (!tv || !from)
1152 return NULL;
1153 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1154 tv->tv_sec = from->tv_sec + (ms/1000);
1155 while (tv->tv_usec >= 1000000) {
1156 tv->tv_usec -= 1000000;
1157 tv->tv_sec++;
1158 }
1159 return tv;
1160}
1161
1162/*
1163 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1164 */
1165static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001166 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001167 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001168 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001169 return 1;
1170 else if (tv1->tv_usec < tv2->tv_usec)
1171 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001172 else if (tv1->tv_usec > tv2->tv_usec)
1173 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001174 else
1175 return 0;
1176}
1177
1178/*
1179 * returns the absolute difference, in ms, between tv1 and tv2
1180 */
1181unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1182 int cmp;
1183 unsigned long ret;
1184
1185
willy tarreauef900ab2005-12-17 12:52:52 +01001186 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001187 if (!cmp)
1188 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001189 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001190 struct timeval *tmp = tv1;
1191 tv1 = tv2;
1192 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001193 }
willy tarreauef900ab2005-12-17 12:52:52 +01001194 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001195 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001196 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001197 else
willy tarreauef900ab2005-12-17 12:52:52 +01001198 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001199 return (unsigned long) ret;
1200}
1201
1202/*
willy tarreau750a4722005-12-17 13:21:24 +01001203 * returns the difference, in ms, between tv1 and tv2
1204 */
1205static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1206 unsigned long ret;
1207
willy tarreau6e682ce2005-12-17 13:26:49 +01001208 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1209 if (tv2->tv_usec > tv1->tv_usec)
1210 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001211 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001212 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001213 return (unsigned long) ret;
1214}
1215
1216/*
willy tarreau0f7af912005-12-17 12:21:26 +01001217 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1218 */
1219static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001220 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001221 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001222 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001223 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1224 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001225 else
1226 return 0;
1227 }
willy tarreau0f7af912005-12-17 12:21:26 +01001228 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001229 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001230 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001231 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1232 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1233 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001234 else
1235 return 0;
1236}
1237
1238/*
1239 * returns the remaining time between tv1=now and event=tv2
1240 * if tv2 is passed, 0 is returned.
1241 */
1242static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1243 unsigned long ret;
1244
willy tarreau0f7af912005-12-17 12:21:26 +01001245 if (tv_cmp_ms(tv1, tv2) >= 0)
1246 return 0; /* event elapsed */
1247
willy tarreauef900ab2005-12-17 12:52:52 +01001248 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001249 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001250 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001251 else
willy tarreauef900ab2005-12-17 12:52:52 +01001252 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001253 return (unsigned long) ret;
1254}
1255
1256
1257/*
1258 * zeroes a struct timeval
1259 */
1260
1261static inline struct timeval *tv_eternity(struct timeval *tv) {
1262 tv->tv_sec = tv->tv_usec = 0;
1263 return tv;
1264}
1265
1266/*
1267 * returns 1 if tv is null, else 0
1268 */
1269static inline int tv_iseternity(struct timeval *tv) {
1270 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1271 return 1;
1272 else
1273 return 0;
1274}
1275
1276/*
1277 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1278 * considering that 0 is the eternity.
1279 */
1280static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1281 if (tv_iseternity(tv1))
1282 if (tv_iseternity(tv2))
1283 return 0; /* same */
1284 else
1285 return 1; /* tv1 later than tv2 */
1286 else if (tv_iseternity(tv2))
1287 return -1; /* tv2 later than tv1 */
1288
1289 if (tv1->tv_sec > tv2->tv_sec)
1290 return 1;
1291 else if (tv1->tv_sec < tv2->tv_sec)
1292 return -1;
1293 else if (tv1->tv_usec > tv2->tv_usec)
1294 return 1;
1295 else if (tv1->tv_usec < tv2->tv_usec)
1296 return -1;
1297 else
1298 return 0;
1299}
1300
1301/*
1302 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1303 * considering that 0 is the eternity.
1304 */
1305static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1306 if (tv_iseternity(tv1))
1307 if (tv_iseternity(tv2))
1308 return 0; /* same */
1309 else
1310 return 1; /* tv1 later than tv2 */
1311 else if (tv_iseternity(tv2))
1312 return -1; /* tv2 later than tv1 */
1313
willy tarreauefae1842005-12-17 12:51:03 +01001314 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001315 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001316 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001317 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001318 return -1;
1319 else
1320 return 0;
1321 }
1322 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001323 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001324 return 1;
1325 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001326 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001327 return -1;
1328 else
1329 return 0;
1330}
1331
1332/*
1333 * returns the first event between tv1 and tv2 into tvmin.
1334 * a zero tv is ignored. tvmin is returned.
1335 */
1336static inline struct timeval *tv_min(struct timeval *tvmin,
1337 struct timeval *tv1, struct timeval *tv2) {
1338
1339 if (tv_cmp2(tv1, tv2) <= 0)
1340 *tvmin = *tv1;
1341 else
1342 *tvmin = *tv2;
1343
1344 return tvmin;
1345}
1346
1347
1348
1349/***********************************************************/
1350/* fd management ***************************************/
1351/***********************************************************/
1352
1353
1354
willy tarreau5cbea6f2005-12-17 12:48:26 +01001355/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1356 * The file descriptor is also closed.
1357 */
willy tarreau0f7af912005-12-17 12:21:26 +01001358static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001359 FD_CLR(fd, StaticReadEvent);
1360 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001361 close(fd);
1362 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001363
1364 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1365 maxfd--;
1366}
1367
1368/* recomputes the maxfd limit from the fd */
1369static inline void fd_insert(int fd) {
1370 if (fd+1 > maxfd)
1371 maxfd = fd+1;
1372}
1373
1374/*************************************************************/
1375/* task management ***************************************/
1376/*************************************************************/
1377
willy tarreau5cbea6f2005-12-17 12:48:26 +01001378/* puts the task <t> in run queue <q>, and returns <t> */
1379static inline struct task *task_wakeup(struct task **q, struct task *t) {
1380 if (t->state == TASK_RUNNING)
1381 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001382 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001383 t->rqnext = *q;
1384 t->state = TASK_RUNNING;
1385 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001386 }
1387}
1388
willy tarreau5cbea6f2005-12-17 12:48:26 +01001389/* removes the task <t> from the queue <q>
1390 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001391 * set the run queue to point to the next one, and return it
1392 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001393static inline struct task *task_sleep(struct task **q, struct task *t) {
1394 if (t->state == TASK_RUNNING) {
1395 *q = t->rqnext;
1396 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001397 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001398 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001399}
1400
1401/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001402 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001403 * from the run queue. A pointer to the task itself is returned.
1404 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001405static inline struct task *task_delete(struct task *t) {
1406 t->prev->next = t->next;
1407 t->next->prev = t->prev;
1408 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001409}
1410
1411/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001412 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001413 */
1414static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001415 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001416}
1417
willy tarreau5cbea6f2005-12-17 12:48:26 +01001418/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001419 * may be only moved or left where it was, depending on its timing requirements.
1420 * <task> is returned.
1421 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001422struct task *task_queue(struct task *task) {
1423 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001424 struct task *start_from;
1425
1426 /* first, test if the task was already in a list */
1427 if (task->prev == NULL) {
1428 // start_from = list;
1429 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001430#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001431 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001432#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001433 /* insert the unlinked <task> into the list, searching back from the last entry */
1434 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1435 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001436#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001437 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001438#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001439 }
1440
1441 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1442 // start_from = start_from->next;
1443 // stats_tsk_nsrch++;
1444 // }
1445 }
1446 else if (task->prev == list ||
1447 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1448 start_from = task->next;
1449 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001450#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001451 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001452#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001453 return task; /* it's already in the right place */
1454 }
1455
willy tarreau750a4722005-12-17 13:21:24 +01001456#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001457 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001458#endif
1459
1460 /* if the task is not at the right place, there's little chance that
1461 * it has only shifted a bit, and it will nearly always be queued
1462 * at the end of the list because of constant timeouts
1463 * (observed in real case).
1464 */
1465#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1466 start_from = list->prev; /* assume we'll queue to the end of the list */
1467 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1468 start_from = start_from->prev;
1469#if STATTIME > 0
1470 stats_tsk_lsrch++;
1471#endif
1472 }
1473#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001474 /* insert the unlinked <task> into the list, searching after position <start_from> */
1475 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1476 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001477#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001478 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001479#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001480 }
willy tarreau750a4722005-12-17 13:21:24 +01001481#endif /* WE_REALLY_... */
1482
willy tarreau0f7af912005-12-17 12:21:26 +01001483 /* we need to unlink it now */
1484 task_delete(task);
1485 }
1486 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001487#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001488 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001489#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001490#ifdef LEFT_TO_TOP /* not very good */
1491 start_from = list;
1492 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1493 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001494#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001495 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001496#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001497 }
1498#else
1499 start_from = task->prev->prev; /* valid because of the previous test above */
1500 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1501 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001502#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001503 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001504#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001505 }
1506#endif
1507 /* we need to unlink it now */
1508 task_delete(task);
1509 }
1510 task->prev = start_from;
1511 task->next = start_from->next;
1512 task->next->prev = task;
1513 start_from->next = task;
1514 return task;
1515}
1516
1517
1518/*********************************************************************/
1519/* more specific functions ***************************************/
1520/*********************************************************************/
1521
1522/* some prototypes */
1523static int maintain_proxies(void);
1524
willy tarreau5cbea6f2005-12-17 12:48:26 +01001525/* this either returns the sockname or the original destination address. Code
1526 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1527 */
1528static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001529#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001530 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1531#else
willy tarreaua1598082005-12-17 13:08:06 +01001532#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001533 return getsockname(fd, (struct sockaddr *)sa, salen);
1534#else
1535 return -1;
1536#endif
1537#endif
1538}
1539
1540/*
1541 * frees the context associated to a session. It must have been removed first.
1542 */
1543static inline void session_free(struct session *s) {
1544 if (s->req)
1545 pool_free(buffer, s->req);
1546 if (s->rep)
1547 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001548
1549 if (s->rsp_cap != NULL) {
1550 struct cap_hdr *h;
1551 for (h = s->proxy->rsp_cap; h; h = h->next) {
1552 if (s->rsp_cap[h->index] != NULL)
1553 pool_free_to(h->pool, s->rsp_cap[h->index]);
1554 }
1555 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1556 }
1557 if (s->req_cap != NULL) {
1558 struct cap_hdr *h;
1559 for (h = s->proxy->req_cap; h; h = h->next) {
1560 if (s->req_cap[h->index] != NULL)
1561 pool_free_to(h->pool, s->req_cap[h->index]);
1562 }
1563 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1564 }
1565
willy tarreaua1598082005-12-17 13:08:06 +01001566 if (s->logs.uri)
1567 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001568 if (s->logs.cli_cookie)
1569 pool_free(capture, s->logs.cli_cookie);
1570 if (s->logs.srv_cookie)
1571 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001572
willy tarreau5cbea6f2005-12-17 12:48:26 +01001573 pool_free(session, s);
1574}
1575
willy tarreau0f7af912005-12-17 12:21:26 +01001576
1577/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001578 * This function tries to find a running server for the proxy <px>. A first
1579 * pass looks for active servers, and if none is found, a second pass also
1580 * looks for backup servers.
1581 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1582 */
1583static inline struct server *find_server(struct proxy *px) {
1584 struct server *srv = px->cursrv;
1585 int ignore_backup = 1;
1586
1587 do {
1588 do {
1589 if (srv == NULL)
1590 srv = px->srv;
1591 if (srv->state & SRV_RUNNING
1592 && !((srv->state & SRV_BACKUP) && ignore_backup))
1593 return srv;
1594 srv = srv->next;
1595 } while (srv != px->cursrv);
1596 } while (ignore_backup--);
1597 return NULL;
1598}
1599
1600/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001601 * This function initiates a connection to the current server (s->srv) if (s->direct)
1602 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001603 * it's OK, -1 if it's impossible.
1604 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001605int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001606 int fd;
1607
1608 // fprintf(stderr,"connect_server : s=%p\n",s);
1609
willy tarreaue39cd132005-12-17 13:00:18 +01001610 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001611 s->srv_addr = s->srv->addr;
1612 }
1613 else if (s->proxy->options & PR_O_BALANCE) {
1614 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001615 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001616
willy tarreau8337c6b2005-12-17 13:41:01 +01001617 srv = find_server(s->proxy);
1618
1619 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001620 return -1;
1621
willy tarreau8337c6b2005-12-17 13:41:01 +01001622 s->srv_addr = srv->addr;
1623 s->srv = srv;
1624 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001625 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001626 else /* unknown balancing algorithm */
1627 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001628 }
willy tarreaua1598082005-12-17 13:08:06 +01001629 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001630 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001631 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001632 }
1633 else if (s->proxy->options & PR_O_TRANSP) {
1634 /* in transparent mode, use the original dest addr if no dispatch specified */
1635 int salen = sizeof(struct sockaddr_in);
1636 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1637 qfprintf(stderr, "Cannot get original server address.\n");
1638 return -1;
1639 }
1640 }
willy tarreau0f7af912005-12-17 12:21:26 +01001641
willy tarreaua41a8b42005-12-17 14:02:24 +01001642 /* if this server remaps proxied ports, we'll use
1643 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001644 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001645 struct sockaddr_in sockname;
1646 int namelen;
1647
1648 namelen = sizeof(sockname);
1649 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1650 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1651 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1652 }
1653
willy tarreau0f7af912005-12-17 12:21:26 +01001654 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001655 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001656 return -1;
1657 }
1658
willy tarreau9fe663a2005-12-17 13:02:59 +01001659 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001660 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1661 close(fd);
1662 return -1;
1663 }
1664
willy tarreau0f7af912005-12-17 12:21:26 +01001665 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1666 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001667 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001668 close(fd);
1669 return -1;
1670 }
1671
willy tarreau0174f312005-12-18 01:02:42 +01001672 /* allow specific binding :
1673 * - server-specific at first
1674 * - proxy-specific next
1675 */
1676 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1677 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1678 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1679 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1680 s->proxy->id, s->srv->id);
1681 close(fd);
1682 return -1;
1683 }
1684 }
1685 else if (s->proxy->options & PR_O_BIND_SRC) {
1686 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1687 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1688 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1689 close(fd);
1690 return -1;
1691 }
willy tarreaua1598082005-12-17 13:08:06 +01001692 }
1693
willy tarreau0f7af912005-12-17 12:21:26 +01001694 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1695 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001696 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001697 close(fd);
1698 return -1;
1699 }
1700 else if (errno != EALREADY && errno != EISCONN) {
1701 close(fd);
1702 return -1;
1703 }
1704 }
1705
willy tarreau5cbea6f2005-12-17 12:48:26 +01001706 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001707 fdtab[fd].read = &event_srv_read;
1708 fdtab[fd].write = &event_srv_write;
1709 fdtab[fd].state = FD_STCONN; /* connection in progress */
1710
1711 FD_SET(fd, StaticWriteEvent); /* for connect status */
1712
1713 fd_insert(fd);
1714
1715 if (s->proxy->contimeout)
1716 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1717 else
1718 tv_eternity(&s->cnexpire);
1719 return 0;
1720}
1721
1722/*
1723 * this function is called on a read event from a client socket.
1724 * It returns 0.
1725 */
1726int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001727 struct task *t = fdtab[fd].owner;
1728 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001729 struct buffer *b = s->req;
1730 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001731
1732 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1733
willy tarreau0f7af912005-12-17 12:21:26 +01001734 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001735 while (1) {
1736 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1737 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001738 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001739 }
1740 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001741 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001742 }
1743 else {
1744 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001745 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1746 * since it means that the rewrite protection has been removed. This
1747 * implies that the if statement can be removed.
1748 */
1749 if (max > b->rlim - b->data)
1750 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001751 }
1752
1753 if (max == 0) { /* not anymore room to store data */
1754 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001755 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001756 }
1757
willy tarreau3242e862005-12-17 12:27:53 +01001758#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001759 {
1760 int skerr, lskerr;
1761
1762 lskerr = sizeof(skerr);
1763 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1764 if (skerr)
1765 ret = -1;
1766 else
1767 ret = recv(fd, b->r, max, 0);
1768 }
willy tarreau3242e862005-12-17 12:27:53 +01001769#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001770 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001771#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001772 if (ret > 0) {
1773 b->r += ret;
1774 b->l += ret;
1775 s->res_cr = RES_DATA;
1776
1777 if (b->r == b->data + BUFSIZE) {
1778 b->r = b->data; /* wrap around the buffer */
1779 }
willy tarreaua1598082005-12-17 13:08:06 +01001780
1781 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001782 /* we hope to read more data or to get a close on next round */
1783 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001784 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001785 else if (ret == 0) {
1786 s->res_cr = RES_NULL;
1787 break;
1788 }
1789 else if (errno == EAGAIN) {/* ignore EAGAIN */
1790 break;
1791 }
1792 else {
1793 s->res_cr = RES_ERROR;
1794 fdtab[fd].state = FD_STERROR;
1795 break;
1796 }
1797 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001798 }
1799 else {
1800 s->res_cr = RES_ERROR;
1801 fdtab[fd].state = FD_STERROR;
1802 }
1803
willy tarreau5cbea6f2005-12-17 12:48:26 +01001804 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001805 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001806 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1807 else
1808 tv_eternity(&s->crexpire);
1809
1810 task_wakeup(&rq, t);
1811 }
willy tarreau0f7af912005-12-17 12:21:26 +01001812
willy tarreau0f7af912005-12-17 12:21:26 +01001813 return 0;
1814}
1815
1816
1817/*
1818 * this function is called on a read event from a server socket.
1819 * It returns 0.
1820 */
1821int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001822 struct task *t = fdtab[fd].owner;
1823 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001824 struct buffer *b = s->rep;
1825 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001826
1827 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1828
willy tarreau0f7af912005-12-17 12:21:26 +01001829 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001830 while (1) {
1831 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1832 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001833 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001834 }
1835 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001836 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001837 }
1838 else {
1839 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001840 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1841 * since it means that the rewrite protection has been removed. This
1842 * implies that the if statement can be removed.
1843 */
1844 if (max > b->rlim - b->data)
1845 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001846 }
1847
1848 if (max == 0) { /* not anymore room to store data */
1849 FD_CLR(fd, StaticReadEvent);
1850 break;
1851 }
1852
willy tarreau3242e862005-12-17 12:27:53 +01001853#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001854 {
1855 int skerr, lskerr;
1856
1857 lskerr = sizeof(skerr);
1858 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1859 if (skerr)
1860 ret = -1;
1861 else
1862 ret = recv(fd, b->r, max, 0);
1863 }
willy tarreau3242e862005-12-17 12:27:53 +01001864#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001865 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001866#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001867 if (ret > 0) {
1868 b->r += ret;
1869 b->l += ret;
1870 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001871
willy tarreau5cbea6f2005-12-17 12:48:26 +01001872 if (b->r == b->data + BUFSIZE) {
1873 b->r = b->data; /* wrap around the buffer */
1874 }
willy tarreaua1598082005-12-17 13:08:06 +01001875
1876 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001877 /* we hope to read more data or to get a close on next round */
1878 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001879 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001880 else if (ret == 0) {
1881 s->res_sr = RES_NULL;
1882 break;
1883 }
1884 else if (errno == EAGAIN) {/* ignore EAGAIN */
1885 break;
1886 }
1887 else {
1888 s->res_sr = RES_ERROR;
1889 fdtab[fd].state = FD_STERROR;
1890 break;
1891 }
1892 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001893 }
1894 else {
1895 s->res_sr = RES_ERROR;
1896 fdtab[fd].state = FD_STERROR;
1897 }
1898
willy tarreau5cbea6f2005-12-17 12:48:26 +01001899 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001900 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001901 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1902 else
1903 tv_eternity(&s->srexpire);
1904
1905 task_wakeup(&rq, t);
1906 }
willy tarreau0f7af912005-12-17 12:21:26 +01001907
willy tarreau0f7af912005-12-17 12:21:26 +01001908 return 0;
1909}
1910
1911/*
1912 * this function is called on a write event from a client socket.
1913 * It returns 0.
1914 */
1915int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001916 struct task *t = fdtab[fd].owner;
1917 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001918 struct buffer *b = s->rep;
1919 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001920
1921 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1922
1923 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001924 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001925 // max = BUFSIZE; BUG !!!!
1926 max = 0;
1927 }
1928 else if (b->r > b->w) {
1929 max = b->r - b->w;
1930 }
1931 else
1932 max = b->data + BUFSIZE - b->w;
1933
willy tarreau0f7af912005-12-17 12:21:26 +01001934 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001935#ifndef MSG_NOSIGNAL
1936 int skerr, lskerr;
1937#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001938
1939 if (max == 0) {
1940 s->res_cw = RES_NULL;
1941 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001942 tv_eternity(&s->cwexpire);
1943 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001944 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001945 }
1946
willy tarreau3242e862005-12-17 12:27:53 +01001947#ifndef MSG_NOSIGNAL
1948 lskerr=sizeof(skerr);
1949 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1950 if (skerr)
1951 ret = -1;
1952 else
1953 ret = send(fd, b->w, max, MSG_DONTWAIT);
1954#else
willy tarreau0f7af912005-12-17 12:21:26 +01001955 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001956#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001957
1958 if (ret > 0) {
1959 b->l -= ret;
1960 b->w += ret;
1961
1962 s->res_cw = RES_DATA;
1963
1964 if (b->w == b->data + BUFSIZE) {
1965 b->w = b->data; /* wrap around the buffer */
1966 }
1967 }
1968 else if (ret == 0) {
1969 /* nothing written, just make as if we were never called */
1970// s->res_cw = RES_NULL;
1971 return 0;
1972 }
1973 else if (errno == EAGAIN) /* ignore EAGAIN */
1974 return 0;
1975 else {
1976 s->res_cw = RES_ERROR;
1977 fdtab[fd].state = FD_STERROR;
1978 }
1979 }
1980 else {
1981 s->res_cw = RES_ERROR;
1982 fdtab[fd].state = FD_STERROR;
1983 }
1984
willy tarreaub1ff9db2005-12-17 13:51:03 +01001985 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001986 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001987 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
1988 s->crexpire = s->cwexpire;
1989 }
willy tarreau0f7af912005-12-17 12:21:26 +01001990 else
1991 tv_eternity(&s->cwexpire);
1992
willy tarreau5cbea6f2005-12-17 12:48:26 +01001993 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001994 return 0;
1995}
1996
1997
1998/*
1999 * this function is called on a write event from a server socket.
2000 * It returns 0.
2001 */
2002int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002003 struct task *t = fdtab[fd].owner;
2004 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002005 struct buffer *b = s->req;
2006 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002007
2008 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2009
2010 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002011 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002012 // max = BUFSIZE; BUG !!!!
2013 max = 0;
2014 }
2015 else if (b->r > b->w) {
2016 max = b->r - b->w;
2017 }
2018 else
2019 max = b->data + BUFSIZE - b->w;
2020
willy tarreau0f7af912005-12-17 12:21:26 +01002021 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01002022#ifndef MSG_NOSIGNAL
2023 int skerr, lskerr;
2024#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002025 if (max == 0) {
2026 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01002027 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002028 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002029 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002030 tv_eternity(&s->swexpire);
2031 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002032 return 0;
2033 }
2034
willy tarreauef900ab2005-12-17 12:52:52 +01002035
willy tarreau3242e862005-12-17 12:27:53 +01002036#ifndef MSG_NOSIGNAL
2037 lskerr=sizeof(skerr);
2038 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2039 if (skerr)
2040 ret = -1;
2041 else
2042 ret = send(fd, b->w, max, MSG_DONTWAIT);
2043#else
willy tarreau0f7af912005-12-17 12:21:26 +01002044 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002045#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002046 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002047 if (ret > 0) {
2048 b->l -= ret;
2049 b->w += ret;
2050
2051 s->res_sw = RES_DATA;
2052
2053 if (b->w == b->data + BUFSIZE) {
2054 b->w = b->data; /* wrap around the buffer */
2055 }
2056 }
2057 else if (ret == 0) {
2058 /* nothing written, just make as if we were never called */
2059 // s->res_sw = RES_NULL;
2060 return 0;
2061 }
2062 else if (errno == EAGAIN) /* ignore EAGAIN */
2063 return 0;
2064 else {
2065 s->res_sw = RES_ERROR;
2066 fdtab[fd].state = FD_STERROR;
2067 }
2068 }
2069 else {
2070 s->res_sw = RES_ERROR;
2071 fdtab[fd].state = FD_STERROR;
2072 }
2073
willy tarreaub1ff9db2005-12-17 13:51:03 +01002074 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002075 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002076 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2077 s->srexpire = s->swexpire;
2078 }
willy tarreau0f7af912005-12-17 12:21:26 +01002079 else
2080 tv_eternity(&s->swexpire);
2081
willy tarreau5cbea6f2005-12-17 12:48:26 +01002082 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002083 return 0;
2084}
2085
2086
2087/*
willy tarreaue39cd132005-12-17 13:00:18 +01002088 * returns a message to the client ; the connection is shut down for read,
2089 * and the request is cleared so that no server connection can be initiated.
2090 * The client must be in a valid state for this (HEADER, DATA ...).
2091 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002092 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002093 */
2094void client_retnclose(struct session *s, int len, const char *msg) {
2095 FD_CLR(s->cli_fd, StaticReadEvent);
2096 FD_SET(s->cli_fd, StaticWriteEvent);
2097 tv_eternity(&s->crexpire);
2098 shutdown(s->cli_fd, SHUT_RD);
2099 s->cli_state = CL_STSHUTR;
2100 strcpy(s->rep->data, msg);
2101 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002102 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002103 s->rep->r += len;
2104 s->req->l = 0;
2105}
2106
2107
2108/*
2109 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002110 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002111 */
2112void client_return(struct session *s, int len, const char *msg) {
2113 strcpy(s->rep->data, msg);
2114 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002115 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002116 s->rep->r += len;
2117 s->req->l = 0;
2118}
2119
willy tarreau9fe663a2005-12-17 13:02:59 +01002120/*
2121 * send a log for the session when we have enough info about it
2122 */
2123void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002124 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002125 struct proxy *p = s->proxy;
2126 int log;
2127 char *uri;
2128 char *pxid;
2129 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002130 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002131
2132 /* This is a first attempt at a better logging system.
2133 * For now, we rely on send_log() to provide the date, although it obviously
2134 * is the date of the log and not of the request, and most fields are not
2135 * computed.
2136 */
2137
willy tarreaua1598082005-12-17 13:08:06 +01002138 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002139
willy tarreau8a86dbf2005-12-18 00:45:59 +01002140 if (s->cli_addr.ss_family == AF_INET)
2141 inet_ntop(AF_INET,
2142 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2143 pn, sizeof(pn));
2144 else
2145 inet_ntop(AF_INET6,
2146 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2147 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002148
willy tarreauc1cae632005-12-17 14:12:23 +01002149 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002150 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002151 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002152
willy tarreauc1cae632005-12-17 14:12:23 +01002153 tm = localtime(&s->logs.tv_accept.tv_sec);
2154 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002155 char tmpline[MAX_SYSLOG_LEN], *h;
2156 int hdr;
2157
2158 h = tmpline;
2159 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2160 *(h++) = ' ';
2161 *(h++) = '{';
2162 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2163 if (hdr)
2164 *(h++) = '|';
2165 if (s->req_cap[hdr] != NULL)
2166 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2167 }
2168 *(h++) = '}';
2169 }
2170
2171 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2172 *(h++) = ' ';
2173 *(h++) = '{';
2174 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2175 if (hdr)
2176 *(h++) = '|';
2177 if (s->rsp_cap[hdr] != NULL)
2178 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2179 }
2180 *(h++) = '}';
2181 }
2182
2183 if (h < tmpline + sizeof(tmpline) - 4) {
2184 *(h++) = ' ';
2185 *(h++) = '"';
2186 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2187 *(h++) = '"';
2188 }
2189 *h = '\0';
2190
2191 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%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002192 pn,
2193 (s->cli_addr.ss_family == AF_INET) ?
2194 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2195 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002196 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2197 tm->tm_hour, tm->tm_min, tm->tm_sec,
2198 pxid, srv,
2199 s->logs.t_request,
2200 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2201 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002202 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2203 s->logs.status,
2204 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002205 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2206 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002207 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2208 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2209 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2210 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau4302f492005-12-18 01:00:37 +01002211 tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002212 }
2213 else {
willy tarreau25c4ea52005-12-18 00:49:49 +01002214 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002215 pn,
2216 (s->cli_addr.ss_family == AF_INET) ?
2217 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2218 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002219 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2220 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002221 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002222 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002223 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2224 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002225 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01002226 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01002227 }
2228
2229 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002230}
2231
willy tarreaue39cd132005-12-17 13:00:18 +01002232
2233/*
willy tarreau0f7af912005-12-17 12:21:26 +01002234 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002235 * to an accept. It tries to accept as many connections as possible.
2236 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002237 */
2238int event_accept(int fd) {
2239 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002240 struct session *s;
2241 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002242 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002243
willy tarreau5cbea6f2005-12-17 12:48:26 +01002244 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002245 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002246 int laddr = sizeof(addr);
2247 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2248 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002249
willy tarreau5cbea6f2005-12-17 12:48:26 +01002250 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2251 Alert("out of memory in event_accept().\n");
2252 FD_CLR(fd, StaticReadEvent);
2253 p->state = PR_STIDLE;
2254 close(cfd);
2255 return 0;
2256 }
willy tarreau0f7af912005-12-17 12:21:26 +01002257
willy tarreau5cbea6f2005-12-17 12:48:26 +01002258 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2259 Alert("out of memory in event_accept().\n");
2260 FD_CLR(fd, StaticReadEvent);
2261 p->state = PR_STIDLE;
2262 close(cfd);
2263 pool_free(session, s);
2264 return 0;
2265 }
willy tarreau0f7af912005-12-17 12:21:26 +01002266
willy tarreau5cbea6f2005-12-17 12:48:26 +01002267 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002268 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002269 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2270 close(cfd);
2271 pool_free(task, t);
2272 pool_free(session, s);
2273 return 0;
2274 }
willy tarreau0f7af912005-12-17 12:21:26 +01002275
willy tarreau5cbea6f2005-12-17 12:48:26 +01002276 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2277 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2278 (char *) &one, sizeof(one)) == -1)) {
2279 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2280 close(cfd);
2281 pool_free(task, t);
2282 pool_free(session, s);
2283 return 0;
2284 }
willy tarreau0f7af912005-12-17 12:21:26 +01002285
willy tarreau9fe663a2005-12-17 13:02:59 +01002286 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2287 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2288 t->state = TASK_IDLE;
2289 t->process = process_session;
2290 t->context = s;
2291
2292 s->task = t;
2293 s->proxy = p;
2294 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2295 s->srv_state = SV_STIDLE;
2296 s->req = s->rep = NULL; /* will be allocated later */
2297 s->flags = 0;
willy tarreau97f58572005-12-18 00:53:44 +01002298
willy tarreau9fe663a2005-12-17 13:02:59 +01002299 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2300 s->cli_fd = cfd;
2301 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002302 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002303 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002304
2305 s->logs.logwait = p->to_log;
2306 s->logs.tv_accept = now;
2307 s->logs.t_request = -1;
2308 s->logs.t_connect = -1;
2309 s->logs.t_data = -1;
2310 s->logs.t_close = 0;
2311 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002312 s->logs.cli_cookie = NULL;
2313 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002314 s->logs.status = -1;
2315 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002316
willy tarreau2f6ba652005-12-17 13:57:42 +01002317 s->uniq_id = totalconn;
2318
willy tarreau4302f492005-12-18 01:00:37 +01002319 if (p->nb_req_cap > 0) {
2320 if ((s->req_cap =
2321 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2322 == NULL) { /* no memory */
2323 close(cfd); /* nothing can be done for this fd without memory */
2324 pool_free(task, t);
2325 pool_free(session, s);
2326 return 0;
2327 }
2328 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2329 }
2330 else
2331 s->req_cap = NULL;
2332
2333 if (p->nb_rsp_cap > 0) {
2334 if ((s->rsp_cap =
2335 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2336 == NULL) { /* no memory */
2337 if (s->req_cap != NULL)
2338 pool_free_to(p->req_cap_pool, s->req_cap);
2339 close(cfd); /* nothing can be done for this fd without memory */
2340 pool_free(task, t);
2341 pool_free(session, s);
2342 return 0;
2343 }
2344 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2345 }
2346 else
2347 s->rsp_cap = NULL;
2348
willy tarreau5cbea6f2005-12-17 12:48:26 +01002349 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2350 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002351 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002352 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002353
willy tarreau5cbea6f2005-12-17 12:48:26 +01002354 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002355 if (addr.ss_family != AF_INET ||
2356 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002357 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002358
willy tarreau9fe663a2005-12-17 13:02:59 +01002359 if (p->to_log) {
2360 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002361 if (s->logs.logwait & LW_CLIP)
2362 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002363 sess_log(s);
2364 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002365 else if (s->cli_addr.ss_family == AF_INET) {
2366 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2367 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2368 sn, sizeof(sn)) &&
2369 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2370 pn, sizeof(pn))) {
2371 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2372 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2373 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2374 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2375 }
2376 }
2377 else {
2378 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2379 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2380 sn, sizeof(sn)) &&
2381 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2382 pn, sizeof(pn))) {
2383 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2384 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2385 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2386 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2387 }
2388 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002389 }
willy tarreau0f7af912005-12-17 12:21:26 +01002390
willy tarreau982249e2005-12-18 00:57:06 +01002391 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002392 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002393 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002394 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002395 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002396 if (addr.ss_family != AF_INET ||
2397 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002398 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002399
willy tarreau8a86dbf2005-12-18 00:45:59 +01002400 if (s->cli_addr.ss_family == AF_INET) {
2401 char pn[INET_ADDRSTRLEN];
2402 inet_ntop(AF_INET,
2403 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2404 pn, sizeof(pn));
2405
2406 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2407 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2408 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2409 }
2410 else {
2411 char pn[INET6_ADDRSTRLEN];
2412 inet_ntop(AF_INET6,
2413 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2414 pn, sizeof(pn));
2415
2416 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2417 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2418 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2419 }
2420
willy tarreauef900ab2005-12-17 12:52:52 +01002421 write(1, trash, len);
2422 }
willy tarreau0f7af912005-12-17 12:21:26 +01002423
willy tarreau5cbea6f2005-12-17 12:48:26 +01002424 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002425 if (s->rsp_cap != NULL)
2426 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2427 if (s->req_cap != NULL)
2428 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002429 close(cfd); /* nothing can be done for this fd without memory */
2430 pool_free(task, t);
2431 pool_free(session, s);
2432 return 0;
2433 }
willy tarreau4302f492005-12-18 01:00:37 +01002434
willy tarreau5cbea6f2005-12-17 12:48:26 +01002435 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002436 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002437 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2438 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002439 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002440 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002441
willy tarreau5cbea6f2005-12-17 12:48:26 +01002442 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2443 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002444 if (s->rsp_cap != NULL)
2445 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2446 if (s->req_cap != NULL)
2447 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002448 close(cfd); /* nothing can be done for this fd without memory */
2449 pool_free(task, t);
2450 pool_free(session, s);
2451 return 0;
2452 }
2453 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002454 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002455 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 +01002456
willy tarreau5cbea6f2005-12-17 12:48:26 +01002457 fdtab[cfd].read = &event_cli_read;
2458 fdtab[cfd].write = &event_cli_write;
2459 fdtab[cfd].owner = t;
2460 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002461
willy tarreau5cbea6f2005-12-17 12:48:26 +01002462 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002463 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2464 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2465 else
2466 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002467 }
2468 else {
2469 FD_SET(cfd, StaticReadEvent);
2470 }
2471
2472 fd_insert(cfd);
2473
2474 tv_eternity(&s->cnexpire);
2475 tv_eternity(&s->srexpire);
2476 tv_eternity(&s->swexpire);
2477 tv_eternity(&s->cwexpire);
2478
2479 if (s->proxy->clitimeout)
2480 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2481 else
2482 tv_eternity(&s->crexpire);
2483
2484 t->expire = s->crexpire;
2485
2486 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002487
2488 if (p->mode != PR_MODE_HEALTH)
2489 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002490
2491 p->nbconn++;
2492 actconn++;
2493 totalconn++;
2494
2495 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2496 } /* end of while (p->nbconn < p->maxconn) */
2497 return 0;
2498}
willy tarreau0f7af912005-12-17 12:21:26 +01002499
willy tarreau0f7af912005-12-17 12:21:26 +01002500
willy tarreau5cbea6f2005-12-17 12:48:26 +01002501/*
2502 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002503 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2504 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002505 * or -1 if an error occured.
2506 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002507int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002508 struct task *t = fdtab[fd].owner;
2509 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002510
willy tarreau5cbea6f2005-12-17 12:48:26 +01002511 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002512 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002513 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002514 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002515 if (skerr)
2516 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002517 else {
2518 if (s->proxy->options & PR_O_HTTP_CHK) {
2519 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002520 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002521 * so we'll send the request, and won't wake the checker up now.
2522 */
2523#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002524 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002525#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002526 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002527#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002528 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002529 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2530 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2531 return 0;
2532 }
2533 else
2534 s->result = -1;
2535 }
2536 else {
2537 /* good TCP connection is enough */
2538 s->result = 1;
2539 }
2540 }
2541
2542 task_wakeup(&rq, t);
2543 return 0;
2544}
2545
willy tarreau0f7af912005-12-17 12:21:26 +01002546
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002547/*
2548 * This function is used only for server health-checks. It handles
2549 * the server's reply to an HTTP request. It returns 1 if the server replies
2550 * 2xx or 3xx (valid responses), or -1 in other cases.
2551 */
2552int event_srv_chk_r(int fd) {
2553 char reply[64];
2554 int len;
2555 struct task *t = fdtab[fd].owner;
2556 struct server *s = t->context;
2557
2558 int skerr, lskerr;
2559 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002560
2561 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002562#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002563 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2564 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002565 len = recv(fd, reply, sizeof(reply), 0);
2566#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002567 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2568 * but the connection was closed on the remote end. Fortunately, recv still
2569 * works correctly and we don't need to do the getsockopt() on linux.
2570 */
2571 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002572#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002573 if ((len >= sizeof("HTTP/1.0 000")) &&
2574 !memcmp(reply, "HTTP/1.", 7) &&
2575 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2576 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002577
2578 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002579 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002580 return 0;
2581}
2582
2583
2584/*
2585 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2586 * and moves <end> just after the end of <str>.
2587 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2588 * the shift value (positive or negative) is returned.
2589 * If there's no space left, the move is not done.
2590 *
2591 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002592int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002593 int delta;
2594 int len;
2595
2596 len = strlen(str);
2597 delta = len - (end - pos);
2598
2599 if (delta + b->r >= b->data + BUFSIZE)
2600 return 0; /* no space left */
2601
2602 /* first, protect the end of the buffer */
2603 memmove(end + delta, end, b->data + b->l - end);
2604
2605 /* now, copy str over pos */
2606 memcpy(pos, str,len);
2607
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 /* we only move data after the displaced zone */
2609 if (b->r > pos) b->r += delta;
2610 if (b->w > pos) b->w += delta;
2611 if (b->h > pos) b->h += delta;
2612 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002613 b->l += delta;
2614
2615 return delta;
2616}
2617
willy tarreau8337c6b2005-12-17 13:41:01 +01002618/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002619 * len is 0.
2620 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002621int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002622 int delta;
2623
2624 delta = len - (end - pos);
2625
2626 if (delta + b->r >= b->data + BUFSIZE)
2627 return 0; /* no space left */
2628
2629 /* first, protect the end of the buffer */
2630 memmove(end + delta, end, b->data + b->l - end);
2631
2632 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002633 if (len)
2634 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002635
willy tarreau5cbea6f2005-12-17 12:48:26 +01002636 /* we only move data after the displaced zone */
2637 if (b->r > pos) b->r += delta;
2638 if (b->w > pos) b->w += delta;
2639 if (b->h > pos) b->h += delta;
2640 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002641 b->l += delta;
2642
2643 return delta;
2644}
2645
2646
2647int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2648 char *old_dst = dst;
2649
2650 while (*str) {
2651 if (*str == '\\') {
2652 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002653 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002654 int len, num;
2655
2656 num = *str - '0';
2657 str++;
2658
willy tarreau8a86dbf2005-12-18 00:45:59 +01002659 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002660 len = matches[num].rm_eo - matches[num].rm_so;
2661 memcpy(dst, src + matches[num].rm_so, len);
2662 dst += len;
2663 }
2664
2665 }
2666 else if (*str == 'x') {
2667 unsigned char hex1, hex2;
2668 str++;
2669
2670 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2671
2672 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2673 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2674 *dst++ = (hex1<<4) + hex2;
2675 }
2676 else
2677 *dst++ = *str++;
2678 }
2679 else
2680 *dst++ = *str++;
2681 }
2682 *dst = 0;
2683 return dst - old_dst;
2684}
2685
willy tarreau9fe663a2005-12-17 13:02:59 +01002686
willy tarreau0f7af912005-12-17 12:21:26 +01002687/*
2688 * manages the client FSM and its socket. BTW, it also tries to handle the
2689 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2690 * 0 else.
2691 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002692int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002693 int s = t->srv_state;
2694 int c = t->cli_state;
2695 struct buffer *req = t->req;
2696 struct buffer *rep = t->rep;
2697
willy tarreau750a4722005-12-17 13:21:24 +01002698#ifdef DEBUG_FULL
2699 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2700#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002701 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2702 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2703 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2704 //);
2705 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002706 /* now parse the partial (or complete) headers */
2707 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2708 char *ptr;
2709 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002710
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002712
willy tarreau0f7af912005-12-17 12:21:26 +01002713 /* look for the end of the current header */
2714 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2715 ptr++;
2716
willy tarreau5cbea6f2005-12-17 12:48:26 +01002717 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002718 int line, len;
2719 /* we can only get here after an end of headers */
2720 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002721
willy tarreaue39cd132005-12-17 13:00:18 +01002722 if (t->flags & SN_CLDENY) {
2723 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002724 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002725 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002726 if (!(t->flags & SN_ERR_MASK))
2727 t->flags |= SN_ERR_PRXCOND;
2728 if (!(t->flags & SN_FINST_MASK))
2729 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002730 return 1;
2731 }
2732
willy tarreau5cbea6f2005-12-17 12:48:26 +01002733 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002734 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2735 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002736 }
willy tarreau0f7af912005-12-17 12:21:26 +01002737
willy tarreau9fe663a2005-12-17 13:02:59 +01002738 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002739 if (t->cli_addr.ss_family == AF_INET) {
2740 unsigned char *pn;
2741 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
2742 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2743 pn[0], pn[1], pn[2], pn[3]);
2744 buffer_replace2(req, req->h, req->h, trash, len);
2745 }
2746 else if (t->cli_addr.ss_family == AF_INET6) {
2747 char pn[INET6_ADDRSTRLEN];
2748 inet_ntop(AF_INET6,
2749 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2750 pn, sizeof(pn));
2751 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
2752 buffer_replace2(req, req->h, req->h, trash, len);
2753 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002754 }
2755
willy tarreau25c4ea52005-12-18 00:49:49 +01002756 /* add a "connection: close" line if needed */
2757 if (t->proxy->options & PR_O_HTTP_CLOSE)
2758 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
2759
willy tarreau982249e2005-12-18 00:57:06 +01002760 if (!memcmp(req->data, "POST ", 5)) {
2761 /* this is a POST request, which is not cacheable by default */
2762 t->flags |= SN_POST;
2763 }
willy tarreaucd878942005-12-17 13:27:43 +01002764
willy tarreau5cbea6f2005-12-17 12:48:26 +01002765 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002766 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002767
willy tarreau750a4722005-12-17 13:21:24 +01002768 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002769 /* FIXME: we'll set the client in a wait state while we try to
2770 * connect to the server. Is this really needed ? wouldn't it be
2771 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002772 //FD_CLR(t->cli_fd, StaticReadEvent);
2773 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002774
2775 /* FIXME: if we break here (as up to 1.1.23), having the client
2776 * shutdown its connection can lead to an abort further.
2777 * it's better to either return 1 or even jump directly to the
2778 * data state which will save one schedule.
2779 */
2780 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002781
2782 if (!t->proxy->clitimeout ||
2783 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2784 /* If the client has no timeout, or if the server is not ready yet,
2785 * and we know for sure that it can expire, then it's cleaner to
2786 * disable the timeout on the client side so that too low values
2787 * cannot make the sessions abort too early.
2788 */
2789 tv_eternity(&t->crexpire);
2790
willy tarreau197e8ec2005-12-17 14:10:59 +01002791 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002792 }
willy tarreau0f7af912005-12-17 12:21:26 +01002793
willy tarreau5cbea6f2005-12-17 12:48:26 +01002794 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2795 if (ptr > req->r - 2) {
2796 /* this is a partial header, let's wait for more to come */
2797 req->lr = ptr;
2798 break;
2799 }
willy tarreau0f7af912005-12-17 12:21:26 +01002800
willy tarreau5cbea6f2005-12-17 12:48:26 +01002801 /* now we know that *ptr is either \r or \n,
2802 * and that there are at least 1 char after it.
2803 */
2804 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2805 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2806 else
2807 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002808
willy tarreau5cbea6f2005-12-17 12:48:26 +01002809 /*
2810 * now we know that we have a full header ; we can do whatever
2811 * we want with these pointers :
2812 * req->h = beginning of header
2813 * ptr = end of header (first \r or \n)
2814 * req->lr = beginning of next line (next rep->h)
2815 * req->r = end of data (not used at this stage)
2816 */
willy tarreau0f7af912005-12-17 12:21:26 +01002817
willy tarreau8337c6b2005-12-17 13:41:01 +01002818 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002819 /* we have a complete HTTP request that we must log */
2820 int urilen;
2821
willy tarreaua1598082005-12-17 13:08:06 +01002822 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002823 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002824 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002825 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002826 if (!(t->flags & SN_ERR_MASK))
2827 t->flags |= SN_ERR_PRXCOND;
2828 if (!(t->flags & SN_FINST_MASK))
2829 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002830 return 1;
2831 }
2832
2833 urilen = ptr - req->h;
2834 if (urilen >= REQURI_LEN)
2835 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002836 memcpy(t->logs.uri, req->h, urilen);
2837 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002838
willy tarreaua1598082005-12-17 13:08:06 +01002839 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002840 sess_log(t);
2841 }
willy tarreau4302f492005-12-18 01:00:37 +01002842 else if (t->logs.logwait & LW_REQHDR) {
2843 struct cap_hdr *h;
2844 int len;
2845 for (h = t->proxy->req_cap; h; h = h->next) {
2846 if ((h->namelen + 2 <= ptr - req->h) &&
2847 (req->h[h->namelen] == ':') &&
2848 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
2849
2850 if (t->req_cap[h->index] == NULL)
2851 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
2852
2853 len = ptr - (req->h + h->namelen + 2);
2854 if (len > h->len)
2855 len = h->len;
2856
2857 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
2858 t->req_cap[h->index][len]=0;
2859 }
2860 }
2861
2862 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002863
willy tarreau5cbea6f2005-12-17 12:48:26 +01002864 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002865
willy tarreau982249e2005-12-18 00:57:06 +01002866 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002867 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002868 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 +01002869 max = ptr - req->h;
2870 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002871 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002872 trash[len++] = '\n';
2873 write(1, trash, len);
2874 }
willy tarreau0f7af912005-12-17 12:21:26 +01002875
willy tarreau25c4ea52005-12-18 00:49:49 +01002876
2877 /* remove "connection: " if needed */
2878 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
2879 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
2880 delete_header = 1;
2881 }
2882
willy tarreau5cbea6f2005-12-17 12:48:26 +01002883 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01002884 if (!delete_header && t->proxy->req_exp != NULL
2885 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002886 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002887 char term;
2888
2889 term = *ptr;
2890 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002891 exp = t->proxy->req_exp;
2892 do {
2893 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2894 switch (exp->action) {
2895 case ACT_ALLOW:
2896 if (!(t->flags & SN_CLDENY))
2897 t->flags |= SN_CLALLOW;
2898 break;
2899 case ACT_REPLACE:
2900 if (!(t->flags & SN_CLDENY)) {
2901 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2902 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2903 }
2904 break;
2905 case ACT_REMOVE:
2906 if (!(t->flags & SN_CLDENY))
2907 delete_header = 1;
2908 break;
2909 case ACT_DENY:
2910 if (!(t->flags & SN_CLALLOW))
2911 t->flags |= SN_CLDENY;
2912 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002913 case ACT_PASS: /* we simply don't deny this one */
2914 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002915 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002916 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002917 }
willy tarreaue39cd132005-12-17 13:00:18 +01002918 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002919 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002920 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002921
willy tarreau240afa62005-12-17 13:14:35 +01002922 /* Now look for cookies. Conforming to RFC2109, we have to support
2923 * attributes whose name begin with a '$', and associate them with
2924 * the right cookie, if we want to delete this cookie.
2925 * So there are 3 cases for each cookie read :
2926 * 1) it's a special attribute, beginning with a '$' : ignore it.
2927 * 2) it's a server id cookie that we *MAY* want to delete : save
2928 * some pointers on it (last semi-colon, beginning of cookie...)
2929 * 3) it's an application cookie : we *MAY* have to delete a previous
2930 * "special" cookie.
2931 * At the end of loop, if a "special" cookie remains, we may have to
2932 * remove it. If no application cookie persists in the header, we
2933 * *MUST* delete it
2934 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002935 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002936 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01002937 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002938 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002939 char *del_colon, *del_cookie, *colon;
2940 int app_cookies;
2941
willy tarreau5cbea6f2005-12-17 12:48:26 +01002942 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002943 colon = p1;
2944 /* del_cookie == NULL => nothing to be deleted */
2945 del_colon = del_cookie = NULL;
2946 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002947
2948 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002949 /* skip spaces and colons, but keep an eye on these ones */
2950 while (p1 < ptr) {
2951 if (*p1 == ';' || *p1 == ',')
2952 colon = p1;
2953 else if (!isspace((int)*p1))
2954 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002955 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002956 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002957
2958 if (p1 == ptr)
2959 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002960
2961 /* p1 is at the beginning of the cookie name */
2962 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002963 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002964 p2++;
2965
2966 if (p2 == ptr)
2967 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002968
2969 p3 = p2 + 1; /* skips the '=' sign */
2970 if (p3 == ptr)
2971 break;
2972
willy tarreau240afa62005-12-17 13:14:35 +01002973 p4 = p3;
2974 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002975 p4++;
2976
2977 /* here, we have the cookie name between p1 and p2,
2978 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01002979 * we can process it :
2980 *
2981 * Cookie: NAME=VALUE;
2982 * | || || |
2983 * | || || +--> p4
2984 * | || |+-------> p3
2985 * | || +--------> p2
2986 * | |+------------> p1
2987 * | +-------------> colon
2988 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01002989 */
2990
willy tarreau240afa62005-12-17 13:14:35 +01002991 if (*p1 == '$') {
2992 /* skip this one */
2993 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002994 else {
2995 /* first, let's see if we want to capture it */
2996 if (t->proxy->capture_name != NULL &&
2997 t->logs.cli_cookie == NULL &&
2998 (p4 - p1 >= t->proxy->capture_namelen) &&
2999 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3000 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003001
willy tarreau8337c6b2005-12-17 13:41:01 +01003002 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3003 Alert("HTTP logging : out of memory.\n");
3004 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003005
willy tarreau8337c6b2005-12-17 13:41:01 +01003006 if (log_len > t->proxy->capture_len)
3007 log_len = t->proxy->capture_len;
3008 memcpy(t->logs.cli_cookie, p1, log_len);
3009 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003010 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003011
3012 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3013 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3014 /* Cool... it's the right one */
3015 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003016 char *delim;
3017
3018 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3019 * have the server ID betweek p3 and delim, and the original cookie between
3020 * delim+1 and p4. Otherwise, delim==p4 :
3021 *
3022 * Cookie: NAME=SRV~VALUE;
3023 * | || || | |
3024 * | || || | +--> p4
3025 * | || || +--------> delim
3026 * | || |+-----------> p3
3027 * | || +------------> p2
3028 * | |+----------------> p1
3029 * | +-----------------> colon
3030 * +------------------------> req->h
3031 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003032
willy tarreau0174f312005-12-18 01:02:42 +01003033 if (t->proxy->options & PR_O_COOK_PFX) {
3034 for (delim = p3; delim < p4; delim++)
3035 if (*delim == COOKIE_DELIM)
3036 break;
3037 }
3038 else
3039 delim = p4;
3040
3041
3042 /* Here, we'll look for the first running server which supports the cookie.
3043 * This allows to share a same cookie between several servers, for example
3044 * to dedicate backup servers to specific servers only.
3045 */
3046 while (srv) {
3047 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3048 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3049 /* we found the server and it's usable */
3050 t->flags &= ~SN_CK_MASK;
3051 t->flags |= SN_CK_VALID | SN_DIRECT;
3052 t->srv = srv;
3053 break;
3054 }
3055 else {
3056 /* we found a server, but it's down */
3057 t->flags &= ~SN_CK_MASK;
3058 t->flags |= SN_CK_DOWN;
3059 }
3060 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003061 srv = srv->next;
3062 }
3063
willy tarreau0174f312005-12-18 01:02:42 +01003064 if (!srv && !(t->flags & SN_CK_DOWN)) {
3065 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003066 t->flags &= ~SN_CK_MASK;
3067 t->flags |= SN_CK_INVALID;
3068 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003069
willy tarreau0174f312005-12-18 01:02:42 +01003070 /* depending on the cookie mode, we may have to either :
3071 * - delete the complete cookie if we're in insert+indirect mode, so that
3072 * the server never sees it ;
3073 * - remove the server id from the cookie value, and tag the cookie as an
3074 * application cookie so that it does not get accidentely removed later,
3075 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003076 */
willy tarreau0174f312005-12-18 01:02:42 +01003077 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3078 buffer_replace2(req, p3, delim + 1, NULL, 0);
3079 p4 -= (delim + 1 - p3);
3080 ptr -= (delim + 1 - p3);
3081 del_cookie = del_colon = NULL;
3082 app_cookies++; /* protect the header from deletion */
3083 }
3084 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003085 (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 +01003086 del_cookie = p1;
3087 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003088 }
willy tarreau240afa62005-12-17 13:14:35 +01003089 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003090 else {
3091 /* now we know that we must keep this cookie since it's
3092 * not ours. But if we wanted to delete our cookie
3093 * earlier, we cannot remove the complete header, but we
3094 * can remove the previous block itself.
3095 */
3096 app_cookies++;
3097
3098 if (del_cookie != NULL) {
3099 buffer_replace2(req, del_cookie, p1, NULL, 0);
3100 p4 -= (p1 - del_cookie);
3101 ptr -= (p1 - del_cookie);
3102 del_cookie = del_colon = NULL;
3103 }
willy tarreau240afa62005-12-17 13:14:35 +01003104 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 }
willy tarreau240afa62005-12-17 13:14:35 +01003106
willy tarreau5cbea6f2005-12-17 12:48:26 +01003107 /* we'll have to look for another cookie ... */
3108 p1 = p4;
3109 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003110
3111 /* There's no more cookie on this line.
3112 * We may have marked the last one(s) for deletion.
3113 * We must do this now in two ways :
3114 * - if there is no app cookie, we simply delete the header ;
3115 * - if there are app cookies, we must delete the end of the
3116 * string properly, including the colon/semi-colon before
3117 * the cookie name.
3118 */
3119 if (del_cookie != NULL) {
3120 if (app_cookies) {
3121 buffer_replace2(req, del_colon, ptr, NULL, 0);
3122 /* WARNING! <ptr> becomes invalid for now. If some code
3123 * below needs to rely on it before the end of the global
3124 * header loop, we need to correct it with this code :
3125 * ptr = del_colon;
3126 */
3127 }
3128 else
3129 delete_header = 1;
3130 }
3131 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003132
3133 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003134 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003135 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003136 }
willy tarreau240afa62005-12-17 13:14:35 +01003137 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3138
willy tarreau5cbea6f2005-12-17 12:48:26 +01003139 req->h = req->lr;
3140 } /* while (req->lr < req->r) */
3141
3142 /* end of header processing (even if incomplete) */
3143
willy tarreauef900ab2005-12-17 12:52:52 +01003144 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3145 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3146 * full. We cannot loop here since event_cli_read will disable it only if
3147 * req->l == rlim-data
3148 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003149 FD_SET(t->cli_fd, StaticReadEvent);
3150 if (t->proxy->clitimeout)
3151 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3152 else
3153 tv_eternity(&t->crexpire);
3154 }
3155
willy tarreaue39cd132005-12-17 13:00:18 +01003156 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003157 * won't be able to free more later, so the session will never terminate.
3158 */
willy tarreaue39cd132005-12-17 13:00:18 +01003159 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003160 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003161 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003162 if (!(t->flags & SN_ERR_MASK))
3163 t->flags |= SN_ERR_PRXCOND;
3164 if (!(t->flags & SN_FINST_MASK))
3165 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003166 return 1;
3167 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003168 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003169 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003170 tv_eternity(&t->crexpire);
3171 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003172 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003173 if (!(t->flags & SN_ERR_MASK))
3174 t->flags |= SN_ERR_CLICL;
3175 if (!(t->flags & SN_FINST_MASK))
3176 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003177 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003178 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003179 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3180
3181 /* read timeout : give up with an error message.
3182 */
3183 t->logs.status = 408;
3184 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003185 if (!(t->flags & SN_ERR_MASK))
3186 t->flags |= SN_ERR_CLITO;
3187 if (!(t->flags & SN_FINST_MASK))
3188 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003189 return 1;
3190 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003191
3192 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003193 }
3194 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003195 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003196 /* FIXME: this error handling is partly buggy because we always report
3197 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3198 * or HEADER phase. BTW, it's not logical to expire the client while
3199 * we're waiting for the server to connect.
3200 */
willy tarreau0f7af912005-12-17 12:21:26 +01003201 /* read or write error */
3202 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003203 tv_eternity(&t->crexpire);
3204 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003205 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003206 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003207 if (!(t->flags & SN_ERR_MASK))
3208 t->flags |= SN_ERR_CLICL;
3209 if (!(t->flags & SN_FINST_MASK))
3210 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003211 return 1;
3212 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003213 /* last read, or end of server write */
3214 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003215 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003216 tv_eternity(&t->crexpire);
3217 shutdown(t->cli_fd, SHUT_RD);
3218 t->cli_state = CL_STSHUTR;
3219 return 1;
3220 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003221 /* last server read and buffer empty */
3222 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003223 FD_CLR(t->cli_fd, StaticWriteEvent);
3224 tv_eternity(&t->cwexpire);
3225 shutdown(t->cli_fd, SHUT_WR);
3226 t->cli_state = CL_STSHUTW;
3227 return 1;
3228 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003229 /* read timeout */
3230 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3231 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003232 tv_eternity(&t->crexpire);
3233 shutdown(t->cli_fd, SHUT_RD);
3234 t->cli_state = CL_STSHUTR;
3235 if (!(t->flags & SN_ERR_MASK))
3236 t->flags |= SN_ERR_CLITO;
3237 if (!(t->flags & SN_FINST_MASK))
3238 t->flags |= SN_FINST_D;
3239 return 1;
3240 }
3241 /* write timeout */
3242 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3243 FD_CLR(t->cli_fd, StaticWriteEvent);
3244 tv_eternity(&t->cwexpire);
3245 shutdown(t->cli_fd, SHUT_WR);
3246 t->cli_state = CL_STSHUTW;
3247 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003248 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003249 if (!(t->flags & SN_FINST_MASK))
3250 t->flags |= SN_FINST_D;
3251 return 1;
3252 }
willy tarreau0f7af912005-12-17 12:21:26 +01003253
willy tarreauc58fc692005-12-17 14:13:08 +01003254 if (req->l >= req->rlim - req->data) {
3255 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003256 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003257 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003258 FD_CLR(t->cli_fd, StaticReadEvent);
3259 tv_eternity(&t->crexpire);
3260 }
3261 }
3262 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003263 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003264 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3265 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003266 if (!t->proxy->clitimeout ||
3267 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3268 /* If the client has no timeout, or if the server not ready yet, and we
3269 * know for sure that it can expire, then it's cleaner to disable the
3270 * timeout on the client side so that too low values cannot make the
3271 * sessions abort too early.
3272 */
willy tarreau0f7af912005-12-17 12:21:26 +01003273 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003274 else
3275 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003276 }
3277 }
3278
3279 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003280 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003281 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3282 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3283 tv_eternity(&t->cwexpire);
3284 }
3285 }
3286 else { /* buffer not empty */
3287 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3288 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003289 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003290 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003291 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3292 t->crexpire = t->cwexpire;
3293 }
willy tarreau0f7af912005-12-17 12:21:26 +01003294 else
3295 tv_eternity(&t->cwexpire);
3296 }
3297 }
3298 return 0; /* other cases change nothing */
3299 }
3300 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003301 if (t->res_cw == RES_ERROR) {
3302 tv_eternity(&t->cwexpire);
3303 fd_delete(t->cli_fd);
3304 t->cli_state = CL_STCLOSE;
3305 if (!(t->flags & SN_ERR_MASK))
3306 t->flags |= SN_ERR_CLICL;
3307 if (!(t->flags & SN_FINST_MASK))
3308 t->flags |= SN_FINST_D;
3309 return 1;
3310 }
3311 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003312 tv_eternity(&t->cwexpire);
3313 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003314 t->cli_state = CL_STCLOSE;
3315 return 1;
3316 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003317 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3318 tv_eternity(&t->cwexpire);
3319 fd_delete(t->cli_fd);
3320 t->cli_state = CL_STCLOSE;
3321 if (!(t->flags & SN_ERR_MASK))
3322 t->flags |= SN_ERR_CLITO;
3323 if (!(t->flags & SN_FINST_MASK))
3324 t->flags |= SN_FINST_D;
3325 return 1;
3326 }
willy tarreau0f7af912005-12-17 12:21:26 +01003327 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003328 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003329 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3330 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3331 tv_eternity(&t->cwexpire);
3332 }
3333 }
3334 else { /* buffer not empty */
3335 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3336 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003337 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003338 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003339 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3340 t->crexpire = t->cwexpire;
3341 }
willy tarreau0f7af912005-12-17 12:21:26 +01003342 else
3343 tv_eternity(&t->cwexpire);
3344 }
3345 }
3346 return 0;
3347 }
3348 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003349 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003350 tv_eternity(&t->crexpire);
3351 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003352 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003353 if (!(t->flags & SN_ERR_MASK))
3354 t->flags |= SN_ERR_CLICL;
3355 if (!(t->flags & SN_FINST_MASK))
3356 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003357 return 1;
3358 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003359 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3360 tv_eternity(&t->crexpire);
3361 fd_delete(t->cli_fd);
3362 t->cli_state = CL_STCLOSE;
3363 return 1;
3364 }
3365 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3366 tv_eternity(&t->crexpire);
3367 fd_delete(t->cli_fd);
3368 t->cli_state = CL_STCLOSE;
3369 if (!(t->flags & SN_ERR_MASK))
3370 t->flags |= SN_ERR_CLITO;
3371 if (!(t->flags & SN_FINST_MASK))
3372 t->flags |= SN_FINST_D;
3373 return 1;
3374 }
willy tarreauef900ab2005-12-17 12:52:52 +01003375 else if (req->l >= req->rlim - req->data) {
3376 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003377 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003378 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003379 FD_CLR(t->cli_fd, StaticReadEvent);
3380 tv_eternity(&t->crexpire);
3381 }
3382 }
3383 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003384 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003385 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3386 FD_SET(t->cli_fd, StaticReadEvent);
3387 if (t->proxy->clitimeout)
3388 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3389 else
3390 tv_eternity(&t->crexpire);
3391 }
3392 }
3393 return 0;
3394 }
3395 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003396 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003397 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003398 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 +01003399 write(1, trash, len);
3400 }
3401 return 0;
3402 }
3403 return 0;
3404}
3405
3406
3407/*
3408 * manages the server FSM and its socket. It returns 1 if a state has changed
3409 * (and a resync may be needed), 0 else.
3410 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003411int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003412 int s = t->srv_state;
3413 int c = t->cli_state;
3414 struct buffer *req = t->req;
3415 struct buffer *rep = t->rep;
3416
willy tarreau750a4722005-12-17 13:21:24 +01003417#ifdef DEBUG_FULL
3418 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3419#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003420 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3421 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3422 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3423 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003424 if (s == SV_STIDLE) {
3425 if (c == CL_STHEADERS)
3426 return 0; /* stay in idle, waiting for data to reach the client side */
3427 else if (c == CL_STCLOSE ||
3428 c == CL_STSHUTW ||
3429 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3430 tv_eternity(&t->cnexpire);
3431 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003432 if (!(t->flags & SN_ERR_MASK))
3433 t->flags |= SN_ERR_CLICL;
3434 if (!(t->flags & SN_FINST_MASK))
3435 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003436 return 1;
3437 }
3438 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003439 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003440 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3441 t->srv_state = SV_STCONN;
3442 }
3443 else { /* try again */
3444 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003445 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003446 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003447 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003448 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3449 t->flags &= ~SN_CK_MASK;
3450 t->flags |= SN_CK_DOWN;
3451 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003452 }
3453
3454 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003455 t->srv_state = SV_STCONN;
3456 break;
3457 }
3458 }
3459 if (t->conn_retries < 0) {
3460 /* if conn_retries < 0 or other error, let's abort */
3461 tv_eternity(&t->cnexpire);
3462 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003463 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003464 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003465 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003466 if (!(t->flags & SN_ERR_MASK))
3467 t->flags |= SN_ERR_SRVCL;
3468 if (!(t->flags & SN_FINST_MASK))
3469 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003470 }
3471 }
3472 return 1;
3473 }
3474 }
3475 else if (s == SV_STCONN) { /* connection in progress */
3476 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3477 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3478 return 0; /* nothing changed */
3479 }
3480 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3481 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3482 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003483 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003484 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003485 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003486 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003487 if (t->conn_retries >= 0) {
3488 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003489 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003490 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003491 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3492 t->flags &= ~SN_CK_MASK;
3493 t->flags |= SN_CK_DOWN;
3494 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003495 }
3496 if (connect_server(t) == 0)
3497 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003498 }
3499 /* if conn_retries < 0 or other error, let's abort */
3500 tv_eternity(&t->cnexpire);
3501 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003502 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003503 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003504 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003505 if (!(t->flags & SN_ERR_MASK))
3506 t->flags |= SN_ERR_SRVCL;
3507 if (!(t->flags & SN_FINST_MASK))
3508 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003509 return 1;
3510 }
3511 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003512 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003513
willy tarreau0f7af912005-12-17 12:21:26 +01003514 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003515 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003516 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003517 tv_eternity(&t->swexpire);
3518 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003519 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003520 if (t->proxy->srvtimeout) {
3521 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3522 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3523 t->srexpire = t->swexpire;
3524 }
3525 else
3526 tv_eternity(&t->swexpire);
3527 }
willy tarreau0f7af912005-12-17 12:21:26 +01003528
3529 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3530 FD_SET(t->srv_fd, StaticReadEvent);
3531 if (t->proxy->srvtimeout)
3532 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3533 else
3534 tv_eternity(&t->srexpire);
3535
3536 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003537 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01003538
3539 /* if the user wants to log as soon as possible, without counting
3540 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003541 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003542 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
3543 sess_log(t);
3544 }
willy tarreau0f7af912005-12-17 12:21:26 +01003545 }
willy tarreauef900ab2005-12-17 12:52:52 +01003546 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003547 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003548 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3549 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003550 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003551 return 1;
3552 }
3553 }
3554 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003555 /* now parse the partial (or complete) headers */
3556 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3557 char *ptr;
3558 int delete_header;
3559
3560 ptr = rep->lr;
3561
3562 /* look for the end of the current header */
3563 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3564 ptr++;
3565
3566 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003567 int line, len;
3568
3569 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01003570
3571 /* first, we'll block if security checks have caught nasty things */
3572 if (t->flags & SN_CACHEABLE) {
3573 if ((t->flags & SN_CACHE_COOK) &&
3574 (t->flags & SN_SCK_ANY) &&
3575 (t->proxy->options & PR_O_CHK_CACHE)) {
3576
3577 /* we're in presence of a cacheable response containing
3578 * a set-cookie header. We'll block it as requested by
3579 * the 'checkcache' option, and send an alert.
3580 */
3581 tv_eternity(&t->srexpire);
3582 tv_eternity(&t->swexpire);
3583 fd_delete(t->srv_fd);
3584 t->srv_state = SV_STCLOSE;
3585 t->logs.status = 502;
3586 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3587 if (!(t->flags & SN_ERR_MASK))
3588 t->flags |= SN_ERR_PRXCOND;
3589 if (!(t->flags & SN_FINST_MASK))
3590 t->flags |= SN_FINST_H;
3591
3592 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3593 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3594
3595 return 1;
3596 }
3597 }
3598
willy tarreau982249e2005-12-18 00:57:06 +01003599 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
3600 if (t->flags & SN_SVDENY) {
3601 tv_eternity(&t->srexpire);
3602 tv_eternity(&t->swexpire);
3603 fd_delete(t->srv_fd);
3604 t->srv_state = SV_STCLOSE;
3605 t->logs.status = 502;
3606 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3607 if (!(t->flags & SN_ERR_MASK))
3608 t->flags |= SN_ERR_PRXCOND;
3609 if (!(t->flags & SN_FINST_MASK))
3610 t->flags |= SN_FINST_H;
3611 return 1;
3612 }
3613
willy tarreau5cbea6f2005-12-17 12:48:26 +01003614 /* we'll have something else to do here : add new headers ... */
3615
willy tarreaucd878942005-12-17 13:27:43 +01003616 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3617 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003618 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003619 * insert a set-cookie here, except if we want to insert only on POST
3620 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003621 */
willy tarreau750a4722005-12-17 13:21:24 +01003622 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003623 t->proxy->cookie_name,
3624 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003625
willy tarreau036e1ce2005-12-17 13:46:33 +01003626 t->flags |= SN_SCK_INSERTED;
3627
willy tarreau750a4722005-12-17 13:21:24 +01003628 /* Here, we will tell an eventual cache on the client side that we don't
3629 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3630 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3631 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3632 */
willy tarreau240afa62005-12-17 13:14:35 +01003633 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003634 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3635 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003636
willy tarreau750a4722005-12-17 13:21:24 +01003637 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003638 }
3639
3640 /* headers to be added */
3641 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003642 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3643 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003644 }
3645
willy tarreau25c4ea52005-12-18 00:49:49 +01003646 /* add a "connection: close" line if needed */
3647 if (t->proxy->options & PR_O_HTTP_CLOSE)
3648 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
3649
willy tarreau5cbea6f2005-12-17 12:48:26 +01003650 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003651 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003652 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01003653
3654 /* if the user wants to log as soon as possible, without counting
3655 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003656 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003657 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
3658 t->logs.bytes = rep->h - rep->data;
3659 sess_log(t);
3660 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003661 break;
3662 }
3663
3664 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3665 if (ptr > rep->r - 2) {
3666 /* this is a partial header, let's wait for more to come */
3667 rep->lr = ptr;
3668 break;
3669 }
3670
3671 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3672 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3673
3674 /* now we know that *ptr is either \r or \n,
3675 * and that there are at least 1 char after it.
3676 */
3677 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3678 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3679 else
3680 rep->lr = ptr + 2; /* \r\n or \n\r */
3681
3682 /*
3683 * now we know that we have a full header ; we can do whatever
3684 * we want with these pointers :
3685 * rep->h = beginning of header
3686 * ptr = end of header (first \r or \n)
3687 * rep->lr = beginning of next line (next rep->h)
3688 * rep->r = end of data (not used at this stage)
3689 */
3690
willy tarreaua1598082005-12-17 13:08:06 +01003691
willy tarreau982249e2005-12-18 00:57:06 +01003692 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01003693 t->logs.logwait &= ~LW_RESP;
3694 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01003695 switch (t->logs.status) {
3696 case 200:
3697 case 203:
3698 case 206:
3699 case 300:
3700 case 301:
3701 case 410:
3702 /* RFC2616 @13.4:
3703 * "A response received with a status code of
3704 * 200, 203, 206, 300, 301 or 410 MAY be stored
3705 * by a cache (...) unless a cache-control
3706 * directive prohibits caching."
3707 *
3708 * RFC2616 @9.5: POST method :
3709 * "Responses to this method are not cacheable,
3710 * unless the response includes appropriate
3711 * Cache-Control or Expires header fields."
3712 */
3713 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
3714 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
3715 break;
3716 default:
3717 break;
3718 }
willy tarreau4302f492005-12-18 01:00:37 +01003719 }
3720 else if (t->logs.logwait & LW_RSPHDR) {
3721 struct cap_hdr *h;
3722 int len;
3723 for (h = t->proxy->rsp_cap; h; h = h->next) {
3724 if ((h->namelen + 2 <= ptr - rep->h) &&
3725 (rep->h[h->namelen] == ':') &&
3726 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
3727
3728 if (t->rsp_cap[h->index] == NULL)
3729 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3730
3731 len = ptr - (rep->h + h->namelen + 2);
3732 if (len > h->len)
3733 len = h->len;
3734
3735 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
3736 t->rsp_cap[h->index][len]=0;
3737 }
3738 }
3739
willy tarreaua1598082005-12-17 13:08:06 +01003740 }
3741
willy tarreau5cbea6f2005-12-17 12:48:26 +01003742 delete_header = 0;
3743
willy tarreau982249e2005-12-18 00:57:06 +01003744 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003745 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003746 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 +01003747 max = ptr - rep->h;
3748 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003749 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003750 trash[len++] = '\n';
3751 write(1, trash, len);
3752 }
3753
willy tarreau25c4ea52005-12-18 00:49:49 +01003754 /* remove "connection: " if needed */
3755 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3756 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
3757 delete_header = 1;
3758 }
3759
willy tarreau5cbea6f2005-12-17 12:48:26 +01003760 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003761 if (!delete_header && t->proxy->rsp_exp != NULL
3762 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003763 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003764 char term;
3765
3766 term = *ptr;
3767 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003768 exp = t->proxy->rsp_exp;
3769 do {
3770 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3771 switch (exp->action) {
3772 case ACT_ALLOW:
3773 if (!(t->flags & SN_SVDENY))
3774 t->flags |= SN_SVALLOW;
3775 break;
3776 case ACT_REPLACE:
3777 if (!(t->flags & SN_SVDENY)) {
3778 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3779 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3780 }
3781 break;
3782 case ACT_REMOVE:
3783 if (!(t->flags & SN_SVDENY))
3784 delete_header = 1;
3785 break;
3786 case ACT_DENY:
3787 if (!(t->flags & SN_SVALLOW))
3788 t->flags |= SN_SVDENY;
3789 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003790 case ACT_PASS: /* we simply don't deny this one */
3791 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003792 }
3793 break;
3794 }
willy tarreaue39cd132005-12-17 13:00:18 +01003795 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003796 *ptr = term; /* restore the string terminator */
3797 }
3798
willy tarreau97f58572005-12-18 00:53:44 +01003799 /* check for cache-control: or pragma: headers */
3800 if (!delete_header && (t->flags & SN_CACHEABLE)) {
3801 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
3802 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3803 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
3804 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01003805 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01003806 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3807 else {
3808 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01003809 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01003810 t->flags &= ~SN_CACHE_COOK;
3811 }
3812 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003813 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01003814 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003815 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01003816 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3817 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003818 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01003819 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01003820 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
3821 (rep->h + 25 == ptr || rep->h[25] == ',')) {
3822 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3823 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
3824 (rep->h + 21 == ptr || rep->h[21] == ',')) {
3825 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01003826 }
3827 }
3828 }
3829
willy tarreau5cbea6f2005-12-17 12:48:26 +01003830 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003831 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3832 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau906b2682005-12-17 13:49:52 +01003833 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003834 char *p1, *p2, *p3, *p4;
3835
willy tarreau97f58572005-12-18 00:53:44 +01003836 t->flags |= SN_SCK_ANY;
3837
willy tarreau5cbea6f2005-12-17 12:48:26 +01003838 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3839
3840 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003841 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003842 p1++;
3843
3844 if (p1 == ptr || *p1 == ';') /* end of cookie */
3845 break;
3846
3847 /* p1 is at the beginning of the cookie name */
3848 p2 = p1;
3849
3850 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3851 p2++;
3852
3853 if (p2 == ptr || *p2 == ';') /* next cookie */
3854 break;
3855
3856 p3 = p2 + 1; /* skips the '=' sign */
3857 if (p3 == ptr)
3858 break;
3859
3860 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003861 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003862 p4++;
3863
3864 /* here, we have the cookie name between p1 and p2,
3865 * and its value between p3 and p4.
3866 * we can process it.
3867 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003868
3869 /* first, let's see if we want to capture it */
3870 if (t->proxy->capture_name != NULL &&
3871 t->logs.srv_cookie == NULL &&
3872 (p4 - p1 >= t->proxy->capture_namelen) &&
3873 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3874 int log_len = p4 - p1;
3875
3876 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3877 Alert("HTTP logging : out of memory.\n");
3878 }
3879
3880 if (log_len > t->proxy->capture_len)
3881 log_len = t->proxy->capture_len;
3882 memcpy(t->logs.srv_cookie, p1, log_len);
3883 t->logs.srv_cookie[log_len] = 0;
3884 }
3885
3886 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3887 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003888 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003889 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003890
3891 /* If the cookie is in insert mode on a known server, we'll delete
3892 * this occurrence because we'll insert another one later.
3893 * We'll delete it too if the "indirect" option is set and we're in
3894 * a direct access. */
3895 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003896 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003897 /* this header must be deleted */
3898 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003899 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003900 }
3901 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3902 /* replace bytes p3->p4 with the cookie name associated
3903 * with this server since we know it.
3904 */
3905 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003906 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003907 }
willy tarreau0174f312005-12-18 01:02:42 +01003908 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
3909 /* insert the cookie name associated with this server
3910 * before existing cookie, and insert a delimitor between them..
3911 */
3912 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
3913 p3[t->srv->cklen] = COOKIE_DELIM;
3914 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
3915 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003916 break;
3917 }
3918 else {
3919 // fprintf(stderr,"Ignoring unknown cookie : ");
3920 // write(2, p1, p2-p1);
3921 // fprintf(stderr," = ");
3922 // write(2, p3, p4-p3);
3923 // fprintf(stderr,"\n");
3924 }
3925 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3926 } /* we're now at the end of the cookie value */
3927 } /* end of cookie processing */
3928
willy tarreau97f58572005-12-18 00:53:44 +01003929 /* check for any set-cookie in case we check for cacheability */
3930 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
3931 (t->proxy->options & PR_O_CHK_CACHE) &&
3932 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
3933 t->flags |= SN_SCK_ANY;
3934 }
3935
willy tarreau5cbea6f2005-12-17 12:48:26 +01003936 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003937 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003938 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003939
willy tarreau5cbea6f2005-12-17 12:48:26 +01003940 rep->h = rep->lr;
3941 } /* while (rep->lr < rep->r) */
3942
3943 /* end of header processing (even if incomplete) */
3944
willy tarreauef900ab2005-12-17 12:52:52 +01003945 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3946 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3947 * full. We cannot loop here since event_srv_read will disable it only if
3948 * rep->l == rlim-data
3949 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003950 FD_SET(t->srv_fd, StaticReadEvent);
3951 if (t->proxy->srvtimeout)
3952 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3953 else
3954 tv_eternity(&t->srexpire);
3955 }
willy tarreau0f7af912005-12-17 12:21:26 +01003956
willy tarreau8337c6b2005-12-17 13:41:01 +01003957 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003958 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003959 tv_eternity(&t->srexpire);
3960 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003961 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003962 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003963 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003964 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003965 if (!(t->flags & SN_ERR_MASK))
3966 t->flags |= SN_ERR_SRVCL;
3967 if (!(t->flags & SN_FINST_MASK))
3968 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003969 return 1;
3970 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003971 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003972 * since we are in header mode, if there's no space left for headers, we
3973 * won't be able to free more later, so the session will never terminate.
3974 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003975 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 +01003976 FD_CLR(t->srv_fd, StaticReadEvent);
3977 tv_eternity(&t->srexpire);
3978 shutdown(t->srv_fd, SHUT_RD);
3979 t->srv_state = SV_STSHUTR;
3980 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003981 }
3982 /* read timeout : return a 504 to the client.
3983 */
3984 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3985 tv_eternity(&t->srexpire);
3986 tv_eternity(&t->swexpire);
3987 fd_delete(t->srv_fd);
3988 t->srv_state = SV_STCLOSE;
3989 t->logs.status = 504;
3990 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003991 if (!(t->flags & SN_ERR_MASK))
3992 t->flags |= SN_ERR_SRVTO;
3993 if (!(t->flags & SN_FINST_MASK))
3994 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003995 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003996
3997 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003998 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003999 /* FIXME!!! here, we don't want to switch to SHUTW if the
4000 * client shuts read too early, because we may still have
4001 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004002 * The side-effect is that if the client completely closes its
4003 * connection during SV_STHEADER, the connection to the server
4004 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004005 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004006 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004007 FD_CLR(t->srv_fd, StaticWriteEvent);
4008 tv_eternity(&t->swexpire);
4009 shutdown(t->srv_fd, SHUT_WR);
4010 t->srv_state = SV_STSHUTW;
4011 return 1;
4012 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004013 /* write timeout */
4014 /* FIXME!!! here, we don't want to switch to SHUTW if the
4015 * client shuts read too early, because we may still have
4016 * some work to do on the headers.
4017 */
4018 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4019 FD_CLR(t->srv_fd, StaticWriteEvent);
4020 tv_eternity(&t->swexpire);
4021 shutdown(t->srv_fd, SHUT_WR);
4022 t->srv_state = SV_STSHUTW;
4023 if (!(t->flags & SN_ERR_MASK))
4024 t->flags |= SN_ERR_SRVTO;
4025 if (!(t->flags & SN_FINST_MASK))
4026 t->flags |= SN_FINST_H;
4027 return 1;
4028 }
willy tarreau0f7af912005-12-17 12:21:26 +01004029
4030 if (req->l == 0) {
4031 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4032 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4033 tv_eternity(&t->swexpire);
4034 }
4035 }
4036 else { /* client buffer not empty */
4037 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4038 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004039 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004040 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004041 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4042 t->srexpire = t->swexpire;
4043 }
willy tarreau0f7af912005-12-17 12:21:26 +01004044 else
4045 tv_eternity(&t->swexpire);
4046 }
4047 }
4048
willy tarreau5cbea6f2005-12-17 12:48:26 +01004049 /* be nice with the client side which would like to send a complete header
4050 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4051 * would read all remaining data at once ! The client should not write past rep->lr
4052 * when the server is in header state.
4053 */
4054 //return header_processed;
4055 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004056 }
4057 else if (s == SV_STDATA) {
4058 /* read or write error */
4059 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004060 tv_eternity(&t->srexpire);
4061 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004062 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004063 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004064 if (!(t->flags & SN_ERR_MASK))
4065 t->flags |= SN_ERR_SRVCL;
4066 if (!(t->flags & SN_FINST_MASK))
4067 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004068 return 1;
4069 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004070 /* last read, or end of client write */
4071 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004072 FD_CLR(t->srv_fd, StaticReadEvent);
4073 tv_eternity(&t->srexpire);
4074 shutdown(t->srv_fd, SHUT_RD);
4075 t->srv_state = SV_STSHUTR;
4076 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004077 }
4078 /* end of client read and no more data to send */
4079 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4080 FD_CLR(t->srv_fd, StaticWriteEvent);
4081 tv_eternity(&t->swexpire);
4082 shutdown(t->srv_fd, SHUT_WR);
4083 t->srv_state = SV_STSHUTW;
4084 return 1;
4085 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004086 /* read timeout */
4087 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4088 FD_CLR(t->srv_fd, StaticReadEvent);
4089 tv_eternity(&t->srexpire);
4090 shutdown(t->srv_fd, SHUT_RD);
4091 t->srv_state = SV_STSHUTR;
4092 if (!(t->flags & SN_ERR_MASK))
4093 t->flags |= SN_ERR_SRVTO;
4094 if (!(t->flags & SN_FINST_MASK))
4095 t->flags |= SN_FINST_D;
4096 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004097 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004098 /* write timeout */
4099 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004100 FD_CLR(t->srv_fd, StaticWriteEvent);
4101 tv_eternity(&t->swexpire);
4102 shutdown(t->srv_fd, SHUT_WR);
4103 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004104 if (!(t->flags & SN_ERR_MASK))
4105 t->flags |= SN_ERR_SRVTO;
4106 if (!(t->flags & SN_FINST_MASK))
4107 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004108 return 1;
4109 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004110
4111 /* recompute request time-outs */
4112 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004113 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4114 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4115 tv_eternity(&t->swexpire);
4116 }
4117 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004118 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004119 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4120 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004121 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004122 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004123 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4124 t->srexpire = t->swexpire;
4125 }
willy tarreau0f7af912005-12-17 12:21:26 +01004126 else
4127 tv_eternity(&t->swexpire);
4128 }
4129 }
4130
willy tarreaub1ff9db2005-12-17 13:51:03 +01004131 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004132 if (rep->l == BUFSIZE) { /* no room to read more data */
4133 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4134 FD_CLR(t->srv_fd, StaticReadEvent);
4135 tv_eternity(&t->srexpire);
4136 }
4137 }
4138 else {
4139 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4140 FD_SET(t->srv_fd, StaticReadEvent);
4141 if (t->proxy->srvtimeout)
4142 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4143 else
4144 tv_eternity(&t->srexpire);
4145 }
4146 }
4147
4148 return 0; /* other cases change nothing */
4149 }
4150 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004151 if (t->res_sw == RES_ERROR) {
4152 //FD_CLR(t->srv_fd, StaticWriteEvent);
4153 tv_eternity(&t->swexpire);
4154 fd_delete(t->srv_fd);
4155 //close(t->srv_fd);
4156 t->srv_state = SV_STCLOSE;
4157 if (!(t->flags & SN_ERR_MASK))
4158 t->flags |= SN_ERR_SRVCL;
4159 if (!(t->flags & SN_FINST_MASK))
4160 t->flags |= SN_FINST_D;
4161 return 1;
4162 }
4163 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004164 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004165 tv_eternity(&t->swexpire);
4166 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004167 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004168 t->srv_state = SV_STCLOSE;
4169 return 1;
4170 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004171 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4172 //FD_CLR(t->srv_fd, StaticWriteEvent);
4173 tv_eternity(&t->swexpire);
4174 fd_delete(t->srv_fd);
4175 //close(t->srv_fd);
4176 t->srv_state = SV_STCLOSE;
4177 if (!(t->flags & SN_ERR_MASK))
4178 t->flags |= SN_ERR_SRVTO;
4179 if (!(t->flags & SN_FINST_MASK))
4180 t->flags |= SN_FINST_D;
4181 return 1;
4182 }
willy tarreau0f7af912005-12-17 12:21:26 +01004183 else if (req->l == 0) {
4184 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4185 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4186 tv_eternity(&t->swexpire);
4187 }
4188 }
4189 else { /* buffer not empty */
4190 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4191 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004192 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004193 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004194 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4195 t->srexpire = t->swexpire;
4196 }
willy tarreau0f7af912005-12-17 12:21:26 +01004197 else
4198 tv_eternity(&t->swexpire);
4199 }
4200 }
4201 return 0;
4202 }
4203 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004204 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004205 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004206 tv_eternity(&t->srexpire);
4207 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004208 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004209 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004210 if (!(t->flags & SN_ERR_MASK))
4211 t->flags |= SN_ERR_SRVCL;
4212 if (!(t->flags & SN_FINST_MASK))
4213 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004214 return 1;
4215 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004216 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4217 //FD_CLR(t->srv_fd, StaticReadEvent);
4218 tv_eternity(&t->srexpire);
4219 fd_delete(t->srv_fd);
4220 //close(t->srv_fd);
4221 t->srv_state = SV_STCLOSE;
4222 return 1;
4223 }
4224 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4225 //FD_CLR(t->srv_fd, StaticReadEvent);
4226 tv_eternity(&t->srexpire);
4227 fd_delete(t->srv_fd);
4228 //close(t->srv_fd);
4229 t->srv_state = SV_STCLOSE;
4230 if (!(t->flags & SN_ERR_MASK))
4231 t->flags |= SN_ERR_SRVTO;
4232 if (!(t->flags & SN_FINST_MASK))
4233 t->flags |= SN_FINST_D;
4234 return 1;
4235 }
willy tarreau0f7af912005-12-17 12:21:26 +01004236 else if (rep->l == BUFSIZE) { /* no room to read more data */
4237 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4238 FD_CLR(t->srv_fd, StaticReadEvent);
4239 tv_eternity(&t->srexpire);
4240 }
4241 }
4242 else {
4243 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4244 FD_SET(t->srv_fd, StaticReadEvent);
4245 if (t->proxy->srvtimeout)
4246 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4247 else
4248 tv_eternity(&t->srexpire);
4249 }
4250 }
4251 return 0;
4252 }
4253 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004254 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004255 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004256 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 +01004257 write(1, trash, len);
4258 }
4259 return 0;
4260 }
4261 return 0;
4262}
4263
4264
willy tarreau5cbea6f2005-12-17 12:48:26 +01004265/* Processes the client and server jobs of a session task, then
4266 * puts it back to the wait queue in a clean state, or
4267 * cleans up its resources if it must be deleted. Returns
4268 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01004269 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004270int process_session(struct task *t) {
4271 struct session *s = t->context;
4272 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004273
willy tarreau5cbea6f2005-12-17 12:48:26 +01004274 do {
4275 fsm_resync = 0;
4276 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4277 fsm_resync |= process_cli(s);
4278 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4279 fsm_resync |= process_srv(s);
4280 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4281 } while (fsm_resync);
4282
4283 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004284 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004285 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004286
willy tarreau5cbea6f2005-12-17 12:48:26 +01004287 tv_min(&min1, &s->crexpire, &s->cwexpire);
4288 tv_min(&min2, &s->srexpire, &s->swexpire);
4289 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004290 tv_min(&t->expire, &min1, &min2);
4291
4292 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004293 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004294
willy tarreau5cbea6f2005-12-17 12:48:26 +01004295 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004296 }
4297
willy tarreau5cbea6f2005-12-17 12:48:26 +01004298 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004299 actconn--;
4300
willy tarreau982249e2005-12-18 00:57:06 +01004301 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004302 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004303 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 +01004304 write(1, trash, len);
4305 }
4306
willy tarreau750a4722005-12-17 13:21:24 +01004307 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004308 if (s->rep != NULL)
4309 s->logs.bytes = s->rep->total;
4310
willy tarreau9fe663a2005-12-17 13:02:59 +01004311 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004312 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004313 sess_log(s);
4314
willy tarreau0f7af912005-12-17 12:21:26 +01004315 /* the task MUST not be in the run queue anymore */
4316 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004317 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004318 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004319 return -1; /* rest in peace for eternity */
4320}
4321
4322
4323
4324/*
4325 * manages a server health-check. Returns
4326 * the time the task accepts to wait, or -1 for infinity.
4327 */
4328int process_chk(struct task *t) {
4329 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004330 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004331 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004332
willy tarreauef900ab2005-12-17 12:52:52 +01004333 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004334
4335 if (fd < 0) { /* no check currently running */
4336 //fprintf(stderr, "process_chk: 2\n");
4337 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4338 task_queue(t); /* restore t to its place in the task list */
4339 return tv_remain(&now, &t->expire);
4340 }
4341
4342 /* we'll initiate a new check */
4343 s->result = 0; /* no result yet */
4344 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004345 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004346 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4347 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4348 //fprintf(stderr, "process_chk: 3\n");
4349
willy tarreaua41a8b42005-12-17 14:02:24 +01004350 /* we'll connect to the check port on the server */
4351 sa = s->addr;
4352 sa.sin_port = htons(s->check_port);
4353
willy tarreau0174f312005-12-18 01:02:42 +01004354 /* allow specific binding :
4355 * - server-specific at first
4356 * - proxy-specific next
4357 */
4358 if (s->state & SRV_BIND_SRC) {
4359 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4360 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
4361 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
4362 s->proxy->id, s->id);
4363 s->result = -1;
4364 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004365 }
willy tarreau0174f312005-12-18 01:02:42 +01004366 else if (s->proxy->options & PR_O_BIND_SRC) {
4367 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4368 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4369 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
4370 s->proxy->id);
4371 s->result = -1;
4372 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004373 }
willy tarreau0174f312005-12-18 01:02:42 +01004374
4375 if (!s->result) {
4376 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
4377 /* OK, connection in progress or established */
4378
4379 //fprintf(stderr, "process_chk: 4\n");
4380
4381 s->curfd = fd; /* that's how we know a test is in progress ;-) */
4382 fdtab[fd].owner = t;
4383 fdtab[fd].read = &event_srv_chk_r;
4384 fdtab[fd].write = &event_srv_chk_w;
4385 fdtab[fd].state = FD_STCONN; /* connection in progress */
4386 FD_SET(fd, StaticWriteEvent); /* for connect status */
4387 fd_insert(fd);
4388 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4389 tv_delayfrom(&t->expire, &now, s->inter);
4390 task_queue(t); /* restore t to its place in the task list */
4391 return tv_remain(&now, &t->expire);
4392 }
4393 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
4394 s->result = -1; /* a real error */
4395 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004396 }
4397 }
4398 //fprintf(stderr, "process_chk: 5\n");
4399 close(fd);
4400 }
4401
4402 if (!s->result) { /* nothing done */
4403 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004404 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004405 task_queue(t); /* restore t to its place in the task list */
4406 return tv_remain(&now, &t->expire);
4407 }
4408
4409 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01004410 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004411 s->health--; /* still good */
4412 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004413 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01004414 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004415 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004416 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01004417
willy tarreaudd07e972005-12-18 00:48:48 +01004418 if (find_server(s->proxy) == NULL) {
4419 Alert("Proxy %s has no server available !\n", s->proxy->id);
4420 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4421 }
4422 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004423 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004424 }
4425
4426 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004427 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4428 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004429 }
4430 else {
4431 //fprintf(stderr, "process_chk: 8\n");
4432 /* there was a test running */
4433 if (s->result > 0) { /* good server detected */
4434 //fprintf(stderr, "process_chk: 9\n");
4435 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01004436 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004437 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004438 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004439 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004440 }
willy tarreauef900ab2005-12-17 12:52:52 +01004441
willy tarreaue47c8d72005-12-17 12:55:52 +01004442 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004443 s->state |= SRV_RUNNING;
4444 }
willy tarreauef900ab2005-12-17 12:52:52 +01004445 s->curfd = -1; /* no check running anymore */
4446 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004447 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004448 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004449 }
4450 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
4451 //fprintf(stderr, "process_chk: 10\n");
4452 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01004453 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004454 s->health--; /* still good */
4455 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004456 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01004457
willy tarreaudd07e972005-12-18 00:48:48 +01004458 if (s->health == s->rise) {
4459 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004460 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01004461
4462 if (find_server(s->proxy) == NULL) {
4463 Alert("Proxy %s has no server available !\n", s->proxy->id);
4464 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4465 }
willy tarreau535ae7a2005-12-17 12:58:00 +01004466 }
willy tarreauef900ab2005-12-17 12:52:52 +01004467
willy tarreau5cbea6f2005-12-17 12:48:26 +01004468 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004469 }
4470 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01004471 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004472 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004473 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004474 }
4475 /* if result is 0 and there's no timeout, we have to wait again */
4476 }
4477 //fprintf(stderr, "process_chk: 11\n");
4478 s->result = 0;
4479 task_queue(t); /* restore t to its place in the task list */
4480 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01004481}
4482
4483
willy tarreau5cbea6f2005-12-17 12:48:26 +01004484
willy tarreau0f7af912005-12-17 12:21:26 +01004485#if STATTIME > 0
4486int stats(void);
4487#endif
4488
4489/*
4490 * Main select() loop.
4491 */
4492
4493void select_loop() {
4494 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01004495 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01004496 int status;
4497 int fd,i;
4498 struct timeval delta;
4499 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004500 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01004501
willy tarreau5cbea6f2005-12-17 12:48:26 +01004502 tv_now(&now);
4503
4504 while (1) {
4505 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01004506
willy tarreau5cbea6f2005-12-17 12:48:26 +01004507 /* look for expired tasks and add them to the run queue.
4508 */
4509 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4510 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4511 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01004512 if (t->state & TASK_RUNNING)
4513 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004514
4515 /* wakeup expired entries. It doesn't matter if they are
4516 * already running because of a previous event
4517 */
4518 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01004519 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004520 task_wakeup(&rq, t);
4521 }
4522 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004523 /* first non-runnable task. Use its expiration date as an upper bound */
4524 int temp_time = tv_remain(&now, &t->expire);
4525 if (temp_time)
4526 next_time = temp_time;
4527 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004528 break;
4529 }
4530 }
4531
4532 /* process each task in the run queue now. Each task may be deleted
4533 * since we only use tnext.
4534 */
4535 tnext = rq;
4536 while ((t = tnext) != NULL) {
4537 int temp_time;
4538
4539 tnext = t->rqnext;
4540 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01004541 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004542 temp_time = t->process(t);
4543 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01004544 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004545 }
4546
willy tarreauef900ab2005-12-17 12:52:52 +01004547 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01004548
4549 /* maintain all proxies in a consistent state. This should quickly become a task */
4550 time2 = maintain_proxies();
4551 next_time = MINTIME(time2, next_time);
4552
4553 /* stop when there's no connection left and we don't allow them anymore */
4554 if (!actconn && listeners == 0)
4555 break;
4556
willy tarreau0f7af912005-12-17 12:21:26 +01004557
4558#if STATTIME > 0
4559 time2 = stats();
4560 // fprintf(stderr," stats = %d\n", time2);
4561 next_time = MINTIME(time2, next_time);
4562#endif
4563
willy tarreau5cbea6f2005-12-17 12:48:26 +01004564 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01004565 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004566 /* to avoid eventual select loops due to timer precision */
4567 next_time += SCHEDULER_RESOLUTION;
4568 delta.tv_sec = next_time / 1000;
4569 delta.tv_usec = (next_time % 1000) * 1000;
4570 }
4571 else if (next_time == 0) { /* allow select to return immediately when needed */
4572 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004573 }
4574
4575
4576 /* let's restore fdset state */
4577
4578 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004579 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004580 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
4581 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
4582 }
4583
4584// /* just a verification code, needs to be removed for performance */
4585// for (i=0; i<maxfd; i++) {
4586// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
4587// abort();
4588// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
4589// abort();
4590//
4591// }
4592
willy tarreau197e8ec2005-12-17 14:10:59 +01004593 status = select(maxfd,
4594 readnotnull ? ReadEvent : NULL,
4595 writenotnull ? WriteEvent : NULL,
4596 NULL,
4597 (next_time >= 0) ? &delta : NULL);
willy tarreau0f7af912005-12-17 12:21:26 +01004598
willy tarreau5cbea6f2005-12-17 12:48:26 +01004599 /* this is an experiment on the separation of the select work */
4600 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4601 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4602
willy tarreau0f7af912005-12-17 12:21:26 +01004603 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004604
willy tarreau0f7af912005-12-17 12:21:26 +01004605 if (status > 0) { /* must proceed with events */
4606
4607 int fds;
4608 char count;
4609
4610 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
4611 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
4612 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
4613
willy tarreau5cbea6f2005-12-17 12:48:26 +01004614 /* if we specify read first, the accepts and zero reads will be
4615 * seen first. Moreover, system buffers will be flushed faster.
4616 */
willy tarreau0f7af912005-12-17 12:21:26 +01004617 if (fdtab[fd].state == FD_STCLOSE)
4618 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01004619
4620 if (FD_ISSET(fd, ReadEvent))
4621 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004622
willy tarreau5cbea6f2005-12-17 12:48:26 +01004623 if (FD_ISSET(fd, WriteEvent))
4624 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004625 }
4626 }
4627 else {
4628 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
4629 }
willy tarreau0f7af912005-12-17 12:21:26 +01004630 }
4631}
4632
4633
4634#if STATTIME > 0
4635/*
4636 * Display proxy statistics regularly. It is designed to be called from the
4637 * select_loop().
4638 */
4639int stats(void) {
4640 static int lines;
4641 static struct timeval nextevt;
4642 static struct timeval lastevt;
4643 static struct timeval starttime = {0,0};
4644 unsigned long totaltime, deltatime;
4645 int ret;
4646
willy tarreau750a4722005-12-17 13:21:24 +01004647 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01004648 deltatime = (tv_diff(&lastevt, &now)?:1);
4649 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01004650
willy tarreau9fe663a2005-12-17 13:02:59 +01004651 if (global.mode & MODE_STATS) {
4652 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004653 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004654 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
4655 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004656 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004657 actconn, totalconn,
4658 stats_tsk_new, stats_tsk_good,
4659 stats_tsk_left, stats_tsk_right,
4660 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
4661 }
4662 }
4663
4664 tv_delayfrom(&nextevt, &now, STATTIME);
4665
4666 lastevt=now;
4667 }
4668 ret = tv_remain(&now, &nextevt);
4669 return ret;
4670}
4671#endif
4672
4673
4674/*
4675 * this function enables proxies when there are enough free sessions,
4676 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01004677 * select_loop(). It returns the time left before next expiration event
4678 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01004679 */
4680static int maintain_proxies(void) {
4681 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01004682 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004683 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01004684
4685 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004686 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01004687
4688 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01004689 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01004690 while (p) {
4691 if (p->nbconn < p->maxconn) {
4692 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004693 for (l = p->listen; l != NULL; l = l->next) {
4694 FD_SET(l->fd, StaticReadEvent);
4695 }
willy tarreau0f7af912005-12-17 12:21:26 +01004696 p->state = PR_STRUN;
4697 }
4698 }
4699 else {
4700 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004701 for (l = p->listen; l != NULL; l = l->next) {
4702 FD_CLR(l->fd, StaticReadEvent);
4703 }
willy tarreau0f7af912005-12-17 12:21:26 +01004704 p->state = PR_STIDLE;
4705 }
4706 }
4707 p = p->next;
4708 }
4709 }
4710 else { /* block all proxies */
4711 while (p) {
4712 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004713 for (l = p->listen; l != NULL; l = l->next) {
4714 FD_CLR(l->fd, StaticReadEvent);
4715 }
willy tarreau0f7af912005-12-17 12:21:26 +01004716 p->state = PR_STIDLE;
4717 }
4718 p = p->next;
4719 }
4720 }
4721
willy tarreau5cbea6f2005-12-17 12:48:26 +01004722 if (stopping) {
4723 p = proxy;
4724 while (p) {
4725 if (p->state != PR_STDISABLED) {
4726 int t;
4727 t = tv_remain(&now, &p->stop_time);
4728 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004729 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004730 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004731
willy tarreaua41a8b42005-12-17 14:02:24 +01004732 for (l = p->listen; l != NULL; l = l->next) {
4733 fd_delete(l->fd);
4734 listeners--;
4735 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004736 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004737 }
4738 else {
4739 tleft = MINTIME(t, tleft);
4740 }
4741 }
4742 p = p->next;
4743 }
4744 }
4745 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004746}
4747
4748/*
4749 * this function disables health-check servers so that the process will quickly be ignored
4750 * by load balancers.
4751 */
4752static void soft_stop(void) {
4753 struct proxy *p;
4754
4755 stopping = 1;
4756 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004757 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004758 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004759 if (p->state != PR_STDISABLED) {
4760 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004761 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004762 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004763 }
willy tarreau0f7af912005-12-17 12:21:26 +01004764 p = p->next;
4765 }
4766}
4767
4768/*
4769 * upon SIGUSR1, let's have a soft stop.
4770 */
4771void sig_soft_stop(int sig) {
4772 soft_stop();
4773 signal(sig, SIG_IGN);
4774}
4775
4776
willy tarreau8337c6b2005-12-17 13:41:01 +01004777/*
4778 * this function dumps every server's state when the process receives SIGHUP.
4779 */
4780void sig_dump_state(int sig) {
4781 struct proxy *p = proxy;
4782
4783 Warning("SIGHUP received, dumping servers states.\n");
4784 while (p) {
4785 struct server *s = p->srv;
4786
4787 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4788 while (s) {
4789 if (s->state & SRV_RUNNING) {
4790 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4791 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4792 }
4793 else {
4794 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4795 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4796 }
4797 s = s->next;
4798 }
willy tarreaudd07e972005-12-18 00:48:48 +01004799
4800 if (find_server(p) == NULL) {
4801 Warning("SIGHUP: proxy %s has no server available !\n", p);
4802 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
4803 }
4804
willy tarreau8337c6b2005-12-17 13:41:01 +01004805 p = p->next;
4806 }
4807 signal(sig, sig_dump_state);
4808}
4809
willy tarreau0f7af912005-12-17 12:21:26 +01004810void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004811 struct task *t, *tnext;
4812 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004813
willy tarreau5cbea6f2005-12-17 12:48:26 +01004814 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4815 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4816 tnext = t->next;
4817 s = t->context;
4818 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4819 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4820 "req=%d, rep=%d, clifd=%d\n",
4821 s, tv_remain(&now, &t->expire),
4822 s->cli_state,
4823 s->srv_state,
4824 FD_ISSET(s->cli_fd, StaticReadEvent),
4825 FD_ISSET(s->cli_fd, StaticWriteEvent),
4826 FD_ISSET(s->srv_fd, StaticReadEvent),
4827 FD_ISSET(s->srv_fd, StaticWriteEvent),
4828 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4829 );
willy tarreau0f7af912005-12-17 12:21:26 +01004830 }
4831}
4832
willy tarreaue39cd132005-12-17 13:00:18 +01004833void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4834 struct hdr_exp *exp;
4835
4836 while (*head != NULL)
4837 head = &(*head)->next;
4838
4839 exp = calloc(1, sizeof(struct hdr_exp));
4840
4841 exp->preg = preg;
4842 exp->replace = replace;
4843 exp->action = action;
4844 *head = exp;
4845}
4846
willy tarreau9fe663a2005-12-17 13:02:59 +01004847
willy tarreau0f7af912005-12-17 12:21:26 +01004848/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004849 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004850 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004851int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004852
willy tarreau9fe663a2005-12-17 13:02:59 +01004853 if (!strcmp(args[0], "global")) { /* new section */
4854 /* no option, nothing special to do */
4855 return 0;
4856 }
4857 else if (!strcmp(args[0], "daemon")) {
4858 global.mode |= MODE_DAEMON;
4859 }
4860 else if (!strcmp(args[0], "debug")) {
4861 global.mode |= MODE_DEBUG;
4862 }
4863 else if (!strcmp(args[0], "quiet")) {
4864 global.mode |= MODE_QUIET;
4865 }
4866 else if (!strcmp(args[0], "stats")) {
4867 global.mode |= MODE_STATS;
4868 }
4869 else if (!strcmp(args[0], "uid")) {
4870 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004871 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004872 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004873 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004874 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004875 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004876 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004877 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004878 global.uid = atol(args[1]);
4879 }
4880 else if (!strcmp(args[0], "gid")) {
4881 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004882 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004883 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004884 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004885 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004886 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004887 return -1;
4888 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004889 global.gid = atol(args[1]);
4890 }
4891 else if (!strcmp(args[0], "nbproc")) {
4892 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004893 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004894 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004895 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004896 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004897 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004898 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004899 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004900 global.nbproc = atol(args[1]);
4901 }
4902 else if (!strcmp(args[0], "maxconn")) {
4903 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004904 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004905 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004906 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004907 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004908 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004909 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004910 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004911 global.maxconn = atol(args[1]);
4912 }
4913 else if (!strcmp(args[0], "chroot")) {
4914 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004915 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004916 return 0;
4917 }
4918 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004919 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004920 return -1;
4921 }
4922 global.chroot = strdup(args[1]);
4923 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01004924 else if (!strcmp(args[0], "pidfile")) {
4925 if (global.pidfile != NULL) {
4926 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
4927 return 0;
4928 }
4929 if (*(args[1]) == 0) {
4930 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
4931 return -1;
4932 }
4933 global.pidfile = strdup(args[1]);
4934 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004935 else if (!strcmp(args[0], "log")) { /* syslog server address */
4936 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004937 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004938
4939 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004940 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004941 return -1;
4942 }
4943
4944 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4945 if (!strcmp(log_facilities[facility], args[2]))
4946 break;
4947
4948 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004949 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004950 exit(1);
4951 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004952
4953 level = 7; /* max syslog level = debug */
4954 if (*(args[3])) {
4955 while (level >= 0 && strcmp(log_levels[level], args[3]))
4956 level--;
4957 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004958 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004959 exit(1);
4960 }
4961 }
4962
willy tarreau9fe663a2005-12-17 13:02:59 +01004963 sa = str2sa(args[1]);
4964 if (!sa->sin_port)
4965 sa->sin_port = htons(SYSLOG_PORT);
4966
4967 if (global.logfac1 == -1) {
4968 global.logsrv1 = *sa;
4969 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004970 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004971 }
4972 else if (global.logfac2 == -1) {
4973 global.logsrv2 = *sa;
4974 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004975 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004976 }
4977 else {
4978 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4979 return -1;
4980 }
4981
4982 }
4983 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004984 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004985 return -1;
4986 }
4987 return 0;
4988}
4989
4990
willy tarreaua41a8b42005-12-17 14:02:24 +01004991void init_default_instance() {
4992 memset(&defproxy, 0, sizeof(defproxy));
4993 defproxy.mode = PR_MODE_TCP;
4994 defproxy.state = PR_STNEW;
4995 defproxy.maxconn = cfg_maxpconn;
4996 defproxy.conn_retries = CONN_RETRIES;
4997 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
4998}
4999
willy tarreau9fe663a2005-12-17 13:02:59 +01005000/*
5001 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
5002 */
5003int cfg_parse_listen(char *file, int linenum, char **args) {
5004 static struct proxy *curproxy = NULL;
5005 struct server *newsrv = NULL;
5006
5007 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01005008 if (!*args[1]) {
5009 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
5010 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005011 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005012 return -1;
5013 }
5014
5015 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005016 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005017 return -1;
5018 }
5019 curproxy->next = proxy;
5020 proxy = curproxy;
5021 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01005022 if (strchr(args[2], ':') != NULL)
5023 curproxy->listen = str2listener(args[2], curproxy->listen);
5024
willy tarreau9fe663a2005-12-17 13:02:59 +01005025 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01005026 curproxy->state = defproxy.state;
5027 curproxy->maxconn = defproxy.maxconn;
5028 curproxy->conn_retries = defproxy.conn_retries;
5029 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005030
5031 if (defproxy.check_req)
5032 curproxy->check_req = strdup(defproxy.check_req);
5033 curproxy->check_len = defproxy.check_len;
5034
5035 if (defproxy.cookie_name)
5036 curproxy->cookie_name = strdup(defproxy.cookie_name);
5037 curproxy->cookie_len = defproxy.cookie_len;
5038
5039 if (defproxy.capture_name)
5040 curproxy->capture_name = strdup(defproxy.capture_name);
5041 curproxy->capture_namelen = defproxy.capture_namelen;
5042 curproxy->capture_len = defproxy.capture_len;
5043
5044 if (defproxy.errmsg.msg400)
5045 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
5046 curproxy->errmsg.len400 = defproxy.errmsg.len400;
5047
5048 if (defproxy.errmsg.msg403)
5049 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
5050 curproxy->errmsg.len403 = defproxy.errmsg.len403;
5051
5052 if (defproxy.errmsg.msg408)
5053 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
5054 curproxy->errmsg.len408 = defproxy.errmsg.len408;
5055
5056 if (defproxy.errmsg.msg500)
5057 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
5058 curproxy->errmsg.len500 = defproxy.errmsg.len500;
5059
5060 if (defproxy.errmsg.msg502)
5061 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
5062 curproxy->errmsg.len502 = defproxy.errmsg.len502;
5063
5064 if (defproxy.errmsg.msg503)
5065 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
5066 curproxy->errmsg.len503 = defproxy.errmsg.len503;
5067
5068 if (defproxy.errmsg.msg504)
5069 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
5070 curproxy->errmsg.len504 = defproxy.errmsg.len504;
5071
willy tarreaua41a8b42005-12-17 14:02:24 +01005072 curproxy->clitimeout = defproxy.clitimeout;
5073 curproxy->contimeout = defproxy.contimeout;
5074 curproxy->srvtimeout = defproxy.srvtimeout;
5075 curproxy->mode = defproxy.mode;
5076 curproxy->logfac1 = defproxy.logfac1;
5077 curproxy->logsrv1 = defproxy.logsrv1;
5078 curproxy->loglev1 = defproxy.loglev1;
5079 curproxy->logfac2 = defproxy.logfac2;
5080 curproxy->logsrv2 = defproxy.logsrv2;
5081 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01005082 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01005083 curproxy->grace = defproxy.grace;
5084 curproxy->source_addr = defproxy.source_addr;
5085 return 0;
5086 }
5087 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005088 /* some variables may have already been initialized earlier */
5089 if (defproxy.check_req) free(defproxy.check_req);
5090 if (defproxy.cookie_name) free(defproxy.cookie_name);
5091 if (defproxy.capture_name) free(defproxy.capture_name);
5092 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
5093 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
5094 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
5095 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
5096 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
5097 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
5098 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
5099
5100 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01005101 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01005102 return 0;
5103 }
5104 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005105 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005106 return -1;
5107 }
5108
willy tarreaua41a8b42005-12-17 14:02:24 +01005109 if (!strcmp(args[0], "bind")) { /* new listen addresses */
5110 if (curproxy == &defproxy) {
5111 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5112 return -1;
5113 }
5114
5115 if (strchr(args[1], ':') == NULL) {
5116 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
5117 file, linenum, args[0]);
5118 return -1;
5119 }
5120 curproxy->listen = str2listener(args[1], curproxy->listen);
5121 return 0;
5122 }
5123 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01005124 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
5125 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
5126 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
5127 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005128 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005129 return -1;
5130 }
5131 }
5132 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
5133 curproxy->state = PR_STDISABLED;
5134 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005135 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
5136 curproxy->state = PR_STNEW;
5137 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005138 else if (!strcmp(args[0], "cookie")) { /* cookie name */
5139 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005140// if (curproxy == &defproxy) {
5141// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5142// return -1;
5143// }
willy tarreaua41a8b42005-12-17 14:02:24 +01005144
willy tarreau9fe663a2005-12-17 13:02:59 +01005145 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005146// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
5147// file, linenum);
5148// return 0;
5149 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005150 }
5151
5152 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005153 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
5154 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005155 return -1;
5156 }
5157 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005158 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005159
5160 cur_arg = 2;
5161 while (*(args[cur_arg])) {
5162 if (!strcmp(args[cur_arg], "rewrite")) {
5163 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01005164 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005165 else if (!strcmp(args[cur_arg], "indirect")) {
5166 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01005167 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005168 else if (!strcmp(args[cur_arg], "insert")) {
5169 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01005170 }
willy tarreau240afa62005-12-17 13:14:35 +01005171 else if (!strcmp(args[cur_arg], "nocache")) {
5172 curproxy->options |= PR_O_COOK_NOC;
5173 }
willy tarreaucd878942005-12-17 13:27:43 +01005174 else if (!strcmp(args[cur_arg], "postonly")) {
5175 curproxy->options |= PR_O_COOK_POST;
5176 }
willy tarreau0174f312005-12-18 01:02:42 +01005177 else if (!strcmp(args[cur_arg], "prefix")) {
5178 curproxy->options |= PR_O_COOK_PFX;
5179 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005180 else {
willy tarreau0174f312005-12-18 01:02:42 +01005181 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005182 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005183 return -1;
5184 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005185 cur_arg++;
5186 }
willy tarreau0174f312005-12-18 01:02:42 +01005187 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
5188 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
5189 file, linenum);
5190 return -1;
5191 }
5192
5193 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
5194 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005195 file, linenum);
5196 return -1;
5197 }
5198 }
willy tarreau4302f492005-12-18 01:00:37 +01005199 else if (!strcmp(args[0], "capture")) {
5200 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
5201 // if (curproxy == &defproxy) {
5202 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5203 // return -1;
5204 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005205
willy tarreau4302f492005-12-18 01:00:37 +01005206 if (curproxy->capture_name != NULL) {
5207 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
5208 // file, linenum, args[0]);
5209 // return 0;
5210 free(curproxy->capture_name);
5211 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005212
willy tarreau4302f492005-12-18 01:00:37 +01005213 if (*(args[4]) == 0) {
5214 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
5215 file, linenum, args[0]);
5216 return -1;
5217 }
5218 curproxy->capture_name = strdup(args[2]);
5219 curproxy->capture_namelen = strlen(curproxy->capture_name);
5220 curproxy->capture_len = atol(args[4]);
5221 if (curproxy->capture_len >= CAPTURE_LEN) {
5222 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
5223 file, linenum, CAPTURE_LEN - 1);
5224 curproxy->capture_len = CAPTURE_LEN - 1;
5225 }
5226 curproxy->to_log |= LW_COOKIE;
5227 }
5228 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
5229 struct cap_hdr *hdr;
5230
5231 if (curproxy == &defproxy) {
5232 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5233 return -1;
5234 }
5235
5236 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5237 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5238 file, linenum, args[0], args[1]);
5239 return -1;
5240 }
5241
5242 hdr = calloc(sizeof(struct cap_hdr), 1);
5243 hdr->next = curproxy->req_cap;
5244 hdr->name = strdup(args[3]);
5245 hdr->namelen = strlen(args[3]);
5246 hdr->len = atol(args[5]);
5247 hdr->index = curproxy->nb_req_cap++;
5248 curproxy->req_cap = hdr;
5249 curproxy->to_log |= LW_REQHDR;
5250 }
5251 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
5252 struct cap_hdr *hdr;
5253
5254 if (curproxy == &defproxy) {
5255 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5256 return -1;
5257 }
5258
5259 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5260 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5261 file, linenum, args[0], args[1]);
5262 return -1;
5263 }
5264 hdr = calloc(sizeof(struct cap_hdr), 1);
5265 hdr->next = curproxy->rsp_cap;
5266 hdr->name = strdup(args[3]);
5267 hdr->namelen = strlen(args[3]);
5268 hdr->len = atol(args[5]);
5269 hdr->index = curproxy->nb_rsp_cap++;
5270 curproxy->rsp_cap = hdr;
5271 curproxy->to_log |= LW_RSPHDR;
5272 }
5273 else {
5274 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005275 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005276 return -1;
5277 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005278 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005279 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005280 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005281 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005282 return 0;
5283 }
5284 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005285 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5286 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005287 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005288 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005289 curproxy->contimeout = atol(args[1]);
5290 }
5291 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005292 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005293 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
5294 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005295 return 0;
5296 }
5297 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005298 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5299 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005300 return -1;
5301 }
5302 curproxy->clitimeout = atol(args[1]);
5303 }
5304 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005305 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005306 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005307 return 0;
5308 }
5309 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005310 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5311 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005312 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005313 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005314 curproxy->srvtimeout = atol(args[1]);
5315 }
5316 else if (!strcmp(args[0], "retries")) { /* connection retries */
5317 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005318 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
5319 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005320 return -1;
5321 }
5322 curproxy->conn_retries = atol(args[1]);
5323 }
5324 else if (!strcmp(args[0], "option")) {
5325 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005326 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005327 return -1;
5328 }
5329 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005330 /* enable reconnections to dispatch */
5331 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01005332#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01005333 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005334 /* enable transparent proxy connections */
5335 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01005336#endif
5337 else if (!strcmp(args[1], "keepalive"))
5338 /* enable keep-alive */
5339 curproxy->options |= PR_O_KEEPALIVE;
5340 else if (!strcmp(args[1], "forwardfor"))
5341 /* insert x-forwarded-for field */
5342 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01005343 else if (!strcmp(args[1], "logasap"))
5344 /* log as soon as possible, without waiting for the session to complete */
5345 curproxy->options |= PR_O_LOGASAP;
5346 else if (!strcmp(args[1], "httpclose"))
5347 /* force connection: close in both directions in HTTP mode */
5348 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01005349 else if (!strcmp(args[1], "checkcache"))
5350 /* require examination of cacheability of the 'set-cookie' field */
5351 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01005352 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01005353 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01005354 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01005355 else if (!strcmp(args[1], "tcplog"))
5356 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01005357 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01005358 else if (!strcmp(args[1], "dontlognull")) {
5359 /* don't log empty requests */
5360 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005361 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005362 else if (!strcmp(args[1], "httpchk")) {
5363 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005364 if (curproxy->check_req != NULL) {
5365 free(curproxy->check_req);
5366 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005367 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005368 if (!*args[2]) { /* no argument */
5369 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
5370 curproxy->check_len = strlen(DEF_CHECK_REQ);
5371 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01005372 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
5373 curproxy->check_req = (char *)malloc(reqlen);
5374 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
5375 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005376 } else { /* more arguments : METHOD URI [HTTP_VER] */
5377 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
5378 if (*args[4])
5379 reqlen += strlen(args[4]);
5380 else
5381 reqlen += strlen("HTTP/1.0");
5382
5383 curproxy->check_req = (char *)malloc(reqlen);
5384 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
5385 "%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 +01005386 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005387 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005388 else if (!strcmp(args[1], "persist")) {
5389 /* persist on using the server specified by the cookie, even when it's down */
5390 curproxy->options |= PR_O_PERSIST;
5391 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005392 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005393 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005394 return -1;
5395 }
5396 return 0;
5397 }
5398 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
5399 /* enable reconnections to dispatch */
5400 curproxy->options |= PR_O_REDISP;
5401 }
willy tarreaua1598082005-12-17 13:08:06 +01005402#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01005403 else if (!strcmp(args[0], "transparent")) {
5404 /* enable transparent proxy connections */
5405 curproxy->options |= PR_O_TRANSP;
5406 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005407#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01005408 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
5409 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005410 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005411 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005412 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005413 curproxy->maxconn = atol(args[1]);
5414 }
5415 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
5416 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005417 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005418 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005419 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005420 curproxy->grace = atol(args[1]);
5421 }
5422 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01005423 if (curproxy == &defproxy) {
5424 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5425 return -1;
5426 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005427 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005428 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005429 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005430 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005431 curproxy->dispatch_addr = *str2sa(args[1]);
5432 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005433 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01005434 if (*(args[1])) {
5435 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005436 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01005437 }
5438 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005439 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005440 return -1;
5441 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005442 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005443 else /* if no option is set, use round-robin by default */
5444 curproxy->options |= PR_O_BALANCE_RR;
5445 }
5446 else if (!strcmp(args[0], "server")) { /* server address */
5447 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005448 char *rport;
5449 char *raddr;
5450 short realport;
5451 int do_check;
5452
5453 if (curproxy == &defproxy) {
5454 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5455 return -1;
5456 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005457
willy tarreaua41a8b42005-12-17 14:02:24 +01005458 if (!*args[2]) {
5459 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005460 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005461 return -1;
5462 }
5463 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
5464 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
5465 return -1;
5466 }
willy tarreau0174f312005-12-18 01:02:42 +01005467
5468 if (curproxy->srv == NULL)
5469 curproxy->srv = newsrv;
5470 else
5471 curproxy->cursrv->next = newsrv;
5472 curproxy->cursrv = newsrv;
5473
5474 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01005475 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01005476
5477 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01005478 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01005479 newsrv->id = strdup(args[1]);
5480
5481 /* several ways to check the port component :
5482 * - IP => port=+0, relative
5483 * - IP: => port=+0, relative
5484 * - IP:N => port=N, absolute
5485 * - IP:+N => port=+N, relative
5486 * - IP:-N => port=-N, relative
5487 */
5488 raddr = strdup(args[2]);
5489 rport = strchr(raddr, ':');
5490 if (rport) {
5491 *rport++ = 0;
5492 realport = atol(rport);
5493 if (!isdigit((int)*rport))
5494 newsrv->state |= SRV_MAPPORTS;
5495 } else {
5496 realport = 0;
5497 newsrv->state |= SRV_MAPPORTS;
5498 }
5499
5500 newsrv->addr = *str2sa(raddr);
5501 newsrv->addr.sin_port = htons(realport);
5502 free(raddr);
5503
willy tarreau9fe663a2005-12-17 13:02:59 +01005504 newsrv->curfd = -1; /* no health-check in progress */
5505 newsrv->inter = DEF_CHKINTR;
5506 newsrv->rise = DEF_RISETIME;
5507 newsrv->fall = DEF_FALLTIME;
5508 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
5509 cur_arg = 3;
5510 while (*args[cur_arg]) {
5511 if (!strcmp(args[cur_arg], "cookie")) {
5512 newsrv->cookie = strdup(args[cur_arg + 1]);
5513 newsrv->cklen = strlen(args[cur_arg + 1]);
5514 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01005515 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005516 else if (!strcmp(args[cur_arg], "rise")) {
5517 newsrv->rise = atol(args[cur_arg + 1]);
5518 newsrv->health = newsrv->rise;
5519 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01005520 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005521 else if (!strcmp(args[cur_arg], "fall")) {
5522 newsrv->fall = atol(args[cur_arg + 1]);
5523 cur_arg += 2;
5524 }
5525 else if (!strcmp(args[cur_arg], "inter")) {
5526 newsrv->inter = atol(args[cur_arg + 1]);
5527 cur_arg += 2;
5528 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005529 else if (!strcmp(args[cur_arg], "port")) {
5530 newsrv->check_port = atol(args[cur_arg + 1]);
5531 cur_arg += 2;
5532 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005533 else if (!strcmp(args[cur_arg], "backup")) {
5534 newsrv->state |= SRV_BACKUP;
5535 cur_arg ++;
5536 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005537 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005538 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005539 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005540 }
willy tarreau0174f312005-12-18 01:02:42 +01005541 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
5542 if (!*args[cur_arg + 1]) {
5543 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
5544 file, linenum, "source");
5545 return -1;
5546 }
5547 newsrv->state |= SRV_BIND_SRC;
5548 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
5549 cur_arg += 2;
5550 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005551 else {
willy tarreau0174f312005-12-18 01:02:42 +01005552 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 +01005553 file, linenum, newsrv->id);
5554 return -1;
5555 }
5556 }
5557
5558 if (do_check) {
5559 struct task *t;
5560
5561 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
5562 newsrv->check_port = realport; /* by default */
5563 if (!newsrv->check_port) {
5564 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 +01005565 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005566 return -1;
5567 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005568
5569 if ((t = pool_alloc(task)) == NULL) {
5570 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
5571 return -1;
5572 }
5573
5574 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
5575 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
5576 t->state = TASK_IDLE;
5577 t->process = process_chk;
5578 t->context = newsrv;
5579
5580 if (curproxy->state != PR_STDISABLED) {
5581 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
5582 task_queue(t);
5583 task_wakeup(&rq, t);
5584 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005585 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005586
willy tarreau9fe663a2005-12-17 13:02:59 +01005587 curproxy->nbservers++;
5588 }
5589 else if (!strcmp(args[0], "log")) { /* syslog server address */
5590 struct sockaddr_in *sa;
5591 int facility;
5592
5593 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
5594 curproxy->logfac1 = global.logfac1;
5595 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005596 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005597 curproxy->logfac2 = global.logfac2;
5598 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01005599 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01005600 }
5601 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01005602 int level;
5603
willy tarreau0f7af912005-12-17 12:21:26 +01005604 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5605 if (!strcmp(log_facilities[facility], args[2]))
5606 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01005607
willy tarreau0f7af912005-12-17 12:21:26 +01005608 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005609 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01005610 exit(1);
5611 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005612
willy tarreau8337c6b2005-12-17 13:41:01 +01005613 level = 7; /* max syslog level = debug */
5614 if (*(args[3])) {
5615 while (level >= 0 && strcmp(log_levels[level], args[3]))
5616 level--;
5617 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005618 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005619 exit(1);
5620 }
5621 }
5622
willy tarreau0f7af912005-12-17 12:21:26 +01005623 sa = str2sa(args[1]);
5624 if (!sa->sin_port)
5625 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01005626
willy tarreau0f7af912005-12-17 12:21:26 +01005627 if (curproxy->logfac1 == -1) {
5628 curproxy->logsrv1 = *sa;
5629 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005630 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005631 }
5632 else if (curproxy->logfac2 == -1) {
5633 curproxy->logsrv2 = *sa;
5634 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005635 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005636 }
5637 else {
5638 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005639 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005640 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005641 }
5642 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005643 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005644 file, linenum);
5645 return -1;
5646 }
5647 }
willy tarreaua1598082005-12-17 13:08:06 +01005648 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01005649 if (!*args[1]) {
5650 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005651 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01005652 return -1;
5653 }
5654
5655 curproxy->source_addr = *str2sa(args[1]);
5656 curproxy->options |= PR_O_BIND_SRC;
5657 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005658 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
5659 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005660 if (curproxy == &defproxy) {
5661 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5662 return -1;
5663 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005664
5665 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005666 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5667 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005668 return -1;
5669 }
5670
5671 preg = calloc(1, sizeof(regex_t));
5672 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005673 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005674 return -1;
5675 }
5676
5677 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5678 }
5679 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
5680 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005681 if (curproxy == &defproxy) {
5682 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5683 return -1;
5684 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005685
5686 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005687 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005688 return -1;
5689 }
5690
5691 preg = calloc(1, sizeof(regex_t));
5692 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005693 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005694 return -1;
5695 }
5696
5697 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5698 }
5699 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
5700 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005701 if (curproxy == &defproxy) {
5702 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5703 return -1;
5704 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005705
5706 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005707 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005708 return -1;
5709 }
5710
5711 preg = calloc(1, sizeof(regex_t));
5712 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005713 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005714 return -1;
5715 }
5716
5717 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5718 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005719 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
5720 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005721 if (curproxy == &defproxy) {
5722 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5723 return -1;
5724 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005725
5726 if (*(args[1]) == 0) {
5727 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5728 return -1;
5729 }
5730
5731 preg = calloc(1, sizeof(regex_t));
5732 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5733 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5734 return -1;
5735 }
5736
5737 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5738 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005739 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
5740 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005741 if (curproxy == &defproxy) {
5742 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5743 return -1;
5744 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005745
5746 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005747 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005748 return -1;
5749 }
5750
5751 preg = calloc(1, sizeof(regex_t));
5752 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005753 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005754 return -1;
5755 }
5756
5757 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5758 }
5759 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
5760 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005761 if (curproxy == &defproxy) {
5762 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5763 return -1;
5764 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005765
5766 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005767 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5768 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005769 return -1;
5770 }
5771
5772 preg = calloc(1, sizeof(regex_t));
5773 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005774 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005775 return -1;
5776 }
5777
5778 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5779 }
5780 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
5781 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005782 if (curproxy == &defproxy) {
5783 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5784 return -1;
5785 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005786
5787 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005788 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005789 return -1;
5790 }
5791
5792 preg = calloc(1, sizeof(regex_t));
5793 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005794 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005795 return -1;
5796 }
5797
5798 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5799 }
5800 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
5801 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005802 if (curproxy == &defproxy) {
5803 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5804 return -1;
5805 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005806
5807 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005808 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005809 return -1;
5810 }
5811
5812 preg = calloc(1, sizeof(regex_t));
5813 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005814 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005815 return -1;
5816 }
5817
5818 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5819 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005820 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
5821 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005822 if (curproxy == &defproxy) {
5823 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5824 return -1;
5825 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005826
5827 if (*(args[1]) == 0) {
5828 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5829 return -1;
5830 }
5831
5832 preg = calloc(1, sizeof(regex_t));
5833 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5834 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5835 return -1;
5836 }
5837
5838 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5839 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005840 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
5841 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005842 if (curproxy == &defproxy) {
5843 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5844 return -1;
5845 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005846
5847 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005848 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005849 return -1;
5850 }
5851
5852 preg = calloc(1, sizeof(regex_t));
5853 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005854 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005855 return -1;
5856 }
5857
5858 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5859 }
5860 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005861 if (curproxy == &defproxy) {
5862 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5863 return -1;
5864 }
5865
willy tarreau9fe663a2005-12-17 13:02:59 +01005866 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005867 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005868 return 0;
5869 }
5870
5871 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005872 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005873 return -1;
5874 }
5875
willy tarreau4302f492005-12-18 01:00:37 +01005876 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
5877 }
5878 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
5879 regex_t *preg;
5880
5881 if (*(args[1]) == 0 || *(args[2]) == 0) {
5882 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5883 file, linenum, args[0]);
5884 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005885 }
willy tarreau4302f492005-12-18 01:00:37 +01005886
5887 preg = calloc(1, sizeof(regex_t));
5888 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5889 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5890 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005891 }
willy tarreau4302f492005-12-18 01:00:37 +01005892
5893 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5894 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005895 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
5896 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005897 if (curproxy == &defproxy) {
5898 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5899 return -1;
5900 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005901
5902 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005903 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005904 return -1;
5905 }
willy tarreaue39cd132005-12-17 13:00:18 +01005906
willy tarreau9fe663a2005-12-17 13:02:59 +01005907 preg = calloc(1, sizeof(regex_t));
5908 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005909 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005910 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005911 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005912
5913 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5914 }
willy tarreau982249e2005-12-18 00:57:06 +01005915 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
5916 regex_t *preg;
5917 if (curproxy == &defproxy) {
5918 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5919 return -1;
5920 }
5921
5922 if (*(args[1]) == 0) {
5923 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
5924 return -1;
5925 }
5926
5927 preg = calloc(1, sizeof(regex_t));
5928 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5929 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5930 return -1;
5931 }
5932
5933 chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
5934 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005935 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01005936 regex_t *preg;
5937 if (curproxy == &defproxy) {
5938 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5939 return -1;
5940 }
willy tarreaue39cd132005-12-17 13:00:18 +01005941
willy tarreaua41a8b42005-12-17 14:02:24 +01005942 if (*(args[1]) == 0 || *(args[2]) == 0) {
5943 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5944 file, linenum, args[0]);
5945 return -1;
5946 }
willy tarreaue39cd132005-12-17 13:00:18 +01005947
willy tarreaua41a8b42005-12-17 14:02:24 +01005948 preg = calloc(1, sizeof(regex_t));
5949 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5950 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5951 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005952 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005953
5954 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5955 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005956 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
5957 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005958 if (curproxy == &defproxy) {
5959 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5960 return -1;
5961 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005962
5963 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005964 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005965 return -1;
5966 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005967
willy tarreau9fe663a2005-12-17 13:02:59 +01005968 preg = calloc(1, sizeof(regex_t));
5969 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005970 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005971 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005973
5974 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5975 }
willy tarreau982249e2005-12-18 00:57:06 +01005976 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
5977 regex_t *preg;
5978 if (curproxy == &defproxy) {
5979 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5980 return -1;
5981 }
5982
5983 if (*(args[1]) == 0) {
5984 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
5985 return -1;
5986 }
5987
5988 preg = calloc(1, sizeof(regex_t));
5989 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5990 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5991 return -1;
5992 }
5993
5994 chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
5995 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005996 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005997 if (curproxy == &defproxy) {
5998 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5999 return -1;
6000 }
6001
willy tarreau9fe663a2005-12-17 13:02:59 +01006002 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006003 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006004 return 0;
6005 }
6006
6007 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006008 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006009 return -1;
6010 }
6011
6012 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
6013 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006014 else if (!strcmp(args[0], "errorloc")) { /* error location */
6015 int errnum;
6016 char *err;
6017
willy tarreaueedaa9f2005-12-17 14:08:03 +01006018 // if (curproxy == &defproxy) {
6019 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6020 // return -1;
6021 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006022
willy tarreau8337c6b2005-12-17 13:41:01 +01006023 if (*(args[2]) == 0) {
6024 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
6025 return -1;
6026 }
6027
6028 errnum = atol(args[1]);
6029 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
6030 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
6031
6032 if (errnum == 400) {
6033 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006034 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006035 free(curproxy->errmsg.msg400);
6036 }
6037 curproxy->errmsg.msg400 = err;
6038 curproxy->errmsg.len400 = strlen(err);
6039 }
6040 else if (errnum == 403) {
6041 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006042 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006043 free(curproxy->errmsg.msg403);
6044 }
6045 curproxy->errmsg.msg403 = err;
6046 curproxy->errmsg.len403 = strlen(err);
6047 }
6048 else if (errnum == 408) {
6049 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006050 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006051 free(curproxy->errmsg.msg408);
6052 }
6053 curproxy->errmsg.msg408 = err;
6054 curproxy->errmsg.len408 = strlen(err);
6055 }
6056 else if (errnum == 500) {
6057 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006058 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006059 free(curproxy->errmsg.msg500);
6060 }
6061 curproxy->errmsg.msg500 = err;
6062 curproxy->errmsg.len500 = strlen(err);
6063 }
6064 else if (errnum == 502) {
6065 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006066 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006067 free(curproxy->errmsg.msg502);
6068 }
6069 curproxy->errmsg.msg502 = err;
6070 curproxy->errmsg.len502 = strlen(err);
6071 }
6072 else if (errnum == 503) {
6073 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006074 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006075 free(curproxy->errmsg.msg503);
6076 }
6077 curproxy->errmsg.msg503 = err;
6078 curproxy->errmsg.len503 = strlen(err);
6079 }
6080 else if (errnum == 504) {
6081 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006082 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006083 free(curproxy->errmsg.msg504);
6084 }
6085 curproxy->errmsg.msg504 = err;
6086 curproxy->errmsg.len504 = strlen(err);
6087 }
6088 else {
6089 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
6090 free(err);
6091 }
6092 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006093 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006094 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01006095 return -1;
6096 }
6097 return 0;
6098}
willy tarreaue39cd132005-12-17 13:00:18 +01006099
willy tarreau5cbea6f2005-12-17 12:48:26 +01006100
willy tarreau9fe663a2005-12-17 13:02:59 +01006101/*
6102 * This function reads and parses the configuration file given in the argument.
6103 * returns 0 if OK, -1 if error.
6104 */
6105int readcfgfile(char *file) {
6106 char thisline[256];
6107 char *line;
6108 FILE *f;
6109 int linenum = 0;
6110 char *end;
6111 char *args[MAX_LINE_ARGS];
6112 int arg;
6113 int cfgerr = 0;
6114 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01006115
willy tarreau9fe663a2005-12-17 13:02:59 +01006116 struct proxy *curproxy = NULL;
6117 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006118
willy tarreau9fe663a2005-12-17 13:02:59 +01006119 if ((f=fopen(file,"r")) == NULL)
6120 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006121
willy tarreaueedaa9f2005-12-17 14:08:03 +01006122 init_default_instance();
6123
willy tarreau9fe663a2005-12-17 13:02:59 +01006124 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
6125 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006126
willy tarreau9fe663a2005-12-17 13:02:59 +01006127 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006128
willy tarreau9fe663a2005-12-17 13:02:59 +01006129 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01006130 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01006131 line++;
6132
6133 arg = 0;
6134 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01006135
willy tarreau9fe663a2005-12-17 13:02:59 +01006136 while (*line && arg < MAX_LINE_ARGS) {
6137 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
6138 * C equivalent value. Other combinations left unchanged (eg: \1).
6139 */
6140 if (*line == '\\') {
6141 int skip = 0;
6142 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
6143 *line = line[1];
6144 skip = 1;
6145 }
6146 else if (line[1] == 'r') {
6147 *line = '\r';
6148 skip = 1;
6149 }
6150 else if (line[1] == 'n') {
6151 *line = '\n';
6152 skip = 1;
6153 }
6154 else if (line[1] == 't') {
6155 *line = '\t';
6156 skip = 1;
6157 }
6158 else if (line[1] == 'x' && (line + 3 < end )) {
6159 unsigned char hex1, hex2;
6160 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
6161 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
6162 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
6163 *line = (hex1<<4) + hex2;
6164 skip = 3;
6165 }
6166 if (skip) {
6167 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
6168 end -= skip;
6169 }
6170 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006171 }
willy tarreaua1598082005-12-17 13:08:06 +01006172 else if (*line == '#' || *line == '\n' || *line == '\r') {
6173 /* end of string, end of loop */
6174 *line = 0;
6175 break;
6176 }
willy tarreauc29948c2005-12-17 13:10:27 +01006177 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006178 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01006179 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01006180 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01006181 line++;
6182 args[++arg] = line;
6183 }
6184 else {
6185 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006186 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006187 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006188
willy tarreau9fe663a2005-12-17 13:02:59 +01006189 /* empty line */
6190 if (!**args)
6191 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01006192
willy tarreau9fe663a2005-12-17 13:02:59 +01006193 /* zero out remaining args */
6194 while (++arg < MAX_LINE_ARGS) {
6195 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006196 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006197
willy tarreaua41a8b42005-12-17 14:02:24 +01006198 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01006199 confsect = CFG_LISTEN;
6200 else if (!strcmp(args[0], "global")) /* global config */
6201 confsect = CFG_GLOBAL;
6202 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006203
willy tarreau9fe663a2005-12-17 13:02:59 +01006204 switch (confsect) {
6205 case CFG_LISTEN:
6206 if (cfg_parse_listen(file, linenum, args) < 0)
6207 return -1;
6208 break;
6209 case CFG_GLOBAL:
6210 if (cfg_parse_global(file, linenum, args) < 0)
6211 return -1;
6212 break;
6213 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01006214 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006215 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006216 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006217
6218
willy tarreau0f7af912005-12-17 12:21:26 +01006219 }
6220 fclose(f);
6221
6222 /*
6223 * Now, check for the integrity of all that we have collected.
6224 */
6225
6226 if ((curproxy = proxy) == NULL) {
6227 Alert("parsing %s : no <listen> line. Nothing to do !\n",
6228 file);
6229 return -1;
6230 }
6231
6232 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01006233 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01006234 if (curproxy->state == PR_STDISABLED) {
6235 curproxy = curproxy->next;
6236 continue;
6237 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006238 if ((curproxy->mode != PR_MODE_HEALTH) &&
6239 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01006240 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006241 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
6242 file, curproxy->id);
6243 cfgerr++;
6244 }
6245 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
6246 if (curproxy->options & PR_O_TRANSP) {
6247 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
6248 file, curproxy->id);
6249 cfgerr++;
6250 }
6251 else if (curproxy->srv == NULL) {
6252 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
6253 file, curproxy->id);
6254 cfgerr++;
6255 }
willy tarreaua1598082005-12-17 13:08:06 +01006256 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006257 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
6258 file, curproxy->id);
6259 }
6260 }
6261 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01006262 if (curproxy->cookie_name != NULL) {
6263 Warning("parsing %s : cookie will be ignored for listener %s.\n",
6264 file, curproxy->id);
6265 }
6266 if ((newsrv = curproxy->srv) != NULL) {
6267 Warning("parsing %s : servers will be ignored for listener %s.\n",
6268 file, curproxy->id);
6269 }
willy tarreaue39cd132005-12-17 13:00:18 +01006270 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01006271 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
6272 file, curproxy->id);
6273 }
willy tarreaue39cd132005-12-17 13:00:18 +01006274 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01006275 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
6276 file, curproxy->id);
6277 }
6278 }
6279 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
6280 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
6281 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
6282 file, curproxy->id);
6283 cfgerr++;
6284 }
6285 else {
6286 while (newsrv != NULL) {
6287 /* nothing to check for now */
6288 newsrv = newsrv->next;
6289 }
6290 }
6291 }
willy tarreau25c4ea52005-12-18 00:49:49 +01006292
6293 if (curproxy->options & PR_O_LOGASAP)
6294 curproxy->to_log &= ~LW_BYTES;
6295
willy tarreau8337c6b2005-12-17 13:41:01 +01006296 if (curproxy->errmsg.msg400 == NULL) {
6297 curproxy->errmsg.msg400 = (char *)HTTP_400;
6298 curproxy->errmsg.len400 = strlen(HTTP_400);
6299 }
6300 if (curproxy->errmsg.msg403 == NULL) {
6301 curproxy->errmsg.msg403 = (char *)HTTP_403;
6302 curproxy->errmsg.len403 = strlen(HTTP_403);
6303 }
6304 if (curproxy->errmsg.msg408 == NULL) {
6305 curproxy->errmsg.msg408 = (char *)HTTP_408;
6306 curproxy->errmsg.len408 = strlen(HTTP_408);
6307 }
6308 if (curproxy->errmsg.msg500 == NULL) {
6309 curproxy->errmsg.msg500 = (char *)HTTP_500;
6310 curproxy->errmsg.len500 = strlen(HTTP_500);
6311 }
6312 if (curproxy->errmsg.msg502 == NULL) {
6313 curproxy->errmsg.msg502 = (char *)HTTP_502;
6314 curproxy->errmsg.len502 = strlen(HTTP_502);
6315 }
6316 if (curproxy->errmsg.msg503 == NULL) {
6317 curproxy->errmsg.msg503 = (char *)HTTP_503;
6318 curproxy->errmsg.len503 = strlen(HTTP_503);
6319 }
6320 if (curproxy->errmsg.msg504 == NULL) {
6321 curproxy->errmsg.msg504 = (char *)HTTP_504;
6322 curproxy->errmsg.len504 = strlen(HTTP_504);
6323 }
willy tarreau0f7af912005-12-17 12:21:26 +01006324 curproxy = curproxy->next;
6325 }
6326 if (cfgerr > 0) {
6327 Alert("Errors found in configuration file, aborting.\n");
6328 return -1;
6329 }
6330 else
6331 return 0;
6332}
6333
6334
6335/*
6336 * This function initializes all the necessary variables. It only returns
6337 * if everything is OK. If something fails, it exits.
6338 */
6339void init(int argc, char **argv) {
6340 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01006341 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01006342 char *old_argv = *argv;
6343 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006344 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006345 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01006346
6347 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01006348 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006349 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01006350 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01006351 exit(1);
6352 }
6353
willy tarreau4302f492005-12-18 01:00:37 +01006354 /* initialize the log header encoding map : '{|}"#' should be encoded with
6355 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
6356 * URL encoding only requires '"', '#' to be encoded as well as non-
6357 * printable characters above.
6358 */
6359 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
6360 memset(url_encode_map, 0, sizeof(url_encode_map));
6361 for (i = 0; i < 32; i++) {
6362 FD_SET(i, hdr_encode_map);
6363 FD_SET(i, url_encode_map);
6364 }
6365 for (i = 127; i < 256; i++) {
6366 FD_SET(i, hdr_encode_map);
6367 FD_SET(i, url_encode_map);
6368 }
6369
6370 tmp = "\"#{|}";
6371 while (*tmp) {
6372 FD_SET(*tmp, hdr_encode_map);
6373 tmp++;
6374 }
6375
6376 tmp = "\"#";
6377 while (*tmp) {
6378 FD_SET(*tmp, url_encode_map);
6379 tmp++;
6380 }
6381
willy tarreau0f7af912005-12-17 12:21:26 +01006382 pid = getpid();
6383 progname = *argv;
6384 while ((tmp = strchr(progname, '/')) != NULL)
6385 progname = tmp + 1;
6386
6387 argc--; argv++;
6388 while (argc > 0) {
6389 char *flag;
6390
6391 if (**argv == '-') {
6392 flag = *argv+1;
6393
6394 /* 1 arg */
6395 if (*flag == 'v') {
6396 display_version();
6397 exit(0);
6398 }
willy tarreau982249e2005-12-18 00:57:06 +01006399 else if (*flag == 'V')
6400 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01006401 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01006402 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01006403 else if (*flag == 'c')
6404 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01006405 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01006406 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006407 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01006408 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01006409#if STATTIME > 0
6410 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01006411 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01006412 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01006413 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01006414#endif
6415 else { /* >=2 args */
6416 argv++; argc--;
6417 if (argc == 0)
6418 usage(old_argv);
6419
6420 switch (*flag) {
6421 case 'n' : cfg_maxconn = atol(*argv); break;
6422 case 'N' : cfg_maxpconn = atol(*argv); break;
6423 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006424 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01006425 default: usage(old_argv);
6426 }
6427 }
6428 }
6429 else
6430 usage(old_argv);
6431 argv++; argc--;
6432 }
6433
willy tarreau982249e2005-12-18 00:57:06 +01006434 global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01006435
willy tarreau0f7af912005-12-17 12:21:26 +01006436 if (!cfg_cfgfile)
6437 usage(old_argv);
6438
6439 gethostname(hostname, MAX_HOSTNAME_LEN);
6440
6441 if (readcfgfile(cfg_cfgfile) < 0) {
6442 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
6443 exit(1);
6444 }
6445
willy tarreau982249e2005-12-18 00:57:06 +01006446 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01006447 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
6448 exit(0);
6449 }
6450
willy tarreau9fe663a2005-12-17 13:02:59 +01006451 if (cfg_maxconn > 0)
6452 global.maxconn = cfg_maxconn;
6453
willy tarreaufe2c5c12005-12-17 14:14:34 +01006454 if (cfg_pidfile) {
6455 if (global.pidfile)
6456 free(global.pidfile);
6457 global.pidfile = strdup(cfg_pidfile);
6458 }
6459
willy tarreau9fe663a2005-12-17 13:02:59 +01006460 if (global.maxconn == 0)
6461 global.maxconn = DEFAULT_MAXCONN;
6462
6463 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
6464
6465 if (arg_mode & MODE_DEBUG) {
6466 /* command line debug mode inhibits configuration mode */
6467 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
6468 }
willy tarreau982249e2005-12-18 00:57:06 +01006469 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
6470 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01006471
6472 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
6473 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
6474 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
6475 }
6476
6477 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
6478 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
6479 global.nbproc = 1;
6480 }
6481
6482 if (global.nbproc < 1)
6483 global.nbproc = 1;
6484
willy tarreau0f7af912005-12-17 12:21:26 +01006485 ReadEvent = (fd_set *)calloc(1,
6486 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006487 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006488 WriteEvent = (fd_set *)calloc(1,
6489 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006490 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006491 StaticReadEvent = (fd_set *)calloc(1,
6492 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006493 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006494 StaticWriteEvent = (fd_set *)calloc(1,
6495 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006496 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006497
6498 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01006499 sizeof(struct fdtab) * (global.maxsock));
6500 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01006501 fdtab[i].state = FD_STCLOSE;
6502 }
6503}
6504
6505/*
6506 * this function starts all the proxies. It returns 0 if OK, -1 if not.
6507 */
6508int start_proxies() {
6509 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006510 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01006511 int fd;
6512
6513 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01006514 if (curproxy->state == PR_STDISABLED)
6515 continue;
6516
willy tarreaua41a8b42005-12-17 14:02:24 +01006517 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
6518 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01006519 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006520 Alert("cannot create listening socket for proxy %s. Aborting.\n",
6521 curproxy->id);
6522 return -1;
6523 }
willy tarreau0f7af912005-12-17 12:21:26 +01006524
willy tarreaua41a8b42005-12-17 14:02:24 +01006525 if (fd >= global.maxsock) {
6526 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
6527 curproxy->id);
6528 close(fd);
6529 return -1;
6530 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006531
willy tarreaua41a8b42005-12-17 14:02:24 +01006532 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
6533 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
6534 (char *) &one, sizeof(one)) == -1)) {
6535 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
6536 curproxy->id);
6537 close(fd);
6538 return -1;
6539 }
willy tarreau0f7af912005-12-17 12:21:26 +01006540
willy tarreaua41a8b42005-12-17 14:02:24 +01006541 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
6542 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
6543 curproxy->id);
6544 }
willy tarreau0f7af912005-12-17 12:21:26 +01006545
willy tarreaua41a8b42005-12-17 14:02:24 +01006546 if (bind(fd,
6547 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01006548 listener->addr.ss_family == AF_INET6 ?
6549 sizeof(struct sockaddr_in6) :
6550 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006551 Alert("cannot bind socket for proxy %s. Aborting.\n",
6552 curproxy->id);
6553 close(fd);
6554 return -1;
6555 }
willy tarreau0f7af912005-12-17 12:21:26 +01006556
willy tarreaua41a8b42005-12-17 14:02:24 +01006557 if (listen(fd, curproxy->maxconn) == -1) {
6558 Alert("cannot listen to socket for proxy %s. Aborting.\n",
6559 curproxy->id);
6560 close(fd);
6561 return -1;
6562 }
willy tarreau0f7af912005-12-17 12:21:26 +01006563
willy tarreaua41a8b42005-12-17 14:02:24 +01006564 /* the function for the accept() event */
6565 fdtab[fd].read = &event_accept;
6566 fdtab[fd].write = NULL; /* never called */
6567 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
6568 curproxy->state = PR_STRUN;
6569 fdtab[fd].state = FD_STLISTEN;
6570 FD_SET(fd, StaticReadEvent);
6571 fd_insert(fd);
6572 listeners++;
6573 }
willy tarreaua1598082005-12-17 13:08:06 +01006574 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006575 }
6576 return 0;
6577}
6578
6579
6580int main(int argc, char **argv) {
willy tarreaufe2c5c12005-12-17 14:14:34 +01006581 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01006582 init(argc, argv);
6583
willy tarreau9fe663a2005-12-17 13:02:59 +01006584 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01006585 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006586 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01006587 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01006588 }
6589
6590 signal(SIGQUIT, dump);
6591 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01006592 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01006593
6594 /* on very high loads, a sigpipe sometimes happen just between the
6595 * getsockopt() which tells "it's OK to write", and the following write :-(
6596 */
willy tarreau3242e862005-12-17 12:27:53 +01006597#ifndef MSG_NOSIGNAL
6598 signal(SIGPIPE, SIG_IGN);
6599#endif
willy tarreau0f7af912005-12-17 12:21:26 +01006600
6601 if (start_proxies() < 0)
6602 exit(1);
6603
willy tarreaufe2c5c12005-12-17 14:14:34 +01006604 /* open log & pid files before the chroot */
6605 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
6606 int pidfd;
6607 unlink(global.pidfile);
6608 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
6609 if (pidfd < 0) {
6610 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
6611 exit(1);
6612 }
6613 pidfile = fdopen(pidfd, "w");
6614 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006615
6616 /* chroot if needed */
6617 if (global.chroot != NULL) {
6618 if (chroot(global.chroot) == -1) {
6619 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
6620 exit(1);
6621 }
6622 chdir("/");
6623 }
6624
6625 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01006626 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006627 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
6628 exit(1);
6629 }
6630
willy tarreau036e1ce2005-12-17 13:46:33 +01006631 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006632 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
6633 exit(1);
6634 }
6635
6636 if (global.mode & MODE_DAEMON) {
6637 int ret = 0;
6638 int proc;
6639
6640 /* the father launches the required number of processes */
6641 for (proc = 0; proc < global.nbproc; proc++) {
6642 ret = fork();
6643 if (ret < 0) {
6644 Alert("[%s.main()] Cannot fork.\n", argv[0]);
6645 exit(1); /* there has been an error */
6646 }
6647 else if (ret == 0) /* child breaks here */
6648 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006649 if (pidfile != NULL) {
6650 fprintf(pidfile, "%d\n", ret);
6651 fflush(pidfile);
6652 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006653 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006654 /* close the pidfile both in children and father */
6655 if (pidfile != NULL)
6656 fclose(pidfile);
6657 free(global.pidfile);
6658
willy tarreau9fe663a2005-12-17 13:02:59 +01006659 if (proc == global.nbproc)
6660 exit(0); /* parent must leave */
6661
willy tarreau750a4722005-12-17 13:21:24 +01006662 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
6663 * that we can detach from the TTY. We MUST NOT do it in other cases since
6664 * it would have already be done, and 0-2 would have been affected to listening
6665 * sockets
6666 */
6667 if (!(global.mode & MODE_QUIET)) {
6668 /* detach from the tty */
6669 fclose(stdin); fclose(stdout); fclose(stderr);
6670 close(0); close(1); close(2); /* close all fd's */
6671 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
6672 }
willy tarreaua1598082005-12-17 13:08:06 +01006673 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01006674 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01006675 }
6676
willy tarreau0f7af912005-12-17 12:21:26 +01006677 select_loop();
6678
6679 exit(0);
6680}