blob: 426786e33dc22e3e72830d18daf6fb222bd013b6 [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 tarreaudd07e972005-12-18 00:48:48 +01003 * 2000-2004 - 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 tarreau4302f492005-12-18 01:00:37 +010060#define HAPROXY_VERSION "1.2.2"
61#define HAPROXY_DATE "2004/10/18"
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 tarreau535ae7a2005-12-17 12:58:00 +010076#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +010077
78// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +010079#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +010080#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +010081#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +010082
willy tarreau5cbea6f2005-12-17 12:48:26 +010083// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +010084#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +010085
willy tarreaue39cd132005-12-17 13:00:18 +010086// max # of added headers per request
87#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +010088
89// max # of matches per regexp
90#define MAX_MATCH 10
91
willy tarreau5cbea6f2005-12-17 12:48:26 +010092/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +010093#define COOKIENAME_LEN 16
94#define SERVERID_LEN 16
95#define CONN_RETRIES 3
96
willy tarreau5cbea6f2005-12-17 12:48:26 +010097#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +010098#define DEF_CHKINTR 2000
99#define DEF_FALLTIME 3
100#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100101#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100102
willy tarreau9fe663a2005-12-17 13:02:59 +0100103/* default connections limit */
104#define DEFAULT_MAXCONN 2000
105
willy tarreau0f7af912005-12-17 12:21:26 +0100106/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
107#define INTBITS 5
108
109/* show stats this every millisecond, 0 to disable */
110#ifndef STATTIME
111#define STATTIME 2000
112#endif
113
willy tarreau5cbea6f2005-12-17 12:48:26 +0100114/* this reduces the number of calls to select() by choosing appropriate
115 * sheduler precision in milliseconds. It should be near the minimum
116 * time that is needed by select() to collect all events. All timeouts
117 * are rounded up by adding this value prior to pass it to select().
118 */
119#define SCHEDULER_RESOLUTION 9
120
willy tarreau0f7af912005-12-17 12:21:26 +0100121#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
122#define SETNOW(a) (*a=now)
123
willy tarreau9da061b2005-12-17 12:29:56 +0100124/****** string-specific macros and functions ******/
125/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
126#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
127
128/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
129#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
130
willy tarreau9da061b2005-12-17 12:29:56 +0100131/*
132 * copies at most <size-1> chars from <src> to <dst>. Last char is always
133 * set to 0, unless <size> is 0. The number of chars copied is returned
134 * (excluding the terminating zero).
135 * This code has been optimized for size and speed : on x86, it's 45 bytes
136 * long, uses only registers, and consumes only 4 cycles per char.
137 */
willy tarreau750a4722005-12-17 13:21:24 +0100138int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100139 char *orig = dst;
140 if (size) {
141 while (--size && (*dst = *src)) {
142 src++; dst++;
143 }
144 *dst = 0;
145 }
146 return dst - orig;
147}
willy tarreau9da061b2005-12-17 12:29:56 +0100148
willy tarreau4302f492005-12-18 01:00:37 +0100149/*
150 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
151 * dynamically allocated. In the first case, <__pool> is updated to point to
152 * the next element in the list.
153 */
154#define pool_alloc_from(__pool, __len) ({ \
155 void *__p; \
156 if ((__p = (__pool)) == NULL) \
157 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
158 else { \
159 __pool = *(void **)(__pool); \
160 } \
161 __p; \
162})
163
164/*
165 * Puts a memory area back to the corresponding pool.
166 * Items are chained directly through a pointer that
167 * is written in the beginning of the memory area, so
168 * there's no need for any carrier cell. This implies
169 * that each memory area is at least as big as one
170 * pointer.
171 */
172#define pool_free_to(__pool, __ptr) ({ \
173 *(void **)(__ptr) = (void *)(__pool); \
174 __pool = (void *)(__ptr); \
175})
176
177
willy tarreau0f7af912005-12-17 12:21:26 +0100178#define MEM_OPTIM
179#ifdef MEM_OPTIM
180/*
181 * Returns a pointer to type <type> taken from the
182 * pool <pool_type> or dynamically allocated. In the
183 * first case, <pool_type> is updated to point to the
184 * next element in the list.
185 */
186#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100187 void *__p; \
188 if ((__p = pool_##type) == NULL) \
189 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100190 else { \
191 pool_##type = *(void **)pool_##type; \
192 } \
willy tarreau4302f492005-12-18 01:00:37 +0100193 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100194})
195
196/*
197 * Puts a memory area back to the corresponding pool.
198 * Items are chained directly through a pointer that
199 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100200 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100201 * that each memory area is at least as big as one
202 * pointer.
203 */
204#define pool_free(type, ptr) ({ \
205 *(void **)ptr = (void *)pool_##type; \
206 pool_##type = (void *)ptr; \
207})
208
209#else
210#define pool_alloc(type) (calloc(1,sizeof_##type));
211#define pool_free(type, ptr) (free(ptr));
212#endif /* MEM_OPTIM */
213
willy tarreau5cbea6f2005-12-17 12:48:26 +0100214#define sizeof_task sizeof(struct task)
215#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100216#define sizeof_buffer sizeof(struct buffer)
217#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100218#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100219#define sizeof_capture CAPTURE_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100220
willy tarreau5cbea6f2005-12-17 12:48:26 +0100221/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100222#define FD_STCLOSE 0
223#define FD_STLISTEN 1
224#define FD_STCONN 2
225#define FD_STREADY 3
226#define FD_STERROR 4
227
willy tarreau5cbea6f2005-12-17 12:48:26 +0100228/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100229#define TASK_IDLE 0
230#define TASK_RUNNING 1
231
willy tarreau5cbea6f2005-12-17 12:48:26 +0100232/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100233#define PR_STNEW 0
234#define PR_STIDLE 1
235#define PR_STRUN 2
236#define PR_STDISABLED 3
237
willy tarreau5cbea6f2005-12-17 12:48:26 +0100238/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100239#define PR_MODE_TCP 0
240#define PR_MODE_HTTP 1
241#define PR_MODE_HEALTH 2
242
willy tarreau5cbea6f2005-12-17 12:48:26 +0100243/* bits for proxy->options */
244#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
245#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
246#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
247#define PR_O_COOK_IND 8 /* keep only indirect cookies */
248#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
249#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
250#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
251#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100252#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
253#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100254#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
255#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100256#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100257#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100258#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
willy tarreau8337c6b2005-12-17 13:41:01 +0100259#define PR_O_PERSIST 8192 /* server persistence stays effective even when server is down */
willy tarreau25c4ea52005-12-18 00:49:49 +0100260#define PR_O_LOGASAP 16384 /* log as soon as possible, without waiting for the session to complete */
261#define PR_O_HTTP_CLOSE 32768 /* force 'connection: close' in both directions */
willy tarreau97f58572005-12-18 00:53:44 +0100262#define PR_O_CHK_CACHE 65536 /* require examination of cacheability of the 'set-cookie' field */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100263
willy tarreaue39cd132005-12-17 13:00:18 +0100264/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100265#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
266#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
267#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
268#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
269#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
270#define SN_POST 0x00000020 /* the request was an HTTP POST */
271
272#define SN_CK_NONE 0x00000000 /* this session had no cookie */
273#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
274#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
275#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
276#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
277#define SN_CK_SHIFT 6 /* bit shift */
278
279#define SN_ERR_CLITO 0x00000100 /* client time-out */
280#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
281#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
282#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
283#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
284#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
285#define SN_ERR_SHIFT 8 /* bit shift */
286
287#define SN_FINST_R 0x00001000 /* session ended during client request */
288#define SN_FINST_C 0x00002000 /* session ended during server connect */
289#define SN_FINST_H 0x00003000 /* session ended during server headers */
290#define SN_FINST_D 0x00004000 /* session ended during data phase */
291#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
292#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
293#define SN_FINST_SHIFT 12 /* bit shift */
294
295#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
296#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
297#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
298#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
299#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100300#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100301#define SN_SCK_SHIFT 16 /* bit shift */
302
willy tarreau97f58572005-12-18 00:53:44 +0100303#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
304#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
305#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100306
307/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100308#define CL_STHEADERS 0
309#define CL_STDATA 1
310#define CL_STSHUTR 2
311#define CL_STSHUTW 3
312#define CL_STCLOSE 4
313
willy tarreau5cbea6f2005-12-17 12:48:26 +0100314/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100315#define SV_STIDLE 0
316#define SV_STCONN 1
317#define SV_STHEADERS 2
318#define SV_STDATA 3
319#define SV_STSHUTR 4
320#define SV_STSHUTW 5
321#define SV_STCLOSE 6
322
323/* result of an I/O event */
324#define RES_SILENT 0 /* didn't happen */
325#define RES_DATA 1 /* data were sent or received */
326#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
327#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
328
willy tarreau9fe663a2005-12-17 13:02:59 +0100329/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100330#define MODE_DEBUG 1
331#define MODE_STATS 2
332#define MODE_LOG 4
333#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100334#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100335#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100336#define MODE_VERBOSE 64
willy tarreau5cbea6f2005-12-17 12:48:26 +0100337
338/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100339#define SRV_RUNNING 1 /* the server is UP */
340#define SRV_BACKUP 2 /* this server is a backup server */
341#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0f7af912005-12-17 12:21:26 +0100342
willy tarreaue39cd132005-12-17 13:00:18 +0100343/* what to do when a header matches a regex */
344#define ACT_ALLOW 0 /* allow the request */
345#define ACT_REPLACE 1 /* replace the matching header */
346#define ACT_REMOVE 2 /* remove the matching header */
347#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100348#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100349
willy tarreau9fe663a2005-12-17 13:02:59 +0100350/* configuration sections */
351#define CFG_NONE 0
352#define CFG_GLOBAL 1
353#define CFG_LISTEN 2
354
willy tarreaua1598082005-12-17 13:08:06 +0100355/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100356#define LW_DATE 1 /* date */
357#define LW_CLIP 2 /* CLient IP */
358#define LW_SVIP 4 /* SerVer IP */
359#define LW_SVID 8 /* server ID */
360#define LW_REQ 16 /* http REQuest */
361#define LW_RESP 32 /* http RESPonse */
362#define LW_PXIP 64 /* proxy IP */
363#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100364#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100365#define LW_COOKIE 512 /* captured cookie */
366#define LW_REQHDR 1024 /* request header(s) */
367#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100368
willy tarreau0f7af912005-12-17 12:21:26 +0100369/*********************************************************************/
370
371#define LIST_HEAD(a) ((void *)(&(a)))
372
373/*********************************************************************/
374
willy tarreau4302f492005-12-18 01:00:37 +0100375struct cap_hdr {
376 struct cap_hdr *next;
377 char *name; /* header name, case insensitive */
378 int namelen; /* length of the header name, to speed-up lookups */
379 int len; /* capture length, not including terminal zero */
380 int index; /* index in the output array */
381 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
382};
383
willy tarreau0f7af912005-12-17 12:21:26 +0100384struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100385 struct hdr_exp *next;
386 regex_t *preg; /* expression to look for */
387 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
388 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100389};
390
391struct buffer {
392 unsigned int l; /* data length */
393 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100394 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100395 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100396 char data[BUFSIZE];
397};
398
399struct server {
400 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100401 int state; /* server state (SRV_*) */
402 int cklen; /* the len of the cookie, to speed up checks */
403 char *cookie; /* the id set in the cookie */
404 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100405 struct sockaddr_in addr; /* the address to connect to */
willy tarreaua41a8b42005-12-17 14:02:24 +0100406 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100407 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100408 int rise, fall; /* time in iterations */
409 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100410 int result; /* 0 = connect OK, -1 = connect KO */
411 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100412 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100413};
414
willy tarreau5cbea6f2005-12-17 12:48:26 +0100415/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100416struct task {
417 struct task *next, *prev; /* chaining ... */
418 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100419 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100420 int state; /* task state : IDLE or RUNNING */
421 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100422 int (*process)(struct task *t); /* the function which processes the task */
423 void *context; /* the task's context */
424};
425
426/* WARNING: if new fields are added, they must be initialized in event_accept() */
427struct session {
428 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100429 /* application specific below */
430 struct timeval crexpire; /* expiration date for a client read */
431 struct timeval cwexpire; /* expiration date for a client write */
432 struct timeval srexpire; /* expiration date for a server read */
433 struct timeval swexpire; /* expiration date for a server write */
434 struct timeval cnexpire; /* expiration date for a connect */
435 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
436 struct proxy *proxy; /* the proxy this socket belongs to */
437 int cli_fd; /* the client side fd */
438 int srv_fd; /* the server side fd */
439 int cli_state; /* state of the client side */
440 int srv_state; /* state of the server side */
441 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100442 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100443 struct buffer *req; /* request buffer */
444 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100445 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100446 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100447 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100448 char **req_cap; /* array of captured request headers (may be NULL) */
449 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100450 struct {
451 int logwait; /* log fields waiting to be collected : LW_* */
452 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
453 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
454 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
455 long t_data; /* delay before the first data byte from the server ... */
456 unsigned long t_close; /* total session duration */
457 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100458 char *cli_cookie; /* cookie presented by the client, in capture mode */
459 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100460 int status; /* HTTP status from the server, negative if from proxy */
461 long long bytes; /* number of bytes transferred from the server */
462 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100463 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100464};
465
willy tarreaua41a8b42005-12-17 14:02:24 +0100466struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100467 int fd; /* the listen socket */
468 struct sockaddr_storage addr; /* the address we listen to */
469 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100470};
471
472
willy tarreau0f7af912005-12-17 12:21:26 +0100473struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100474 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100475 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100476 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100477 struct server *srv, *cursrv; /* known servers, current server */
478 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100479 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100480 int cookie_len; /* strlen(cookie_len), computed only once */
481 char *capture_name; /* beginning of the name of the cookie to capture */
482 int capture_namelen; /* length of the cookie name to match */
483 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100484 int clitimeout; /* client I/O timeout (in milliseconds) */
485 int srvtimeout; /* server I/O timeout (in milliseconds) */
486 int contimeout; /* connect timeout (in milliseconds) */
487 char *id; /* proxy id */
488 int nbconn; /* # of active sessions */
489 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100490 int conn_retries; /* maximum number of connect retries */
491 int options; /* PR_O_REDISP, PR_O_TRANSP */
492 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100493 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100494 struct proxy *next;
495 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
496 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100497 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100498 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100499 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100500 int nb_reqadd, nb_rspadd;
501 struct hdr_exp *req_exp; /* regular expressions for request headers */
502 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100503 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
504 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
505 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
506 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100507 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100508 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100509 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
510 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100511 struct {
512 char *msg400; /* message for error 400 */
513 int len400; /* message length for error 400 */
514 char *msg403; /* message for error 403 */
515 int len403; /* message length for error 403 */
516 char *msg408; /* message for error 408 */
517 int len408; /* message length for error 408 */
518 char *msg500; /* message for error 500 */
519 int len500; /* message length for error 500 */
520 char *msg502; /* message for error 502 */
521 int len502; /* message length for error 502 */
522 char *msg503; /* message for error 503 */
523 int len503; /* message length for error 503 */
524 char *msg504; /* message for error 504 */
525 int len504; /* message length for error 504 */
526 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100527};
528
529/* info about one given fd */
530struct fdtab {
531 int (*read)(int fd); /* read function */
532 int (*write)(int fd); /* write function */
533 struct task *owner; /* the session (or proxy) associated with this fd */
534 int state; /* the state of this fd */
535};
536
537/*********************************************************************/
538
willy tarreau0f7af912005-12-17 12:21:26 +0100539int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100540char *cfg_cfgfile = NULL; /* configuration file */
541char *progname = NULL; /* program name */
542int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100543
544/* global options */
545static struct {
546 int uid;
547 int gid;
548 int nbproc;
549 int maxconn;
550 int maxsock; /* max # of sockets */
551 int mode;
552 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100553 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100554 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100555 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100556 struct sockaddr_in logsrv1, logsrv2;
557} global = {
558 logfac1 : -1,
559 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100560 loglev1 : 7, /* max syslog level : debug */
561 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100562 /* others NULL OK */
563};
564
willy tarreau0f7af912005-12-17 12:21:26 +0100565/*********************************************************************/
566
567fd_set *ReadEvent,
568 *WriteEvent,
569 *StaticReadEvent,
570 *StaticWriteEvent;
571
572void **pool_session = NULL,
573 **pool_buffer = NULL,
574 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100575 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100576 **pool_task = NULL,
577 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100578
579struct proxy *proxy = NULL; /* list of all existing proxies */
580struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100581struct task *rq = NULL; /* global run queue */
582struct task wait_queue = { /* global wait queue */
583 prev:LIST_HEAD(wait_queue),
584 next:LIST_HEAD(wait_queue)
585};
willy tarreau0f7af912005-12-17 12:21:26 +0100586
willy tarreau0f7af912005-12-17 12:21:26 +0100587static int totalconn = 0; /* total # of terminated sessions */
588static int actconn = 0; /* # of active sessions */
589static int maxfd = 0; /* # of the highest fd + 1 */
590static int listeners = 0; /* # of listeners */
591static int stopping = 0; /* non zero means stopping in progress */
592static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100593static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100594
595static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100596/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100597static char trash[BUFSIZE];
598
willy tarreaudd07e972005-12-18 00:48:48 +0100599const int zero = 0;
600const int one = 1;
601
willy tarreau0f7af912005-12-17 12:21:26 +0100602/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100603 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100604 */
605
606#define MAX_SYSLOG_LEN 1024
607#define NB_LOG_FACILITIES 24
608const char *log_facilities[NB_LOG_FACILITIES] = {
609 "kern", "user", "mail", "daemon",
610 "auth", "syslog", "lpr", "news",
611 "uucp", "cron", "auth2", "ftp",
612 "ntp", "audit", "alert", "cron2",
613 "local0", "local1", "local2", "local3",
614 "local4", "local5", "local6", "local7"
615};
616
617
618#define NB_LOG_LEVELS 8
619const char *log_levels[NB_LOG_LEVELS] = {
620 "emerg", "alert", "crit", "err",
621 "warning", "notice", "info", "debug"
622};
623
624#define SYSLOG_PORT 514
625
626const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
627 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100628
629const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
630const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
631const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
632const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
633 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
634 unknown, Set-cookie Rewritten */
635
willy tarreau0f7af912005-12-17 12:21:26 +0100636#define MAX_HOSTNAME_LEN 32
637static char hostname[MAX_HOSTNAME_LEN] = "";
638
willy tarreau8337c6b2005-12-17 13:41:01 +0100639const char *HTTP_302 =
640 "HTTP/1.0 302 Found\r\n"
641 "Cache-Control: no-cache\r\n"
642 "Connection: close\r\n"
643 "Location: "; /* not terminated since it will be concatenated with the URL */
644
willy tarreaua1598082005-12-17 13:08:06 +0100645const char *HTTP_400 =
646 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100647 "Cache-Control: no-cache\r\n"
648 "Connection: close\r\n"
649 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100650 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100651
willy tarreaua1598082005-12-17 13:08:06 +0100652const char *HTTP_403 =
653 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100654 "Cache-Control: no-cache\r\n"
655 "Connection: close\r\n"
656 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100657 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
658
willy tarreau8337c6b2005-12-17 13:41:01 +0100659const char *HTTP_408 =
660 "HTTP/1.0 408 Request Time-out\r\n"
661 "Cache-Control: no-cache\r\n"
662 "Connection: close\r\n"
663 "\r\n"
664 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
665
willy tarreau750a4722005-12-17 13:21:24 +0100666const char *HTTP_500 =
667 "HTTP/1.0 500 Server Error\r\n"
668 "Cache-Control: no-cache\r\n"
669 "Connection: close\r\n"
670 "\r\n"
671 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100672
673const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100674 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100675 "Cache-Control: no-cache\r\n"
676 "Connection: close\r\n"
677 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100678 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
679
680const char *HTTP_503 =
681 "HTTP/1.0 503 Service Unavailable\r\n"
682 "Cache-Control: no-cache\r\n"
683 "Connection: close\r\n"
684 "\r\n"
685 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
686
687const char *HTTP_504 =
688 "HTTP/1.0 504 Gateway Time-out\r\n"
689 "Cache-Control: no-cache\r\n"
690 "Connection: close\r\n"
691 "\r\n"
692 "<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 +0100693
willy tarreau0f7af912005-12-17 12:21:26 +0100694/*********************************************************************/
695/* statistics ******************************************************/
696/*********************************************************************/
697
willy tarreau750a4722005-12-17 13:21:24 +0100698#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100699static int stats_tsk_lsrch, stats_tsk_rsrch,
700 stats_tsk_good, stats_tsk_right, stats_tsk_left,
701 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100702#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100703
704
705/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100706/* debugging *******************************************************/
707/*********************************************************************/
708#ifdef DEBUG_FULL
709static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
710static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
711#endif
712
713/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100714/* function prototypes *********************************************/
715/*********************************************************************/
716
717int event_accept(int fd);
718int event_cli_read(int fd);
719int event_cli_write(int fd);
720int event_srv_read(int fd);
721int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100722int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100723
724/*********************************************************************/
725/* general purpose functions ***************************************/
726/*********************************************************************/
727
728void display_version() {
729 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreaudd07e972005-12-18 00:48:48 +0100730 printf("Copyright 2000-2004 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100731}
732
733/*
734 * This function prints the command line usage and exits
735 */
736void usage(char *name) {
737 display_version();
738 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100739 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100740#if STATTIME > 0
741 "sl"
742#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100743 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100744 " -v displays version\n"
745 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100746 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100747#if STATTIME > 0
748 " -s enables statistics output\n"
749 " -l enables long statistics format\n"
750#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100751 " -D goes daemon ; implies -q\n"
752 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100753 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100754 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100755 " -N sets the default, per-proxy maximum # of connections (%d)\n"
756 " -p writes pids of all children to this file\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100757 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100758 exit(1);
759}
760
761
762/*
763 * Displays the message on stderr with the date and pid.
764 */
765void Alert(char *fmt, ...) {
766 va_list argp;
767 struct timeval tv;
768 struct tm *tm;
769
willy tarreau982249e2005-12-18 00:57:06 +0100770 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100771 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100772
willy tarreau5cbea6f2005-12-17 12:48:26 +0100773 gettimeofday(&tv, NULL);
774 tm=localtime(&tv.tv_sec);
775 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100776 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100777 vfprintf(stderr, fmt, argp);
778 fflush(stderr);
779 va_end(argp);
780 }
willy tarreau0f7af912005-12-17 12:21:26 +0100781}
782
783
784/*
785 * Displays the message on stderr with the date and pid.
786 */
787void Warning(char *fmt, ...) {
788 va_list argp;
789 struct timeval tv;
790 struct tm *tm;
791
willy tarreau982249e2005-12-18 00:57:06 +0100792 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100793 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100794
willy tarreau5cbea6f2005-12-17 12:48:26 +0100795 gettimeofday(&tv, NULL);
796 tm=localtime(&tv.tv_sec);
797 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100798 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100799 vfprintf(stderr, fmt, argp);
800 fflush(stderr);
801 va_end(argp);
802 }
803}
804
805/*
806 * Displays the message on <out> only if quiet mode is not set.
807 */
808void qfprintf(FILE *out, char *fmt, ...) {
809 va_list argp;
810
willy tarreau982249e2005-12-18 00:57:06 +0100811 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100812 va_start(argp, fmt);
813 vfprintf(out, fmt, argp);
814 fflush(out);
815 va_end(argp);
816 }
willy tarreau0f7af912005-12-17 12:21:26 +0100817}
818
819
820/*
821 * converts <str> to a struct sockaddr_in* which is locally allocated.
822 * The format is "addr:port", where "addr" can be empty or "*" to indicate
823 * INADDR_ANY.
824 */
825struct sockaddr_in *str2sa(char *str) {
826 static struct sockaddr_in sa;
827 char *c;
828 int port;
829
willy tarreaua1598082005-12-17 13:08:06 +0100830 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100831 str=strdup(str);
832
833 if ((c=strrchr(str,':')) != NULL) {
834 *c++=0;
835 port=atol(c);
836 }
837 else
838 port=0;
839
840 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
841 sa.sin_addr.s_addr = INADDR_ANY;
842 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100843 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100844 struct hostent *he;
845
846 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100847 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100848 }
849 else
850 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
851 }
852 sa.sin_port=htons(port);
853 sa.sin_family=AF_INET;
854
855 free(str);
856 return &sa;
857}
858
willy tarreau9fe663a2005-12-17 13:02:59 +0100859
860/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100861 * converts <str> to a list of listeners which are dynamically allocated.
862 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
863 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
864 * - <port> is a numerical port from 1 to 65535 ;
865 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
866 * This can be repeated as many times as necessary, separated by a coma.
867 * The <tail> argument is a pointer to a current list which should be appended
868 * to the tail of the new list. The pointer to the new list is returned.
869 */
870struct listener *str2listener(char *str, struct listener *tail) {
871 struct listener *l;
872 char *c, *next, *range, *dupstr;
873 int port, end;
874
875 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +0100876
willy tarreaua41a8b42005-12-17 14:02:24 +0100877 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100878 struct sockaddr_storage ss;
879
willy tarreaua41a8b42005-12-17 14:02:24 +0100880 str = next;
881 /* 1) look for the end of the first address */
882 if ((next = strrchr(str, ',')) != NULL) {
883 *next++ = 0;
884 }
885
willy tarreau8a86dbf2005-12-18 00:45:59 +0100886 /* 2) look for the addr/port delimiter, it's the last colon. */
887 if ((range = strrchr(str, ':')) == NULL) {
888 Alert("Missing port number: '%s'\n", str);
889 }
890
891 *range++ = 0;
892
893 if (strrchr(str, ':') != NULL) {
894 /* IPv6 address contains ':' */
895 memset(&ss, 0, sizeof(ss));
896 ss.ss_family = AF_INET6;
897
898 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
899 Alert("Invalid server address: '%s'\n", str);
900 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100901 }
902 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100903 memset(&ss, 0, sizeof(ss));
904 ss.ss_family = AF_INET;
905
906 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
907 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
908 }
909 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
910 struct hostent *he;
911
912 if ((he = gethostbyname(str)) == NULL) {
913 Alert("Invalid server name: '%s'\n", str);
914 }
915 else
916 ((struct sockaddr_in *)&ss)->sin_addr =
917 *(struct in_addr *) *(he->h_addr_list);
918 }
919 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100920
921 /* 3) look for the port-end delimiter */
922 if ((c = strchr(range, '-')) != NULL) {
923 *c++ = 0;
924 end = atol(c);
925 }
926 else {
927 end = atol(range);
928 }
929
930 for (port = atol(range); port <= end; port++) {
931 l = (struct listener *)calloc(1, sizeof(struct listener));
932 l->next = tail;
933 tail = l;
934
willy tarreau8a86dbf2005-12-18 00:45:59 +0100935 l->addr = ss;
936 if (ss.ss_family == AF_INET6)
937 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
938 else
939 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
940
willy tarreaua41a8b42005-12-17 14:02:24 +0100941 } /* end for(port) */
942 } /* end while(next) */
943 free(dupstr);
944 return tail;
945}
946
willy tarreau4302f492005-12-18 01:00:37 +0100947
948#define FD_SETS_ARE_BITFIELDS
949#ifdef FD_SETS_ARE_BITFIELDS
950/*
951 * This map is used with all the FD_* macros to check whether a particular bit
952 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
953 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
954 * byte should be encoded. Be careful to always pass bytes from 0 to 255
955 * exclusively to the macros.
956 */
957fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
958fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
959
960#else
961#error "Check if your OS uses bitfields for fd_sets"
962#endif
963
964/* will try to encode the string <string> replacing all characters tagged in
965 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
966 * prefixed by <escape>, and will store the result between <start> (included
967 *) and <stop> (excluded), and will always terminate the string with a '\0'
968 * before <stop>. The position of the '\0' is returned if the conversion
969 * completes. If bytes are missing between <start> and <stop>, then the
970 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
971 * cannot even be stored so we return <start> without writing the 0.
972 * The input string must also be zero-terminated.
973 */
974char hextab[16] = "0123456789ABCDEF";
975char *encode_string(char *start, char *stop,
976 const char escape, const fd_set *map,
977 const char *string)
978{
979 if (start < stop) {
980 stop--; /* reserve one byte for the final '\0' */
981 while (start < stop && *string != 0) {
982 if (!FD_ISSET((unsigned char)(*string), map))
983 *start++ = *string;
984 else {
985 if (start + 3 >= stop)
986 break;
987 *start++ = escape;
988 *start++ = hextab[(*string >> 4) & 15];
989 *start++ = hextab[*string & 15];
990 }
991 string++;
992 }
993 *start = '\0';
994 }
995 return start;
996}
willy tarreaua41a8b42005-12-17 14:02:24 +0100997
998/*
willy tarreau9fe663a2005-12-17 13:02:59 +0100999 * This function sends a syslog message to both log servers of a proxy,
1000 * or to global log servers if the proxy is NULL.
1001 * It also tries not to waste too much time computing the message header.
1002 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001003 */
1004void send_log(struct proxy *p, int level, char *message, ...) {
1005 static int logfd = -1; /* syslog UDP socket */
1006 static long tvsec = -1; /* to force the string to be initialized */
1007 struct timeval tv;
1008 va_list argp;
1009 static char logmsg[MAX_SYSLOG_LEN];
1010 static char *dataptr = NULL;
1011 int fac_level;
1012 int hdr_len, data_len;
1013 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001014 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001015 int nbloggers = 0;
1016 char *log_ptr;
1017
1018 if (logfd < 0) {
1019 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1020 return;
1021 }
1022
1023 if (level < 0 || progname == NULL || message == NULL)
1024 return;
1025
1026 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001027 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001028 /* this string is rebuild only once a second */
1029 struct tm *tm = localtime(&tv.tv_sec);
1030 tvsec = tv.tv_sec;
1031
willy tarreauc29948c2005-12-17 13:10:27 +01001032 hdr_len = snprintf(logmsg, sizeof(logmsg),
1033 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1034 monthname[tm->tm_mon],
1035 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1036 progname, pid);
1037 /* WARNING: depending upon implementations, snprintf may return
1038 * either -1 or the number of bytes that would be needed to store
1039 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001040 */
willy tarreauc29948c2005-12-17 13:10:27 +01001041 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1042 hdr_len = sizeof(logmsg);
1043
1044 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001045 }
1046
1047 va_start(argp, message);
1048 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001049 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1050 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001051 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001052 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001053
1054 if (p == NULL) {
1055 if (global.logfac1 >= 0) {
1056 sa[nbloggers] = &global.logsrv1;
1057 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001058 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001059 nbloggers++;
1060 }
1061 if (global.logfac2 >= 0) {
1062 sa[nbloggers] = &global.logsrv2;
1063 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001064 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001065 nbloggers++;
1066 }
1067 } else {
1068 if (p->logfac1 >= 0) {
1069 sa[nbloggers] = &p->logsrv1;
1070 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001071 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001072 nbloggers++;
1073 }
1074 if (p->logfac2 >= 0) {
1075 sa[nbloggers] = &p->logsrv2;
1076 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001077 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001078 nbloggers++;
1079 }
1080 }
1081
1082 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001083 /* we can filter the level of the messages that are sent to each logger */
1084 if (level > loglevel[nbloggers])
1085 continue;
1086
willy tarreauc29948c2005-12-17 13:10:27 +01001087 /* For each target, we may have a different facility.
1088 * We can also have a different log level for each message.
1089 * This induces variations in the message header length.
1090 * Since we don't want to recompute it each time, nor copy it every
1091 * time, we only change the facility in the pre-computed header,
1092 * and we change the pointer to the header accordingly.
1093 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001094 fac_level = (facilities[nbloggers] << 3) + level;
1095 log_ptr = logmsg + 3; /* last digit of the log level */
1096 do {
1097 *log_ptr = '0' + fac_level % 10;
1098 fac_level /= 10;
1099 log_ptr--;
1100 } while (fac_level && log_ptr > logmsg);
1101 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001102
willy tarreauc29948c2005-12-17 13:10:27 +01001103 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001104
1105#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001106 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001107 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1108#else
willy tarreauc29948c2005-12-17 13:10:27 +01001109 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001110 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1111#endif
1112 }
willy tarreau0f7af912005-12-17 12:21:26 +01001113}
1114
1115
1116/* sets <tv> to the current time */
1117static inline struct timeval *tv_now(struct timeval *tv) {
1118 if (tv)
1119 gettimeofday(tv, NULL);
1120 return tv;
1121}
1122
1123/*
1124 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1125 */
1126static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1127 if (!tv || !from)
1128 return NULL;
1129 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1130 tv->tv_sec = from->tv_sec + (ms/1000);
1131 while (tv->tv_usec >= 1000000) {
1132 tv->tv_usec -= 1000000;
1133 tv->tv_sec++;
1134 }
1135 return tv;
1136}
1137
1138/*
1139 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1140 */
1141static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001142 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001143 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001144 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001145 return 1;
1146 else if (tv1->tv_usec < tv2->tv_usec)
1147 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001148 else if (tv1->tv_usec > tv2->tv_usec)
1149 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001150 else
1151 return 0;
1152}
1153
1154/*
1155 * returns the absolute difference, in ms, between tv1 and tv2
1156 */
1157unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1158 int cmp;
1159 unsigned long ret;
1160
1161
willy tarreauef900ab2005-12-17 12:52:52 +01001162 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001163 if (!cmp)
1164 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001165 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001166 struct timeval *tmp = tv1;
1167 tv1 = tv2;
1168 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001169 }
willy tarreauef900ab2005-12-17 12:52:52 +01001170 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001171 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001172 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001173 else
willy tarreauef900ab2005-12-17 12:52:52 +01001174 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001175 return (unsigned long) ret;
1176}
1177
1178/*
willy tarreau750a4722005-12-17 13:21:24 +01001179 * returns the difference, in ms, between tv1 and tv2
1180 */
1181static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1182 unsigned long ret;
1183
willy tarreau6e682ce2005-12-17 13:26:49 +01001184 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1185 if (tv2->tv_usec > tv1->tv_usec)
1186 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001187 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001188 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001189 return (unsigned long) ret;
1190}
1191
1192/*
willy tarreau0f7af912005-12-17 12:21:26 +01001193 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1194 */
1195static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001196 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001197 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001198 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001199 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1200 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001201 else
1202 return 0;
1203 }
willy tarreau0f7af912005-12-17 12:21:26 +01001204 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001205 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001206 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001207 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1208 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1209 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001210 else
1211 return 0;
1212}
1213
1214/*
1215 * returns the remaining time between tv1=now and event=tv2
1216 * if tv2 is passed, 0 is returned.
1217 */
1218static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1219 unsigned long ret;
1220
willy tarreau0f7af912005-12-17 12:21:26 +01001221 if (tv_cmp_ms(tv1, tv2) >= 0)
1222 return 0; /* event elapsed */
1223
willy tarreauef900ab2005-12-17 12:52:52 +01001224 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001225 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001226 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001227 else
willy tarreauef900ab2005-12-17 12:52:52 +01001228 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001229 return (unsigned long) ret;
1230}
1231
1232
1233/*
1234 * zeroes a struct timeval
1235 */
1236
1237static inline struct timeval *tv_eternity(struct timeval *tv) {
1238 tv->tv_sec = tv->tv_usec = 0;
1239 return tv;
1240}
1241
1242/*
1243 * returns 1 if tv is null, else 0
1244 */
1245static inline int tv_iseternity(struct timeval *tv) {
1246 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1247 return 1;
1248 else
1249 return 0;
1250}
1251
1252/*
1253 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1254 * considering that 0 is the eternity.
1255 */
1256static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1257 if (tv_iseternity(tv1))
1258 if (tv_iseternity(tv2))
1259 return 0; /* same */
1260 else
1261 return 1; /* tv1 later than tv2 */
1262 else if (tv_iseternity(tv2))
1263 return -1; /* tv2 later than tv1 */
1264
1265 if (tv1->tv_sec > tv2->tv_sec)
1266 return 1;
1267 else if (tv1->tv_sec < tv2->tv_sec)
1268 return -1;
1269 else if (tv1->tv_usec > tv2->tv_usec)
1270 return 1;
1271 else if (tv1->tv_usec < tv2->tv_usec)
1272 return -1;
1273 else
1274 return 0;
1275}
1276
1277/*
1278 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1279 * considering that 0 is the eternity.
1280 */
1281static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1282 if (tv_iseternity(tv1))
1283 if (tv_iseternity(tv2))
1284 return 0; /* same */
1285 else
1286 return 1; /* tv1 later than tv2 */
1287 else if (tv_iseternity(tv2))
1288 return -1; /* tv2 later than tv1 */
1289
willy tarreauefae1842005-12-17 12:51:03 +01001290 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001291 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001292 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001293 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001294 return -1;
1295 else
1296 return 0;
1297 }
1298 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001299 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001300 return 1;
1301 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001302 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001303 return -1;
1304 else
1305 return 0;
1306}
1307
1308/*
1309 * returns the first event between tv1 and tv2 into tvmin.
1310 * a zero tv is ignored. tvmin is returned.
1311 */
1312static inline struct timeval *tv_min(struct timeval *tvmin,
1313 struct timeval *tv1, struct timeval *tv2) {
1314
1315 if (tv_cmp2(tv1, tv2) <= 0)
1316 *tvmin = *tv1;
1317 else
1318 *tvmin = *tv2;
1319
1320 return tvmin;
1321}
1322
1323
1324
1325/***********************************************************/
1326/* fd management ***************************************/
1327/***********************************************************/
1328
1329
1330
willy tarreau5cbea6f2005-12-17 12:48:26 +01001331/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1332 * The file descriptor is also closed.
1333 */
willy tarreau0f7af912005-12-17 12:21:26 +01001334static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001335 FD_CLR(fd, StaticReadEvent);
1336 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001337 close(fd);
1338 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001339
1340 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1341 maxfd--;
1342}
1343
1344/* recomputes the maxfd limit from the fd */
1345static inline void fd_insert(int fd) {
1346 if (fd+1 > maxfd)
1347 maxfd = fd+1;
1348}
1349
1350/*************************************************************/
1351/* task management ***************************************/
1352/*************************************************************/
1353
willy tarreau5cbea6f2005-12-17 12:48:26 +01001354/* puts the task <t> in run queue <q>, and returns <t> */
1355static inline struct task *task_wakeup(struct task **q, struct task *t) {
1356 if (t->state == TASK_RUNNING)
1357 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001358 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001359 t->rqnext = *q;
1360 t->state = TASK_RUNNING;
1361 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001362 }
1363}
1364
willy tarreau5cbea6f2005-12-17 12:48:26 +01001365/* removes the task <t> from the queue <q>
1366 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001367 * set the run queue to point to the next one, and return it
1368 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001369static inline struct task *task_sleep(struct task **q, struct task *t) {
1370 if (t->state == TASK_RUNNING) {
1371 *q = t->rqnext;
1372 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001373 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001374 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001375}
1376
1377/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001378 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001379 * from the run queue. A pointer to the task itself is returned.
1380 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001381static inline struct task *task_delete(struct task *t) {
1382 t->prev->next = t->next;
1383 t->next->prev = t->prev;
1384 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001385}
1386
1387/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001388 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001389 */
1390static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001391 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001392}
1393
willy tarreau5cbea6f2005-12-17 12:48:26 +01001394/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001395 * may be only moved or left where it was, depending on its timing requirements.
1396 * <task> is returned.
1397 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001398struct task *task_queue(struct task *task) {
1399 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001400 struct task *start_from;
1401
1402 /* first, test if the task was already in a list */
1403 if (task->prev == NULL) {
1404 // start_from = list;
1405 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001406#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001407 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001408#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001409 /* insert the unlinked <task> into the list, searching back from the last entry */
1410 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1411 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001412#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001413 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001414#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001415 }
1416
1417 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1418 // start_from = start_from->next;
1419 // stats_tsk_nsrch++;
1420 // }
1421 }
1422 else if (task->prev == list ||
1423 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1424 start_from = task->next;
1425 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001426#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001427 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001428#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001429 return task; /* it's already in the right place */
1430 }
1431
willy tarreau750a4722005-12-17 13:21:24 +01001432#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001433 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001434#endif
1435
1436 /* if the task is not at the right place, there's little chance that
1437 * it has only shifted a bit, and it will nearly always be queued
1438 * at the end of the list because of constant timeouts
1439 * (observed in real case).
1440 */
1441#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1442 start_from = list->prev; /* assume we'll queue to the end of the list */
1443 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1444 start_from = start_from->prev;
1445#if STATTIME > 0
1446 stats_tsk_lsrch++;
1447#endif
1448 }
1449#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001450 /* insert the unlinked <task> into the list, searching after position <start_from> */
1451 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1452 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001453#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001454 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001455#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001456 }
willy tarreau750a4722005-12-17 13:21:24 +01001457#endif /* WE_REALLY_... */
1458
willy tarreau0f7af912005-12-17 12:21:26 +01001459 /* we need to unlink it now */
1460 task_delete(task);
1461 }
1462 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001463#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001464 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001465#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001466#ifdef LEFT_TO_TOP /* not very good */
1467 start_from = list;
1468 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1469 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001470#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001471 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001472#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001473 }
1474#else
1475 start_from = task->prev->prev; /* valid because of the previous test above */
1476 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1477 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001478#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001479 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001480#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001481 }
1482#endif
1483 /* we need to unlink it now */
1484 task_delete(task);
1485 }
1486 task->prev = start_from;
1487 task->next = start_from->next;
1488 task->next->prev = task;
1489 start_from->next = task;
1490 return task;
1491}
1492
1493
1494/*********************************************************************/
1495/* more specific functions ***************************************/
1496/*********************************************************************/
1497
1498/* some prototypes */
1499static int maintain_proxies(void);
1500
willy tarreau5cbea6f2005-12-17 12:48:26 +01001501/* this either returns the sockname or the original destination address. Code
1502 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1503 */
1504static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001505#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001506 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1507#else
willy tarreaua1598082005-12-17 13:08:06 +01001508#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001509 return getsockname(fd, (struct sockaddr *)sa, salen);
1510#else
1511 return -1;
1512#endif
1513#endif
1514}
1515
1516/*
1517 * frees the context associated to a session. It must have been removed first.
1518 */
1519static inline void session_free(struct session *s) {
1520 if (s->req)
1521 pool_free(buffer, s->req);
1522 if (s->rep)
1523 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001524
1525 if (s->rsp_cap != NULL) {
1526 struct cap_hdr *h;
1527 for (h = s->proxy->rsp_cap; h; h = h->next) {
1528 if (s->rsp_cap[h->index] != NULL)
1529 pool_free_to(h->pool, s->rsp_cap[h->index]);
1530 }
1531 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1532 }
1533 if (s->req_cap != NULL) {
1534 struct cap_hdr *h;
1535 for (h = s->proxy->req_cap; h; h = h->next) {
1536 if (s->req_cap[h->index] != NULL)
1537 pool_free_to(h->pool, s->req_cap[h->index]);
1538 }
1539 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1540 }
1541
willy tarreaua1598082005-12-17 13:08:06 +01001542 if (s->logs.uri)
1543 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001544 if (s->logs.cli_cookie)
1545 pool_free(capture, s->logs.cli_cookie);
1546 if (s->logs.srv_cookie)
1547 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001548
willy tarreau5cbea6f2005-12-17 12:48:26 +01001549 pool_free(session, s);
1550}
1551
willy tarreau0f7af912005-12-17 12:21:26 +01001552
1553/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001554 * This function tries to find a running server for the proxy <px>. A first
1555 * pass looks for active servers, and if none is found, a second pass also
1556 * looks for backup servers.
1557 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1558 */
1559static inline struct server *find_server(struct proxy *px) {
1560 struct server *srv = px->cursrv;
1561 int ignore_backup = 1;
1562
1563 do {
1564 do {
1565 if (srv == NULL)
1566 srv = px->srv;
1567 if (srv->state & SRV_RUNNING
1568 && !((srv->state & SRV_BACKUP) && ignore_backup))
1569 return srv;
1570 srv = srv->next;
1571 } while (srv != px->cursrv);
1572 } while (ignore_backup--);
1573 return NULL;
1574}
1575
1576/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001577 * This function initiates a connection to the current server (s->srv) if (s->direct)
1578 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001579 * it's OK, -1 if it's impossible.
1580 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001581int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001582 int fd;
1583
1584 // fprintf(stderr,"connect_server : s=%p\n",s);
1585
willy tarreaue39cd132005-12-17 13:00:18 +01001586 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001587 s->srv_addr = s->srv->addr;
1588 }
1589 else if (s->proxy->options & PR_O_BALANCE) {
1590 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001591 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001592
willy tarreau8337c6b2005-12-17 13:41:01 +01001593 srv = find_server(s->proxy);
1594
1595 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001596 return -1;
1597
willy tarreau8337c6b2005-12-17 13:41:01 +01001598 s->srv_addr = srv->addr;
1599 s->srv = srv;
1600 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001601 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001602 else /* unknown balancing algorithm */
1603 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001604 }
willy tarreaua1598082005-12-17 13:08:06 +01001605 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001606 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001607 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001608 }
1609 else if (s->proxy->options & PR_O_TRANSP) {
1610 /* in transparent mode, use the original dest addr if no dispatch specified */
1611 int salen = sizeof(struct sockaddr_in);
1612 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1613 qfprintf(stderr, "Cannot get original server address.\n");
1614 return -1;
1615 }
1616 }
willy tarreau0f7af912005-12-17 12:21:26 +01001617
willy tarreaua41a8b42005-12-17 14:02:24 +01001618 /* if this server remaps proxied ports, we'll use
1619 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001620 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001621 struct sockaddr_in sockname;
1622 int namelen;
1623
1624 namelen = sizeof(sockname);
1625 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1626 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1627 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1628 }
1629
willy tarreau0f7af912005-12-17 12:21:26 +01001630 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001631 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001632 return -1;
1633 }
1634
willy tarreau9fe663a2005-12-17 13:02:59 +01001635 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001636 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1637 close(fd);
1638 return -1;
1639 }
1640
willy tarreau0f7af912005-12-17 12:21:26 +01001641 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1642 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001643 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001644 close(fd);
1645 return -1;
1646 }
1647
willy tarreaua1598082005-12-17 13:08:06 +01001648 /* allow specific binding */
1649 if (s->proxy->options & PR_O_BIND_SRC &&
1650 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1651 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1652 close(fd);
1653 return -1;
1654 }
1655
willy tarreau0f7af912005-12-17 12:21:26 +01001656 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1657 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001658 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001659 close(fd);
1660 return -1;
1661 }
1662 else if (errno != EALREADY && errno != EISCONN) {
1663 close(fd);
1664 return -1;
1665 }
1666 }
1667
willy tarreau5cbea6f2005-12-17 12:48:26 +01001668 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001669 fdtab[fd].read = &event_srv_read;
1670 fdtab[fd].write = &event_srv_write;
1671 fdtab[fd].state = FD_STCONN; /* connection in progress */
1672
1673 FD_SET(fd, StaticWriteEvent); /* for connect status */
1674
1675 fd_insert(fd);
1676
1677 if (s->proxy->contimeout)
1678 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1679 else
1680 tv_eternity(&s->cnexpire);
1681 return 0;
1682}
1683
1684/*
1685 * this function is called on a read event from a client socket.
1686 * It returns 0.
1687 */
1688int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001689 struct task *t = fdtab[fd].owner;
1690 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001691 struct buffer *b = s->req;
1692 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001693
1694 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1695
willy tarreau0f7af912005-12-17 12:21:26 +01001696 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 while (1) {
1698 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1699 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001700 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001701 }
1702 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001703 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001704 }
1705 else {
1706 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001707 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1708 * since it means that the rewrite protection has been removed. This
1709 * implies that the if statement can be removed.
1710 */
1711 if (max > b->rlim - b->data)
1712 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001713 }
1714
1715 if (max == 0) { /* not anymore room to store data */
1716 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001717 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001718 }
1719
willy tarreau3242e862005-12-17 12:27:53 +01001720#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001721 {
1722 int skerr, lskerr;
1723
1724 lskerr = sizeof(skerr);
1725 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1726 if (skerr)
1727 ret = -1;
1728 else
1729 ret = recv(fd, b->r, max, 0);
1730 }
willy tarreau3242e862005-12-17 12:27:53 +01001731#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001732 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001733#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001734 if (ret > 0) {
1735 b->r += ret;
1736 b->l += ret;
1737 s->res_cr = RES_DATA;
1738
1739 if (b->r == b->data + BUFSIZE) {
1740 b->r = b->data; /* wrap around the buffer */
1741 }
willy tarreaua1598082005-12-17 13:08:06 +01001742
1743 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001744 /* we hope to read more data or to get a close on next round */
1745 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001746 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001747 else if (ret == 0) {
1748 s->res_cr = RES_NULL;
1749 break;
1750 }
1751 else if (errno == EAGAIN) {/* ignore EAGAIN */
1752 break;
1753 }
1754 else {
1755 s->res_cr = RES_ERROR;
1756 fdtab[fd].state = FD_STERROR;
1757 break;
1758 }
1759 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001760 }
1761 else {
1762 s->res_cr = RES_ERROR;
1763 fdtab[fd].state = FD_STERROR;
1764 }
1765
willy tarreau5cbea6f2005-12-17 12:48:26 +01001766 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001767 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001768 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1769 else
1770 tv_eternity(&s->crexpire);
1771
1772 task_wakeup(&rq, t);
1773 }
willy tarreau0f7af912005-12-17 12:21:26 +01001774
willy tarreau0f7af912005-12-17 12:21:26 +01001775 return 0;
1776}
1777
1778
1779/*
1780 * this function is called on a read event from a server socket.
1781 * It returns 0.
1782 */
1783int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001784 struct task *t = fdtab[fd].owner;
1785 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001786 struct buffer *b = s->rep;
1787 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001788
1789 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1790
willy tarreau0f7af912005-12-17 12:21:26 +01001791 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001792 while (1) {
1793 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1794 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001795 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001796 }
1797 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001798 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001799 }
1800 else {
1801 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001802 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1803 * since it means that the rewrite protection has been removed. This
1804 * implies that the if statement can be removed.
1805 */
1806 if (max > b->rlim - b->data)
1807 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001808 }
1809
1810 if (max == 0) { /* not anymore room to store data */
1811 FD_CLR(fd, StaticReadEvent);
1812 break;
1813 }
1814
willy tarreau3242e862005-12-17 12:27:53 +01001815#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001816 {
1817 int skerr, lskerr;
1818
1819 lskerr = sizeof(skerr);
1820 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1821 if (skerr)
1822 ret = -1;
1823 else
1824 ret = recv(fd, b->r, max, 0);
1825 }
willy tarreau3242e862005-12-17 12:27:53 +01001826#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001827 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001828#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001829 if (ret > 0) {
1830 b->r += ret;
1831 b->l += ret;
1832 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001833
willy tarreau5cbea6f2005-12-17 12:48:26 +01001834 if (b->r == b->data + BUFSIZE) {
1835 b->r = b->data; /* wrap around the buffer */
1836 }
willy tarreaua1598082005-12-17 13:08:06 +01001837
1838 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001839 /* we hope to read more data or to get a close on next round */
1840 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001841 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001842 else if (ret == 0) {
1843 s->res_sr = RES_NULL;
1844 break;
1845 }
1846 else if (errno == EAGAIN) {/* ignore EAGAIN */
1847 break;
1848 }
1849 else {
1850 s->res_sr = RES_ERROR;
1851 fdtab[fd].state = FD_STERROR;
1852 break;
1853 }
1854 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001855 }
1856 else {
1857 s->res_sr = RES_ERROR;
1858 fdtab[fd].state = FD_STERROR;
1859 }
1860
willy tarreau5cbea6f2005-12-17 12:48:26 +01001861 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001862 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001863 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1864 else
1865 tv_eternity(&s->srexpire);
1866
1867 task_wakeup(&rq, t);
1868 }
willy tarreau0f7af912005-12-17 12:21:26 +01001869
willy tarreau0f7af912005-12-17 12:21:26 +01001870 return 0;
1871}
1872
1873/*
1874 * this function is called on a write event from a client socket.
1875 * It returns 0.
1876 */
1877int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 struct task *t = fdtab[fd].owner;
1879 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001880 struct buffer *b = s->rep;
1881 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001882
1883 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1884
1885 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001886 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001887 // max = BUFSIZE; BUG !!!!
1888 max = 0;
1889 }
1890 else if (b->r > b->w) {
1891 max = b->r - b->w;
1892 }
1893 else
1894 max = b->data + BUFSIZE - b->w;
1895
willy tarreau0f7af912005-12-17 12:21:26 +01001896 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001897#ifndef MSG_NOSIGNAL
1898 int skerr, lskerr;
1899#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001900
1901 if (max == 0) {
1902 s->res_cw = RES_NULL;
1903 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001904 tv_eternity(&s->cwexpire);
1905 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001906 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001907 }
1908
willy tarreau3242e862005-12-17 12:27:53 +01001909#ifndef MSG_NOSIGNAL
1910 lskerr=sizeof(skerr);
1911 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1912 if (skerr)
1913 ret = -1;
1914 else
1915 ret = send(fd, b->w, max, MSG_DONTWAIT);
1916#else
willy tarreau0f7af912005-12-17 12:21:26 +01001917 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001918#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001919
1920 if (ret > 0) {
1921 b->l -= ret;
1922 b->w += ret;
1923
1924 s->res_cw = RES_DATA;
1925
1926 if (b->w == b->data + BUFSIZE) {
1927 b->w = b->data; /* wrap around the buffer */
1928 }
1929 }
1930 else if (ret == 0) {
1931 /* nothing written, just make as if we were never called */
1932// s->res_cw = RES_NULL;
1933 return 0;
1934 }
1935 else if (errno == EAGAIN) /* ignore EAGAIN */
1936 return 0;
1937 else {
1938 s->res_cw = RES_ERROR;
1939 fdtab[fd].state = FD_STERROR;
1940 }
1941 }
1942 else {
1943 s->res_cw = RES_ERROR;
1944 fdtab[fd].state = FD_STERROR;
1945 }
1946
willy tarreaub1ff9db2005-12-17 13:51:03 +01001947 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001948 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001949 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
1950 s->crexpire = s->cwexpire;
1951 }
willy tarreau0f7af912005-12-17 12:21:26 +01001952 else
1953 tv_eternity(&s->cwexpire);
1954
willy tarreau5cbea6f2005-12-17 12:48:26 +01001955 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001956 return 0;
1957}
1958
1959
1960/*
1961 * this function is called on a write event from a server socket.
1962 * It returns 0.
1963 */
1964int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001965 struct task *t = fdtab[fd].owner;
1966 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001967 struct buffer *b = s->req;
1968 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001969
1970 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1971
1972 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001973 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001974 // max = BUFSIZE; BUG !!!!
1975 max = 0;
1976 }
1977 else if (b->r > b->w) {
1978 max = b->r - b->w;
1979 }
1980 else
1981 max = b->data + BUFSIZE - b->w;
1982
willy tarreau0f7af912005-12-17 12:21:26 +01001983 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001984#ifndef MSG_NOSIGNAL
1985 int skerr, lskerr;
1986#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001987 if (max == 0) {
1988 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001989 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001990 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001991 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01001992 tv_eternity(&s->swexpire);
1993 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01001994 return 0;
1995 }
1996
willy tarreauef900ab2005-12-17 12:52:52 +01001997
willy tarreau3242e862005-12-17 12:27:53 +01001998#ifndef MSG_NOSIGNAL
1999 lskerr=sizeof(skerr);
2000 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2001 if (skerr)
2002 ret = -1;
2003 else
2004 ret = send(fd, b->w, max, MSG_DONTWAIT);
2005#else
willy tarreau0f7af912005-12-17 12:21:26 +01002006 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002007#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002008 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002009 if (ret > 0) {
2010 b->l -= ret;
2011 b->w += ret;
2012
2013 s->res_sw = RES_DATA;
2014
2015 if (b->w == b->data + BUFSIZE) {
2016 b->w = b->data; /* wrap around the buffer */
2017 }
2018 }
2019 else if (ret == 0) {
2020 /* nothing written, just make as if we were never called */
2021 // s->res_sw = RES_NULL;
2022 return 0;
2023 }
2024 else if (errno == EAGAIN) /* ignore EAGAIN */
2025 return 0;
2026 else {
2027 s->res_sw = RES_ERROR;
2028 fdtab[fd].state = FD_STERROR;
2029 }
2030 }
2031 else {
2032 s->res_sw = RES_ERROR;
2033 fdtab[fd].state = FD_STERROR;
2034 }
2035
willy tarreaub1ff9db2005-12-17 13:51:03 +01002036 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002037 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002038 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2039 s->srexpire = s->swexpire;
2040 }
willy tarreau0f7af912005-12-17 12:21:26 +01002041 else
2042 tv_eternity(&s->swexpire);
2043
willy tarreau5cbea6f2005-12-17 12:48:26 +01002044 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002045 return 0;
2046}
2047
2048
2049/*
willy tarreaue39cd132005-12-17 13:00:18 +01002050 * returns a message to the client ; the connection is shut down for read,
2051 * and the request is cleared so that no server connection can be initiated.
2052 * The client must be in a valid state for this (HEADER, DATA ...).
2053 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002054 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002055 */
2056void client_retnclose(struct session *s, int len, const char *msg) {
2057 FD_CLR(s->cli_fd, StaticReadEvent);
2058 FD_SET(s->cli_fd, StaticWriteEvent);
2059 tv_eternity(&s->crexpire);
2060 shutdown(s->cli_fd, SHUT_RD);
2061 s->cli_state = CL_STSHUTR;
2062 strcpy(s->rep->data, msg);
2063 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002064 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002065 s->rep->r += len;
2066 s->req->l = 0;
2067}
2068
2069
2070/*
2071 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002072 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002073 */
2074void client_return(struct session *s, int len, const char *msg) {
2075 strcpy(s->rep->data, msg);
2076 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002077 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002078 s->rep->r += len;
2079 s->req->l = 0;
2080}
2081
willy tarreau9fe663a2005-12-17 13:02:59 +01002082/*
2083 * send a log for the session when we have enough info about it
2084 */
2085void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002086 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002087 struct proxy *p = s->proxy;
2088 int log;
2089 char *uri;
2090 char *pxid;
2091 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002092 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002093
2094 /* This is a first attempt at a better logging system.
2095 * For now, we rely on send_log() to provide the date, although it obviously
2096 * is the date of the log and not of the request, and most fields are not
2097 * computed.
2098 */
2099
willy tarreaua1598082005-12-17 13:08:06 +01002100 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002101
willy tarreau8a86dbf2005-12-18 00:45:59 +01002102 if (s->cli_addr.ss_family == AF_INET)
2103 inet_ntop(AF_INET,
2104 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2105 pn, sizeof(pn));
2106 else
2107 inet_ntop(AF_INET6,
2108 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2109 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002110
willy tarreauc1cae632005-12-17 14:12:23 +01002111 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002112 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002113 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002114
willy tarreauc1cae632005-12-17 14:12:23 +01002115 tm = localtime(&s->logs.tv_accept.tv_sec);
2116 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002117 char tmpline[MAX_SYSLOG_LEN], *h;
2118 int hdr;
2119
2120 h = tmpline;
2121 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2122 *(h++) = ' ';
2123 *(h++) = '{';
2124 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2125 if (hdr)
2126 *(h++) = '|';
2127 if (s->req_cap[hdr] != NULL)
2128 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2129 }
2130 *(h++) = '}';
2131 }
2132
2133 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2134 *(h++) = ' ';
2135 *(h++) = '{';
2136 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2137 if (hdr)
2138 *(h++) = '|';
2139 if (s->rsp_cap[hdr] != NULL)
2140 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2141 }
2142 *(h++) = '}';
2143 }
2144
2145 if (h < tmpline + sizeof(tmpline) - 4) {
2146 *(h++) = ' ';
2147 *(h++) = '"';
2148 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2149 *(h++) = '"';
2150 }
2151 *h = '\0';
2152
2153 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 +01002154 pn,
2155 (s->cli_addr.ss_family == AF_INET) ?
2156 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2157 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002158 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2159 tm->tm_hour, tm->tm_min, tm->tm_sec,
2160 pxid, srv,
2161 s->logs.t_request,
2162 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2163 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002164 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2165 s->logs.status,
2166 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002167 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2168 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002169 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2170 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2171 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2172 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau4302f492005-12-18 01:00:37 +01002173 tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002174 }
2175 else {
willy tarreau25c4ea52005-12-18 00:49:49 +01002176 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 +01002177 pn,
2178 (s->cli_addr.ss_family == AF_INET) ?
2179 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2180 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002181 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2182 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002183 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002184 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002185 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2186 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002187 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01002188 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01002189 }
2190
2191 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002192}
2193
willy tarreaue39cd132005-12-17 13:00:18 +01002194
2195/*
willy tarreau0f7af912005-12-17 12:21:26 +01002196 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002197 * to an accept. It tries to accept as many connections as possible.
2198 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002199 */
2200int event_accept(int fd) {
2201 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002202 struct session *s;
2203 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002204 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002205
willy tarreau5cbea6f2005-12-17 12:48:26 +01002206 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002207 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002208 int laddr = sizeof(addr);
2209 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2210 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002211
willy tarreau5cbea6f2005-12-17 12:48:26 +01002212 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2213 Alert("out of memory in event_accept().\n");
2214 FD_CLR(fd, StaticReadEvent);
2215 p->state = PR_STIDLE;
2216 close(cfd);
2217 return 0;
2218 }
willy tarreau0f7af912005-12-17 12:21:26 +01002219
willy tarreau5cbea6f2005-12-17 12:48:26 +01002220 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2221 Alert("out of memory in event_accept().\n");
2222 FD_CLR(fd, StaticReadEvent);
2223 p->state = PR_STIDLE;
2224 close(cfd);
2225 pool_free(session, s);
2226 return 0;
2227 }
willy tarreau0f7af912005-12-17 12:21:26 +01002228
willy tarreau5cbea6f2005-12-17 12:48:26 +01002229 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002230 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002231 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2232 close(cfd);
2233 pool_free(task, t);
2234 pool_free(session, s);
2235 return 0;
2236 }
willy tarreau0f7af912005-12-17 12:21:26 +01002237
willy tarreau5cbea6f2005-12-17 12:48:26 +01002238 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2239 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2240 (char *) &one, sizeof(one)) == -1)) {
2241 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2242 close(cfd);
2243 pool_free(task, t);
2244 pool_free(session, s);
2245 return 0;
2246 }
willy tarreau0f7af912005-12-17 12:21:26 +01002247
willy tarreau9fe663a2005-12-17 13:02:59 +01002248 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2249 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2250 t->state = TASK_IDLE;
2251 t->process = process_session;
2252 t->context = s;
2253
2254 s->task = t;
2255 s->proxy = p;
2256 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2257 s->srv_state = SV_STIDLE;
2258 s->req = s->rep = NULL; /* will be allocated later */
2259 s->flags = 0;
willy tarreau97f58572005-12-18 00:53:44 +01002260
willy tarreau9fe663a2005-12-17 13:02:59 +01002261 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2262 s->cli_fd = cfd;
2263 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002264 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002265 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002266
2267 s->logs.logwait = p->to_log;
2268 s->logs.tv_accept = now;
2269 s->logs.t_request = -1;
2270 s->logs.t_connect = -1;
2271 s->logs.t_data = -1;
2272 s->logs.t_close = 0;
2273 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002274 s->logs.cli_cookie = NULL;
2275 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002276 s->logs.status = -1;
2277 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002278
willy tarreau2f6ba652005-12-17 13:57:42 +01002279 s->uniq_id = totalconn;
2280
willy tarreau4302f492005-12-18 01:00:37 +01002281 if (p->nb_req_cap > 0) {
2282 if ((s->req_cap =
2283 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2284 == NULL) { /* no memory */
2285 close(cfd); /* nothing can be done for this fd without memory */
2286 pool_free(task, t);
2287 pool_free(session, s);
2288 return 0;
2289 }
2290 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2291 }
2292 else
2293 s->req_cap = NULL;
2294
2295 if (p->nb_rsp_cap > 0) {
2296 if ((s->rsp_cap =
2297 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2298 == NULL) { /* no memory */
2299 if (s->req_cap != NULL)
2300 pool_free_to(p->req_cap_pool, s->req_cap);
2301 close(cfd); /* nothing can be done for this fd without memory */
2302 pool_free(task, t);
2303 pool_free(session, s);
2304 return 0;
2305 }
2306 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2307 }
2308 else
2309 s->rsp_cap = NULL;
2310
willy tarreau5cbea6f2005-12-17 12:48:26 +01002311 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2312 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002313 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002314 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002315
willy tarreau5cbea6f2005-12-17 12:48:26 +01002316 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002317 if (addr.ss_family != AF_INET ||
2318 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002319 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002320
willy tarreau9fe663a2005-12-17 13:02:59 +01002321 if (p->to_log) {
2322 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002323 if (s->logs.logwait & LW_CLIP)
2324 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002325 sess_log(s);
2326 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002327 else if (s->cli_addr.ss_family == AF_INET) {
2328 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2329 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2330 sn, sizeof(sn)) &&
2331 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2332 pn, sizeof(pn))) {
2333 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2334 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2335 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2336 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2337 }
2338 }
2339 else {
2340 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2341 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2342 sn, sizeof(sn)) &&
2343 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2344 pn, sizeof(pn))) {
2345 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2346 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2347 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2348 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2349 }
2350 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002351 }
willy tarreau0f7af912005-12-17 12:21:26 +01002352
willy tarreau982249e2005-12-18 00:57:06 +01002353 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002354 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002355 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002356 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002357 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002358 if (addr.ss_family != AF_INET ||
2359 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002360 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002361
willy tarreau8a86dbf2005-12-18 00:45:59 +01002362 if (s->cli_addr.ss_family == AF_INET) {
2363 char pn[INET_ADDRSTRLEN];
2364 inet_ntop(AF_INET,
2365 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2366 pn, sizeof(pn));
2367
2368 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2369 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2370 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2371 }
2372 else {
2373 char pn[INET6_ADDRSTRLEN];
2374 inet_ntop(AF_INET6,
2375 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2376 pn, sizeof(pn));
2377
2378 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2379 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2380 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2381 }
2382
willy tarreauef900ab2005-12-17 12:52:52 +01002383 write(1, trash, len);
2384 }
willy tarreau0f7af912005-12-17 12:21:26 +01002385
willy tarreau5cbea6f2005-12-17 12:48:26 +01002386 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002387 if (s->rsp_cap != NULL)
2388 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2389 if (s->req_cap != NULL)
2390 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002391 close(cfd); /* nothing can be done for this fd without memory */
2392 pool_free(task, t);
2393 pool_free(session, s);
2394 return 0;
2395 }
willy tarreau4302f492005-12-18 01:00:37 +01002396
willy tarreau5cbea6f2005-12-17 12:48:26 +01002397 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002398 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002399 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2400 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002401 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002402 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002403
willy tarreau5cbea6f2005-12-17 12:48:26 +01002404 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2405 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002406 if (s->rsp_cap != NULL)
2407 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2408 if (s->req_cap != NULL)
2409 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002410 close(cfd); /* nothing can be done for this fd without memory */
2411 pool_free(task, t);
2412 pool_free(session, s);
2413 return 0;
2414 }
2415 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002416 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002417 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 +01002418
willy tarreau5cbea6f2005-12-17 12:48:26 +01002419 fdtab[cfd].read = &event_cli_read;
2420 fdtab[cfd].write = &event_cli_write;
2421 fdtab[cfd].owner = t;
2422 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002423
willy tarreau5cbea6f2005-12-17 12:48:26 +01002424 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002425 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2426 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2427 else
2428 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002429 }
2430 else {
2431 FD_SET(cfd, StaticReadEvent);
2432 }
2433
2434 fd_insert(cfd);
2435
2436 tv_eternity(&s->cnexpire);
2437 tv_eternity(&s->srexpire);
2438 tv_eternity(&s->swexpire);
2439 tv_eternity(&s->cwexpire);
2440
2441 if (s->proxy->clitimeout)
2442 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2443 else
2444 tv_eternity(&s->crexpire);
2445
2446 t->expire = s->crexpire;
2447
2448 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002449
2450 if (p->mode != PR_MODE_HEALTH)
2451 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002452
2453 p->nbconn++;
2454 actconn++;
2455 totalconn++;
2456
2457 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2458 } /* end of while (p->nbconn < p->maxconn) */
2459 return 0;
2460}
willy tarreau0f7af912005-12-17 12:21:26 +01002461
willy tarreau0f7af912005-12-17 12:21:26 +01002462
willy tarreau5cbea6f2005-12-17 12:48:26 +01002463/*
2464 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002465 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2466 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002467 * or -1 if an error occured.
2468 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002469int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002470 struct task *t = fdtab[fd].owner;
2471 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002472
willy tarreau5cbea6f2005-12-17 12:48:26 +01002473 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002474 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002475 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002476 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002477 if (skerr)
2478 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002479 else {
2480 if (s->proxy->options & PR_O_HTTP_CHK) {
2481 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002482 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002483 * so we'll send the request, and won't wake the checker up now.
2484 */
2485#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002486 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002487#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002488 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002489#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002490 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002491 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2492 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2493 return 0;
2494 }
2495 else
2496 s->result = -1;
2497 }
2498 else {
2499 /* good TCP connection is enough */
2500 s->result = 1;
2501 }
2502 }
2503
2504 task_wakeup(&rq, t);
2505 return 0;
2506}
2507
willy tarreau0f7af912005-12-17 12:21:26 +01002508
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002509/*
2510 * This function is used only for server health-checks. It handles
2511 * the server's reply to an HTTP request. It returns 1 if the server replies
2512 * 2xx or 3xx (valid responses), or -1 in other cases.
2513 */
2514int event_srv_chk_r(int fd) {
2515 char reply[64];
2516 int len;
2517 struct task *t = fdtab[fd].owner;
2518 struct server *s = t->context;
2519
2520 int skerr, lskerr;
2521 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002522
2523 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002524#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002525 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2526 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002527 len = recv(fd, reply, sizeof(reply), 0);
2528#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002529 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2530 * but the connection was closed on the remote end. Fortunately, recv still
2531 * works correctly and we don't need to do the getsockopt() on linux.
2532 */
2533 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002534#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002535 if ((len >= sizeof("HTTP/1.0 000")) &&
2536 !memcmp(reply, "HTTP/1.", 7) &&
2537 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2538 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002539
2540 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002541 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002542 return 0;
2543}
2544
2545
2546/*
2547 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2548 * and moves <end> just after the end of <str>.
2549 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2550 * the shift value (positive or negative) is returned.
2551 * If there's no space left, the move is not done.
2552 *
2553 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002554int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002555 int delta;
2556 int len;
2557
2558 len = strlen(str);
2559 delta = len - (end - pos);
2560
2561 if (delta + b->r >= b->data + BUFSIZE)
2562 return 0; /* no space left */
2563
2564 /* first, protect the end of the buffer */
2565 memmove(end + delta, end, b->data + b->l - end);
2566
2567 /* now, copy str over pos */
2568 memcpy(pos, str,len);
2569
willy tarreau5cbea6f2005-12-17 12:48:26 +01002570 /* we only move data after the displaced zone */
2571 if (b->r > pos) b->r += delta;
2572 if (b->w > pos) b->w += delta;
2573 if (b->h > pos) b->h += delta;
2574 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002575 b->l += delta;
2576
2577 return delta;
2578}
2579
willy tarreau8337c6b2005-12-17 13:41:01 +01002580/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002581 * len is 0.
2582 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002583int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002584 int delta;
2585
2586 delta = len - (end - pos);
2587
2588 if (delta + b->r >= b->data + BUFSIZE)
2589 return 0; /* no space left */
2590
2591 /* first, protect the end of the buffer */
2592 memmove(end + delta, end, b->data + b->l - end);
2593
2594 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002595 if (len)
2596 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002597
willy tarreau5cbea6f2005-12-17 12:48:26 +01002598 /* we only move data after the displaced zone */
2599 if (b->r > pos) b->r += delta;
2600 if (b->w > pos) b->w += delta;
2601 if (b->h > pos) b->h += delta;
2602 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002603 b->l += delta;
2604
2605 return delta;
2606}
2607
2608
2609int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2610 char *old_dst = dst;
2611
2612 while (*str) {
2613 if (*str == '\\') {
2614 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002615 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002616 int len, num;
2617
2618 num = *str - '0';
2619 str++;
2620
willy tarreau8a86dbf2005-12-18 00:45:59 +01002621 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002622 len = matches[num].rm_eo - matches[num].rm_so;
2623 memcpy(dst, src + matches[num].rm_so, len);
2624 dst += len;
2625 }
2626
2627 }
2628 else if (*str == 'x') {
2629 unsigned char hex1, hex2;
2630 str++;
2631
2632 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2633
2634 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2635 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2636 *dst++ = (hex1<<4) + hex2;
2637 }
2638 else
2639 *dst++ = *str++;
2640 }
2641 else
2642 *dst++ = *str++;
2643 }
2644 *dst = 0;
2645 return dst - old_dst;
2646}
2647
willy tarreau9fe663a2005-12-17 13:02:59 +01002648
willy tarreau0f7af912005-12-17 12:21:26 +01002649/*
2650 * manages the client FSM and its socket. BTW, it also tries to handle the
2651 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2652 * 0 else.
2653 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002654int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002655 int s = t->srv_state;
2656 int c = t->cli_state;
2657 struct buffer *req = t->req;
2658 struct buffer *rep = t->rep;
2659
willy tarreau750a4722005-12-17 13:21:24 +01002660#ifdef DEBUG_FULL
2661 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2662#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002663 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2664 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2665 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2666 //);
2667 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002668 /* now parse the partial (or complete) headers */
2669 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2670 char *ptr;
2671 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002672
willy tarreau5cbea6f2005-12-17 12:48:26 +01002673 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002674
willy tarreau0f7af912005-12-17 12:21:26 +01002675 /* look for the end of the current header */
2676 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2677 ptr++;
2678
willy tarreau5cbea6f2005-12-17 12:48:26 +01002679 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002680 int line, len;
2681 /* we can only get here after an end of headers */
2682 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002683
willy tarreaue39cd132005-12-17 13:00:18 +01002684 if (t->flags & SN_CLDENY) {
2685 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002686 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002687 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002688 if (!(t->flags & SN_ERR_MASK))
2689 t->flags |= SN_ERR_PRXCOND;
2690 if (!(t->flags & SN_FINST_MASK))
2691 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002692 return 1;
2693 }
2694
willy tarreau5cbea6f2005-12-17 12:48:26 +01002695 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002696 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2697 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002698 }
willy tarreau0f7af912005-12-17 12:21:26 +01002699
willy tarreau9fe663a2005-12-17 13:02:59 +01002700 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002701 if (t->cli_addr.ss_family == AF_INET) {
2702 unsigned char *pn;
2703 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
2704 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2705 pn[0], pn[1], pn[2], pn[3]);
2706 buffer_replace2(req, req->h, req->h, trash, len);
2707 }
2708 else if (t->cli_addr.ss_family == AF_INET6) {
2709 char pn[INET6_ADDRSTRLEN];
2710 inet_ntop(AF_INET6,
2711 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2712 pn, sizeof(pn));
2713 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
2714 buffer_replace2(req, req->h, req->h, trash, len);
2715 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002716 }
2717
willy tarreau25c4ea52005-12-18 00:49:49 +01002718 /* add a "connection: close" line if needed */
2719 if (t->proxy->options & PR_O_HTTP_CLOSE)
2720 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
2721
willy tarreau982249e2005-12-18 00:57:06 +01002722 if (!memcmp(req->data, "POST ", 5)) {
2723 /* this is a POST request, which is not cacheable by default */
2724 t->flags |= SN_POST;
2725 }
willy tarreaucd878942005-12-17 13:27:43 +01002726
willy tarreau5cbea6f2005-12-17 12:48:26 +01002727 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002728 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002729
willy tarreau750a4722005-12-17 13:21:24 +01002730 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002731 /* FIXME: we'll set the client in a wait state while we try to
2732 * connect to the server. Is this really needed ? wouldn't it be
2733 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002734 //FD_CLR(t->cli_fd, StaticReadEvent);
2735 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002736
2737 /* FIXME: if we break here (as up to 1.1.23), having the client
2738 * shutdown its connection can lead to an abort further.
2739 * it's better to either return 1 or even jump directly to the
2740 * data state which will save one schedule.
2741 */
2742 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002743
2744 if (!t->proxy->clitimeout ||
2745 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2746 /* If the client has no timeout, or if the server is not ready yet,
2747 * and we know for sure that it can expire, then it's cleaner to
2748 * disable the timeout on the client side so that too low values
2749 * cannot make the sessions abort too early.
2750 */
2751 tv_eternity(&t->crexpire);
2752
willy tarreau197e8ec2005-12-17 14:10:59 +01002753 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002754 }
willy tarreau0f7af912005-12-17 12:21:26 +01002755
willy tarreau5cbea6f2005-12-17 12:48:26 +01002756 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2757 if (ptr > req->r - 2) {
2758 /* this is a partial header, let's wait for more to come */
2759 req->lr = ptr;
2760 break;
2761 }
willy tarreau0f7af912005-12-17 12:21:26 +01002762
willy tarreau5cbea6f2005-12-17 12:48:26 +01002763 /* now we know that *ptr is either \r or \n,
2764 * and that there are at least 1 char after it.
2765 */
2766 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2767 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2768 else
2769 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002770
willy tarreau5cbea6f2005-12-17 12:48:26 +01002771 /*
2772 * now we know that we have a full header ; we can do whatever
2773 * we want with these pointers :
2774 * req->h = beginning of header
2775 * ptr = end of header (first \r or \n)
2776 * req->lr = beginning of next line (next rep->h)
2777 * req->r = end of data (not used at this stage)
2778 */
willy tarreau0f7af912005-12-17 12:21:26 +01002779
willy tarreau8337c6b2005-12-17 13:41:01 +01002780 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002781 /* we have a complete HTTP request that we must log */
2782 int urilen;
2783
willy tarreaua1598082005-12-17 13:08:06 +01002784 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002785 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002786 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002787 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002788 if (!(t->flags & SN_ERR_MASK))
2789 t->flags |= SN_ERR_PRXCOND;
2790 if (!(t->flags & SN_FINST_MASK))
2791 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002792 return 1;
2793 }
2794
2795 urilen = ptr - req->h;
2796 if (urilen >= REQURI_LEN)
2797 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002798 memcpy(t->logs.uri, req->h, urilen);
2799 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002800
willy tarreaua1598082005-12-17 13:08:06 +01002801 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002802 sess_log(t);
2803 }
willy tarreau4302f492005-12-18 01:00:37 +01002804 else if (t->logs.logwait & LW_REQHDR) {
2805 struct cap_hdr *h;
2806 int len;
2807 for (h = t->proxy->req_cap; h; h = h->next) {
2808 if ((h->namelen + 2 <= ptr - req->h) &&
2809 (req->h[h->namelen] == ':') &&
2810 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
2811
2812 if (t->req_cap[h->index] == NULL)
2813 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
2814
2815 len = ptr - (req->h + h->namelen + 2);
2816 if (len > h->len)
2817 len = h->len;
2818
2819 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
2820 t->req_cap[h->index][len]=0;
2821 }
2822 }
2823
2824 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002825
willy tarreau5cbea6f2005-12-17 12:48:26 +01002826 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002827
willy tarreau982249e2005-12-18 00:57:06 +01002828 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002829 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002830 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 +01002831 max = ptr - req->h;
2832 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002833 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002834 trash[len++] = '\n';
2835 write(1, trash, len);
2836 }
willy tarreau0f7af912005-12-17 12:21:26 +01002837
willy tarreau25c4ea52005-12-18 00:49:49 +01002838
2839 /* remove "connection: " if needed */
2840 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
2841 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
2842 delete_header = 1;
2843 }
2844
willy tarreau5cbea6f2005-12-17 12:48:26 +01002845 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01002846 if (!delete_header && t->proxy->req_exp != NULL
2847 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002848 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849 char term;
2850
2851 term = *ptr;
2852 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002853 exp = t->proxy->req_exp;
2854 do {
2855 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2856 switch (exp->action) {
2857 case ACT_ALLOW:
2858 if (!(t->flags & SN_CLDENY))
2859 t->flags |= SN_CLALLOW;
2860 break;
2861 case ACT_REPLACE:
2862 if (!(t->flags & SN_CLDENY)) {
2863 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2864 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2865 }
2866 break;
2867 case ACT_REMOVE:
2868 if (!(t->flags & SN_CLDENY))
2869 delete_header = 1;
2870 break;
2871 case ACT_DENY:
2872 if (!(t->flags & SN_CLALLOW))
2873 t->flags |= SN_CLDENY;
2874 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002875 case ACT_PASS: /* we simply don't deny this one */
2876 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002877 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002878 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002879 }
willy tarreaue39cd132005-12-17 13:00:18 +01002880 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002881 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002882 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002883
willy tarreau240afa62005-12-17 13:14:35 +01002884 /* Now look for cookies. Conforming to RFC2109, we have to support
2885 * attributes whose name begin with a '$', and associate them with
2886 * the right cookie, if we want to delete this cookie.
2887 * So there are 3 cases for each cookie read :
2888 * 1) it's a special attribute, beginning with a '$' : ignore it.
2889 * 2) it's a server id cookie that we *MAY* want to delete : save
2890 * some pointers on it (last semi-colon, beginning of cookie...)
2891 * 3) it's an application cookie : we *MAY* have to delete a previous
2892 * "special" cookie.
2893 * At the end of loop, if a "special" cookie remains, we may have to
2894 * remove it. If no application cookie persists in the header, we
2895 * *MUST* delete it
2896 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002897 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002898 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01002899 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002900 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002901 char *del_colon, *del_cookie, *colon;
2902 int app_cookies;
2903
willy tarreau5cbea6f2005-12-17 12:48:26 +01002904 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002905 colon = p1;
2906 /* del_cookie == NULL => nothing to be deleted */
2907 del_colon = del_cookie = NULL;
2908 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002909
2910 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002911 /* skip spaces and colons, but keep an eye on these ones */
2912 while (p1 < ptr) {
2913 if (*p1 == ';' || *p1 == ',')
2914 colon = p1;
2915 else if (!isspace((int)*p1))
2916 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002917 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002918 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002919
2920 if (p1 == ptr)
2921 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002922
2923 /* p1 is at the beginning of the cookie name */
2924 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002925 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002926 p2++;
2927
2928 if (p2 == ptr)
2929 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002930
2931 p3 = p2 + 1; /* skips the '=' sign */
2932 if (p3 == ptr)
2933 break;
2934
willy tarreau240afa62005-12-17 13:14:35 +01002935 p4 = p3;
2936 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002937 p4++;
2938
2939 /* here, we have the cookie name between p1 and p2,
2940 * and its value between p3 and p4.
2941 * we can process it.
2942 */
2943
willy tarreau240afa62005-12-17 13:14:35 +01002944 if (*p1 == '$') {
2945 /* skip this one */
2946 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002947 else {
2948 /* first, let's see if we want to capture it */
2949 if (t->proxy->capture_name != NULL &&
2950 t->logs.cli_cookie == NULL &&
2951 (p4 - p1 >= t->proxy->capture_namelen) &&
2952 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2953 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002954
willy tarreau8337c6b2005-12-17 13:41:01 +01002955 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2956 Alert("HTTP logging : out of memory.\n");
2957 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002958
willy tarreau8337c6b2005-12-17 13:41:01 +01002959 if (log_len > t->proxy->capture_len)
2960 log_len = t->proxy->capture_len;
2961 memcpy(t->logs.cli_cookie, p1, log_len);
2962 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002963 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002964
2965 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2966 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2967 /* Cool... it's the right one */
2968 struct server *srv = t->proxy->srv;
2969
2970 while (srv &&
2971 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2972 srv = srv->next;
2973 }
2974
willy tarreau036e1ce2005-12-17 13:46:33 +01002975 if (!srv) {
2976 t->flags &= ~SN_CK_MASK;
2977 t->flags |= SN_CK_INVALID;
2978 }
2979 else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002980 /* we found the server and it's usable */
willy tarreau036e1ce2005-12-17 13:46:33 +01002981 t->flags &= ~SN_CK_MASK;
2982 t->flags |= SN_CK_VALID | SN_DIRECT;
willy tarreau8337c6b2005-12-17 13:41:01 +01002983 t->srv = srv;
2984 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002985 else {
2986 t->flags &= ~SN_CK_MASK;
2987 t->flags |= SN_CK_DOWN;
2988 }
2989
willy tarreau8337c6b2005-12-17 13:41:01 +01002990 /* if this cookie was set in insert+indirect mode, then it's better that the
2991 * server never sees it.
2992 */
2993 if (del_cookie == NULL &&
2994 (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 +01002995 del_cookie = p1;
2996 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002997 }
willy tarreau240afa62005-12-17 13:14:35 +01002998 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002999 else {
3000 /* now we know that we must keep this cookie since it's
3001 * not ours. But if we wanted to delete our cookie
3002 * earlier, we cannot remove the complete header, but we
3003 * can remove the previous block itself.
3004 */
3005 app_cookies++;
3006
3007 if (del_cookie != NULL) {
3008 buffer_replace2(req, del_cookie, p1, NULL, 0);
3009 p4 -= (p1 - del_cookie);
3010 ptr -= (p1 - del_cookie);
3011 del_cookie = del_colon = NULL;
3012 }
willy tarreau240afa62005-12-17 13:14:35 +01003013 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003014 }
willy tarreau240afa62005-12-17 13:14:35 +01003015
willy tarreau5cbea6f2005-12-17 12:48:26 +01003016 /* we'll have to look for another cookie ... */
3017 p1 = p4;
3018 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003019
3020 /* There's no more cookie on this line.
3021 * We may have marked the last one(s) for deletion.
3022 * We must do this now in two ways :
3023 * - if there is no app cookie, we simply delete the header ;
3024 * - if there are app cookies, we must delete the end of the
3025 * string properly, including the colon/semi-colon before
3026 * the cookie name.
3027 */
3028 if (del_cookie != NULL) {
3029 if (app_cookies) {
3030 buffer_replace2(req, del_colon, ptr, NULL, 0);
3031 /* WARNING! <ptr> becomes invalid for now. If some code
3032 * below needs to rely on it before the end of the global
3033 * header loop, we need to correct it with this code :
3034 * ptr = del_colon;
3035 */
3036 }
3037 else
3038 delete_header = 1;
3039 }
3040 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003041
3042 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003043 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003044 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003045 }
willy tarreau240afa62005-12-17 13:14:35 +01003046 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3047
willy tarreau5cbea6f2005-12-17 12:48:26 +01003048 req->h = req->lr;
3049 } /* while (req->lr < req->r) */
3050
3051 /* end of header processing (even if incomplete) */
3052
willy tarreauef900ab2005-12-17 12:52:52 +01003053 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3054 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3055 * full. We cannot loop here since event_cli_read will disable it only if
3056 * req->l == rlim-data
3057 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003058 FD_SET(t->cli_fd, StaticReadEvent);
3059 if (t->proxy->clitimeout)
3060 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3061 else
3062 tv_eternity(&t->crexpire);
3063 }
3064
willy tarreaue39cd132005-12-17 13:00:18 +01003065 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003066 * won't be able to free more later, so the session will never terminate.
3067 */
willy tarreaue39cd132005-12-17 13:00:18 +01003068 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003069 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003070 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003071 if (!(t->flags & SN_ERR_MASK))
3072 t->flags |= SN_ERR_PRXCOND;
3073 if (!(t->flags & SN_FINST_MASK))
3074 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003075 return 1;
3076 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003077 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003078 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003079 tv_eternity(&t->crexpire);
3080 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003081 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003082 if (!(t->flags & SN_ERR_MASK))
3083 t->flags |= SN_ERR_CLICL;
3084 if (!(t->flags & SN_FINST_MASK))
3085 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003086 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003087 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003088 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3089
3090 /* read timeout : give up with an error message.
3091 */
3092 t->logs.status = 408;
3093 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003094 if (!(t->flags & SN_ERR_MASK))
3095 t->flags |= SN_ERR_CLITO;
3096 if (!(t->flags & SN_FINST_MASK))
3097 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003098 return 1;
3099 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003100
3101 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003102 }
3103 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003104 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003105 /* FIXME: this error handling is partly buggy because we always report
3106 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3107 * or HEADER phase. BTW, it's not logical to expire the client while
3108 * we're waiting for the server to connect.
3109 */
willy tarreau0f7af912005-12-17 12:21:26 +01003110 /* read or write error */
3111 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003112 tv_eternity(&t->crexpire);
3113 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003114 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003115 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003116 if (!(t->flags & SN_ERR_MASK))
3117 t->flags |= SN_ERR_CLICL;
3118 if (!(t->flags & SN_FINST_MASK))
3119 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003120 return 1;
3121 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003122 /* last read, or end of server write */
3123 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003124 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003125 tv_eternity(&t->crexpire);
3126 shutdown(t->cli_fd, SHUT_RD);
3127 t->cli_state = CL_STSHUTR;
3128 return 1;
3129 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003130 /* last server read and buffer empty */
3131 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003132 FD_CLR(t->cli_fd, StaticWriteEvent);
3133 tv_eternity(&t->cwexpire);
3134 shutdown(t->cli_fd, SHUT_WR);
3135 t->cli_state = CL_STSHUTW;
3136 return 1;
3137 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003138 /* read timeout */
3139 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3140 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003141 tv_eternity(&t->crexpire);
3142 shutdown(t->cli_fd, SHUT_RD);
3143 t->cli_state = CL_STSHUTR;
3144 if (!(t->flags & SN_ERR_MASK))
3145 t->flags |= SN_ERR_CLITO;
3146 if (!(t->flags & SN_FINST_MASK))
3147 t->flags |= SN_FINST_D;
3148 return 1;
3149 }
3150 /* write timeout */
3151 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3152 FD_CLR(t->cli_fd, StaticWriteEvent);
3153 tv_eternity(&t->cwexpire);
3154 shutdown(t->cli_fd, SHUT_WR);
3155 t->cli_state = CL_STSHUTW;
3156 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003157 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003158 if (!(t->flags & SN_FINST_MASK))
3159 t->flags |= SN_FINST_D;
3160 return 1;
3161 }
willy tarreau0f7af912005-12-17 12:21:26 +01003162
willy tarreauc58fc692005-12-17 14:13:08 +01003163 if (req->l >= req->rlim - req->data) {
3164 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003165 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003166 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003167 FD_CLR(t->cli_fd, StaticReadEvent);
3168 tv_eternity(&t->crexpire);
3169 }
3170 }
3171 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003172 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003173 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3174 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003175 if (!t->proxy->clitimeout ||
3176 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3177 /* If the client has no timeout, or if the server not ready yet, and we
3178 * know for sure that it can expire, then it's cleaner to disable the
3179 * timeout on the client side so that too low values cannot make the
3180 * sessions abort too early.
3181 */
willy tarreau0f7af912005-12-17 12:21:26 +01003182 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003183 else
3184 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003185 }
3186 }
3187
3188 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003189 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003190 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3191 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3192 tv_eternity(&t->cwexpire);
3193 }
3194 }
3195 else { /* buffer not empty */
3196 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3197 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003198 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003199 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003200 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3201 t->crexpire = t->cwexpire;
3202 }
willy tarreau0f7af912005-12-17 12:21:26 +01003203 else
3204 tv_eternity(&t->cwexpire);
3205 }
3206 }
3207 return 0; /* other cases change nothing */
3208 }
3209 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003210 if (t->res_cw == RES_ERROR) {
3211 tv_eternity(&t->cwexpire);
3212 fd_delete(t->cli_fd);
3213 t->cli_state = CL_STCLOSE;
3214 if (!(t->flags & SN_ERR_MASK))
3215 t->flags |= SN_ERR_CLICL;
3216 if (!(t->flags & SN_FINST_MASK))
3217 t->flags |= SN_FINST_D;
3218 return 1;
3219 }
3220 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003221 tv_eternity(&t->cwexpire);
3222 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003223 t->cli_state = CL_STCLOSE;
3224 return 1;
3225 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003226 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3227 tv_eternity(&t->cwexpire);
3228 fd_delete(t->cli_fd);
3229 t->cli_state = CL_STCLOSE;
3230 if (!(t->flags & SN_ERR_MASK))
3231 t->flags |= SN_ERR_CLITO;
3232 if (!(t->flags & SN_FINST_MASK))
3233 t->flags |= SN_FINST_D;
3234 return 1;
3235 }
willy tarreau0f7af912005-12-17 12:21:26 +01003236 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003237 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003238 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3239 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3240 tv_eternity(&t->cwexpire);
3241 }
3242 }
3243 else { /* buffer not empty */
3244 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3245 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003246 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003247 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003248 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3249 t->crexpire = t->cwexpire;
3250 }
willy tarreau0f7af912005-12-17 12:21:26 +01003251 else
3252 tv_eternity(&t->cwexpire);
3253 }
3254 }
3255 return 0;
3256 }
3257 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003258 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003259 tv_eternity(&t->crexpire);
3260 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003261 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003262 if (!(t->flags & SN_ERR_MASK))
3263 t->flags |= SN_ERR_CLICL;
3264 if (!(t->flags & SN_FINST_MASK))
3265 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003266 return 1;
3267 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003268 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3269 tv_eternity(&t->crexpire);
3270 fd_delete(t->cli_fd);
3271 t->cli_state = CL_STCLOSE;
3272 return 1;
3273 }
3274 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3275 tv_eternity(&t->crexpire);
3276 fd_delete(t->cli_fd);
3277 t->cli_state = CL_STCLOSE;
3278 if (!(t->flags & SN_ERR_MASK))
3279 t->flags |= SN_ERR_CLITO;
3280 if (!(t->flags & SN_FINST_MASK))
3281 t->flags |= SN_FINST_D;
3282 return 1;
3283 }
willy tarreauef900ab2005-12-17 12:52:52 +01003284 else if (req->l >= req->rlim - req->data) {
3285 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003286 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003287 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003288 FD_CLR(t->cli_fd, StaticReadEvent);
3289 tv_eternity(&t->crexpire);
3290 }
3291 }
3292 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003293 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003294 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3295 FD_SET(t->cli_fd, StaticReadEvent);
3296 if (t->proxy->clitimeout)
3297 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3298 else
3299 tv_eternity(&t->crexpire);
3300 }
3301 }
3302 return 0;
3303 }
3304 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003305 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003306 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003307 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 +01003308 write(1, trash, len);
3309 }
3310 return 0;
3311 }
3312 return 0;
3313}
3314
3315
3316/*
3317 * manages the server FSM and its socket. It returns 1 if a state has changed
3318 * (and a resync may be needed), 0 else.
3319 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003320int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003321 int s = t->srv_state;
3322 int c = t->cli_state;
3323 struct buffer *req = t->req;
3324 struct buffer *rep = t->rep;
3325
willy tarreau750a4722005-12-17 13:21:24 +01003326#ifdef DEBUG_FULL
3327 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3328#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003329 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3330 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3331 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3332 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003333 if (s == SV_STIDLE) {
3334 if (c == CL_STHEADERS)
3335 return 0; /* stay in idle, waiting for data to reach the client side */
3336 else if (c == CL_STCLOSE ||
3337 c == CL_STSHUTW ||
3338 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3339 tv_eternity(&t->cnexpire);
3340 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003341 if (!(t->flags & SN_ERR_MASK))
3342 t->flags |= SN_ERR_CLICL;
3343 if (!(t->flags & SN_FINST_MASK))
3344 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003345 return 1;
3346 }
3347 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003348 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003349 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3350 t->srv_state = SV_STCONN;
3351 }
3352 else { /* try again */
3353 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003354 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003355 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003356 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003357 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3358 t->flags &= ~SN_CK_MASK;
3359 t->flags |= SN_CK_DOWN;
3360 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003361 }
3362
3363 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003364 t->srv_state = SV_STCONN;
3365 break;
3366 }
3367 }
3368 if (t->conn_retries < 0) {
3369 /* if conn_retries < 0 or other error, let's abort */
3370 tv_eternity(&t->cnexpire);
3371 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003372 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003373 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003374 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003375 if (!(t->flags & SN_ERR_MASK))
3376 t->flags |= SN_ERR_SRVCL;
3377 if (!(t->flags & SN_FINST_MASK))
3378 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003379 }
3380 }
3381 return 1;
3382 }
3383 }
3384 else if (s == SV_STCONN) { /* connection in progress */
3385 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3386 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3387 return 0; /* nothing changed */
3388 }
3389 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3390 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3391 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003392 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003393 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003394 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003395 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003396 if (t->conn_retries >= 0) {
3397 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003398 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003399 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003400 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3401 t->flags &= ~SN_CK_MASK;
3402 t->flags |= SN_CK_DOWN;
3403 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003404 }
3405 if (connect_server(t) == 0)
3406 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003407 }
3408 /* if conn_retries < 0 or other error, let's abort */
3409 tv_eternity(&t->cnexpire);
3410 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003411 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003412 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003413 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003414 if (!(t->flags & SN_ERR_MASK))
3415 t->flags |= SN_ERR_SRVCL;
3416 if (!(t->flags & SN_FINST_MASK))
3417 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003418 return 1;
3419 }
3420 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003421 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003422
willy tarreau0f7af912005-12-17 12:21:26 +01003423 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003424 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003425 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003426 tv_eternity(&t->swexpire);
3427 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003428 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003429 if (t->proxy->srvtimeout) {
3430 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3431 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3432 t->srexpire = t->swexpire;
3433 }
3434 else
3435 tv_eternity(&t->swexpire);
3436 }
willy tarreau0f7af912005-12-17 12:21:26 +01003437
3438 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3439 FD_SET(t->srv_fd, StaticReadEvent);
3440 if (t->proxy->srvtimeout)
3441 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3442 else
3443 tv_eternity(&t->srexpire);
3444
3445 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003446 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01003447
3448 /* if the user wants to log as soon as possible, without counting
3449 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003450 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003451 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
3452 sess_log(t);
3453 }
willy tarreau0f7af912005-12-17 12:21:26 +01003454 }
willy tarreauef900ab2005-12-17 12:52:52 +01003455 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003456 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003457 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3458 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003459 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003460 return 1;
3461 }
3462 }
3463 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003464 /* now parse the partial (or complete) headers */
3465 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3466 char *ptr;
3467 int delete_header;
3468
3469 ptr = rep->lr;
3470
3471 /* look for the end of the current header */
3472 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3473 ptr++;
3474
3475 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003476 int line, len;
3477
3478 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01003479
3480 /* first, we'll block if security checks have caught nasty things */
3481 if (t->flags & SN_CACHEABLE) {
3482 if ((t->flags & SN_CACHE_COOK) &&
3483 (t->flags & SN_SCK_ANY) &&
3484 (t->proxy->options & PR_O_CHK_CACHE)) {
3485
3486 /* we're in presence of a cacheable response containing
3487 * a set-cookie header. We'll block it as requested by
3488 * the 'checkcache' option, and send an alert.
3489 */
3490 tv_eternity(&t->srexpire);
3491 tv_eternity(&t->swexpire);
3492 fd_delete(t->srv_fd);
3493 t->srv_state = SV_STCLOSE;
3494 t->logs.status = 502;
3495 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3496 if (!(t->flags & SN_ERR_MASK))
3497 t->flags |= SN_ERR_PRXCOND;
3498 if (!(t->flags & SN_FINST_MASK))
3499 t->flags |= SN_FINST_H;
3500
3501 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3502 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3503
3504 return 1;
3505 }
3506 }
3507
willy tarreau982249e2005-12-18 00:57:06 +01003508 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
3509 if (t->flags & SN_SVDENY) {
3510 tv_eternity(&t->srexpire);
3511 tv_eternity(&t->swexpire);
3512 fd_delete(t->srv_fd);
3513 t->srv_state = SV_STCLOSE;
3514 t->logs.status = 502;
3515 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3516 if (!(t->flags & SN_ERR_MASK))
3517 t->flags |= SN_ERR_PRXCOND;
3518 if (!(t->flags & SN_FINST_MASK))
3519 t->flags |= SN_FINST_H;
3520 return 1;
3521 }
3522
willy tarreau5cbea6f2005-12-17 12:48:26 +01003523 /* we'll have something else to do here : add new headers ... */
3524
willy tarreaucd878942005-12-17 13:27:43 +01003525 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3526 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003527 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003528 * insert a set-cookie here, except if we want to insert only on POST
3529 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003530 */
willy tarreau750a4722005-12-17 13:21:24 +01003531 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003532 t->proxy->cookie_name,
3533 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003534
willy tarreau036e1ce2005-12-17 13:46:33 +01003535 t->flags |= SN_SCK_INSERTED;
3536
willy tarreau750a4722005-12-17 13:21:24 +01003537 /* Here, we will tell an eventual cache on the client side that we don't
3538 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3539 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3540 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3541 */
willy tarreau240afa62005-12-17 13:14:35 +01003542 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003543 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3544 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003545
willy tarreau750a4722005-12-17 13:21:24 +01003546 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003547 }
3548
3549 /* headers to be added */
3550 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003551 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3552 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003553 }
3554
willy tarreau25c4ea52005-12-18 00:49:49 +01003555 /* add a "connection: close" line if needed */
3556 if (t->proxy->options & PR_O_HTTP_CLOSE)
3557 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
3558
willy tarreau5cbea6f2005-12-17 12:48:26 +01003559 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003560 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003561 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01003562
3563 /* if the user wants to log as soon as possible, without counting
3564 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003565 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003566 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
3567 t->logs.bytes = rep->h - rep->data;
3568 sess_log(t);
3569 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003570 break;
3571 }
3572
3573 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3574 if (ptr > rep->r - 2) {
3575 /* this is a partial header, let's wait for more to come */
3576 rep->lr = ptr;
3577 break;
3578 }
3579
3580 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3581 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3582
3583 /* now we know that *ptr is either \r or \n,
3584 * and that there are at least 1 char after it.
3585 */
3586 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3587 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3588 else
3589 rep->lr = ptr + 2; /* \r\n or \n\r */
3590
3591 /*
3592 * now we know that we have a full header ; we can do whatever
3593 * we want with these pointers :
3594 * rep->h = beginning of header
3595 * ptr = end of header (first \r or \n)
3596 * rep->lr = beginning of next line (next rep->h)
3597 * rep->r = end of data (not used at this stage)
3598 */
3599
willy tarreaua1598082005-12-17 13:08:06 +01003600
willy tarreau982249e2005-12-18 00:57:06 +01003601 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01003602 t->logs.logwait &= ~LW_RESP;
3603 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01003604 switch (t->logs.status) {
3605 case 200:
3606 case 203:
3607 case 206:
3608 case 300:
3609 case 301:
3610 case 410:
3611 /* RFC2616 @13.4:
3612 * "A response received with a status code of
3613 * 200, 203, 206, 300, 301 or 410 MAY be stored
3614 * by a cache (...) unless a cache-control
3615 * directive prohibits caching."
3616 *
3617 * RFC2616 @9.5: POST method :
3618 * "Responses to this method are not cacheable,
3619 * unless the response includes appropriate
3620 * Cache-Control or Expires header fields."
3621 */
3622 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
3623 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
3624 break;
3625 default:
3626 break;
3627 }
willy tarreau4302f492005-12-18 01:00:37 +01003628 }
3629 else if (t->logs.logwait & LW_RSPHDR) {
3630 struct cap_hdr *h;
3631 int len;
3632 for (h = t->proxy->rsp_cap; h; h = h->next) {
3633 if ((h->namelen + 2 <= ptr - rep->h) &&
3634 (rep->h[h->namelen] == ':') &&
3635 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
3636
3637 if (t->rsp_cap[h->index] == NULL)
3638 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3639
3640 len = ptr - (rep->h + h->namelen + 2);
3641 if (len > h->len)
3642 len = h->len;
3643
3644 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
3645 t->rsp_cap[h->index][len]=0;
3646 }
3647 }
3648
willy tarreaua1598082005-12-17 13:08:06 +01003649 }
3650
willy tarreau5cbea6f2005-12-17 12:48:26 +01003651 delete_header = 0;
3652
willy tarreau982249e2005-12-18 00:57:06 +01003653 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003654 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003655 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 +01003656 max = ptr - rep->h;
3657 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003658 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003659 trash[len++] = '\n';
3660 write(1, trash, len);
3661 }
3662
willy tarreau25c4ea52005-12-18 00:49:49 +01003663 /* remove "connection: " if needed */
3664 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3665 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
3666 delete_header = 1;
3667 }
3668
willy tarreau5cbea6f2005-12-17 12:48:26 +01003669 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003670 if (!delete_header && t->proxy->rsp_exp != NULL
3671 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003672 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003673 char term;
3674
3675 term = *ptr;
3676 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003677 exp = t->proxy->rsp_exp;
3678 do {
3679 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3680 switch (exp->action) {
3681 case ACT_ALLOW:
3682 if (!(t->flags & SN_SVDENY))
3683 t->flags |= SN_SVALLOW;
3684 break;
3685 case ACT_REPLACE:
3686 if (!(t->flags & SN_SVDENY)) {
3687 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3688 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3689 }
3690 break;
3691 case ACT_REMOVE:
3692 if (!(t->flags & SN_SVDENY))
3693 delete_header = 1;
3694 break;
3695 case ACT_DENY:
3696 if (!(t->flags & SN_SVALLOW))
3697 t->flags |= SN_SVDENY;
3698 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003699 case ACT_PASS: /* we simply don't deny this one */
3700 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003701 }
3702 break;
3703 }
willy tarreaue39cd132005-12-17 13:00:18 +01003704 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003705 *ptr = term; /* restore the string terminator */
3706 }
3707
willy tarreau97f58572005-12-18 00:53:44 +01003708 /* check for cache-control: or pragma: headers */
3709 if (!delete_header && (t->flags & SN_CACHEABLE)) {
3710 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
3711 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3712 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
3713 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01003714 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01003715 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3716 else {
3717 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01003718 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01003719 t->flags &= ~SN_CACHE_COOK;
3720 }
3721 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003722 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01003723 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003724 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01003725 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3726 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003727 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01003728 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01003729 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
3730 (rep->h + 25 == ptr || rep->h[25] == ',')) {
3731 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3732 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
3733 (rep->h + 21 == ptr || rep->h[21] == ',')) {
3734 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01003735 }
3736 }
3737 }
3738
willy tarreau5cbea6f2005-12-17 12:48:26 +01003739 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003740 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3741 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau906b2682005-12-17 13:49:52 +01003742 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003743 char *p1, *p2, *p3, *p4;
3744
willy tarreau97f58572005-12-18 00:53:44 +01003745 t->flags |= SN_SCK_ANY;
3746
willy tarreau5cbea6f2005-12-17 12:48:26 +01003747 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3748
3749 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003750 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003751 p1++;
3752
3753 if (p1 == ptr || *p1 == ';') /* end of cookie */
3754 break;
3755
3756 /* p1 is at the beginning of the cookie name */
3757 p2 = p1;
3758
3759 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3760 p2++;
3761
3762 if (p2 == ptr || *p2 == ';') /* next cookie */
3763 break;
3764
3765 p3 = p2 + 1; /* skips the '=' sign */
3766 if (p3 == ptr)
3767 break;
3768
3769 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003770 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003771 p4++;
3772
3773 /* here, we have the cookie name between p1 and p2,
3774 * and its value between p3 and p4.
3775 * we can process it.
3776 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003777
3778 /* first, let's see if we want to capture it */
3779 if (t->proxy->capture_name != NULL &&
3780 t->logs.srv_cookie == NULL &&
3781 (p4 - p1 >= t->proxy->capture_namelen) &&
3782 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3783 int log_len = p4 - p1;
3784
3785 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3786 Alert("HTTP logging : out of memory.\n");
3787 }
3788
3789 if (log_len > t->proxy->capture_len)
3790 log_len = t->proxy->capture_len;
3791 memcpy(t->logs.srv_cookie, p1, log_len);
3792 t->logs.srv_cookie[log_len] = 0;
3793 }
3794
3795 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3796 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003797 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003798 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003799
3800 /* If the cookie is in insert mode on a known server, we'll delete
3801 * this occurrence because we'll insert another one later.
3802 * We'll delete it too if the "indirect" option is set and we're in
3803 * a direct access. */
3804 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003805 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003806 /* this header must be deleted */
3807 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003808 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003809 }
3810 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3811 /* replace bytes p3->p4 with the cookie name associated
3812 * with this server since we know it.
3813 */
3814 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003815 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003816 }
3817 break;
3818 }
3819 else {
3820 // fprintf(stderr,"Ignoring unknown cookie : ");
3821 // write(2, p1, p2-p1);
3822 // fprintf(stderr," = ");
3823 // write(2, p3, p4-p3);
3824 // fprintf(stderr,"\n");
3825 }
3826 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3827 } /* we're now at the end of the cookie value */
3828 } /* end of cookie processing */
3829
willy tarreau97f58572005-12-18 00:53:44 +01003830 /* check for any set-cookie in case we check for cacheability */
3831 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
3832 (t->proxy->options & PR_O_CHK_CACHE) &&
3833 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
3834 t->flags |= SN_SCK_ANY;
3835 }
3836
willy tarreau5cbea6f2005-12-17 12:48:26 +01003837 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003838 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003839 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003840
willy tarreau5cbea6f2005-12-17 12:48:26 +01003841 rep->h = rep->lr;
3842 } /* while (rep->lr < rep->r) */
3843
3844 /* end of header processing (even if incomplete) */
3845
willy tarreauef900ab2005-12-17 12:52:52 +01003846 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3847 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3848 * full. We cannot loop here since event_srv_read will disable it only if
3849 * rep->l == rlim-data
3850 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003851 FD_SET(t->srv_fd, StaticReadEvent);
3852 if (t->proxy->srvtimeout)
3853 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3854 else
3855 tv_eternity(&t->srexpire);
3856 }
willy tarreau0f7af912005-12-17 12:21:26 +01003857
willy tarreau8337c6b2005-12-17 13:41:01 +01003858 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003859 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003860 tv_eternity(&t->srexpire);
3861 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003862 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003863 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003864 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003865 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003866 if (!(t->flags & SN_ERR_MASK))
3867 t->flags |= SN_ERR_SRVCL;
3868 if (!(t->flags & SN_FINST_MASK))
3869 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003870 return 1;
3871 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003872 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003873 * since we are in header mode, if there's no space left for headers, we
3874 * won't be able to free more later, so the session will never terminate.
3875 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003876 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 +01003877 FD_CLR(t->srv_fd, StaticReadEvent);
3878 tv_eternity(&t->srexpire);
3879 shutdown(t->srv_fd, SHUT_RD);
3880 t->srv_state = SV_STSHUTR;
3881 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003882 }
3883 /* read timeout : return a 504 to the client.
3884 */
3885 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3886 tv_eternity(&t->srexpire);
3887 tv_eternity(&t->swexpire);
3888 fd_delete(t->srv_fd);
3889 t->srv_state = SV_STCLOSE;
3890 t->logs.status = 504;
3891 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003892 if (!(t->flags & SN_ERR_MASK))
3893 t->flags |= SN_ERR_SRVTO;
3894 if (!(t->flags & SN_FINST_MASK))
3895 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003896 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003897
3898 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003899 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003900 /* FIXME!!! here, we don't want to switch to SHUTW if the
3901 * client shuts read too early, because we may still have
3902 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01003903 * The side-effect is that if the client completely closes its
3904 * connection during SV_STHEADER, the connection to the server
3905 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01003906 */
willy tarreau036e1ce2005-12-17 13:46:33 +01003907 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003908 FD_CLR(t->srv_fd, StaticWriteEvent);
3909 tv_eternity(&t->swexpire);
3910 shutdown(t->srv_fd, SHUT_WR);
3911 t->srv_state = SV_STSHUTW;
3912 return 1;
3913 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003914 /* write timeout */
3915 /* FIXME!!! here, we don't want to switch to SHUTW if the
3916 * client shuts read too early, because we may still have
3917 * some work to do on the headers.
3918 */
3919 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3920 FD_CLR(t->srv_fd, StaticWriteEvent);
3921 tv_eternity(&t->swexpire);
3922 shutdown(t->srv_fd, SHUT_WR);
3923 t->srv_state = SV_STSHUTW;
3924 if (!(t->flags & SN_ERR_MASK))
3925 t->flags |= SN_ERR_SRVTO;
3926 if (!(t->flags & SN_FINST_MASK))
3927 t->flags |= SN_FINST_H;
3928 return 1;
3929 }
willy tarreau0f7af912005-12-17 12:21:26 +01003930
3931 if (req->l == 0) {
3932 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3933 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3934 tv_eternity(&t->swexpire);
3935 }
3936 }
3937 else { /* client buffer not empty */
3938 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3939 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003940 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003941 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003942 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3943 t->srexpire = t->swexpire;
3944 }
willy tarreau0f7af912005-12-17 12:21:26 +01003945 else
3946 tv_eternity(&t->swexpire);
3947 }
3948 }
3949
willy tarreau5cbea6f2005-12-17 12:48:26 +01003950 /* be nice with the client side which would like to send a complete header
3951 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3952 * would read all remaining data at once ! The client should not write past rep->lr
3953 * when the server is in header state.
3954 */
3955 //return header_processed;
3956 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003957 }
3958 else if (s == SV_STDATA) {
3959 /* read or write error */
3960 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003961 tv_eternity(&t->srexpire);
3962 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003963 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003964 t->srv_state = SV_STCLOSE;
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_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003969 return 1;
3970 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003971 /* last read, or end of client write */
3972 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003973 FD_CLR(t->srv_fd, StaticReadEvent);
3974 tv_eternity(&t->srexpire);
3975 shutdown(t->srv_fd, SHUT_RD);
3976 t->srv_state = SV_STSHUTR;
3977 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01003978 }
3979 /* end of client read and no more data to send */
3980 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
3981 FD_CLR(t->srv_fd, StaticWriteEvent);
3982 tv_eternity(&t->swexpire);
3983 shutdown(t->srv_fd, SHUT_WR);
3984 t->srv_state = SV_STSHUTW;
3985 return 1;
3986 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003987 /* read timeout */
3988 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3989 FD_CLR(t->srv_fd, StaticReadEvent);
3990 tv_eternity(&t->srexpire);
3991 shutdown(t->srv_fd, SHUT_RD);
3992 t->srv_state = SV_STSHUTR;
3993 if (!(t->flags & SN_ERR_MASK))
3994 t->flags |= SN_ERR_SRVTO;
3995 if (!(t->flags & SN_FINST_MASK))
3996 t->flags |= SN_FINST_D;
3997 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003998 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003999 /* write timeout */
4000 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004001 FD_CLR(t->srv_fd, StaticWriteEvent);
4002 tv_eternity(&t->swexpire);
4003 shutdown(t->srv_fd, SHUT_WR);
4004 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004005 if (!(t->flags & SN_ERR_MASK))
4006 t->flags |= SN_ERR_SRVTO;
4007 if (!(t->flags & SN_FINST_MASK))
4008 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004009 return 1;
4010 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004011
4012 /* recompute request time-outs */
4013 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004014 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4015 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4016 tv_eternity(&t->swexpire);
4017 }
4018 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004019 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004020 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4021 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004022 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004023 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004024 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4025 t->srexpire = t->swexpire;
4026 }
willy tarreau0f7af912005-12-17 12:21:26 +01004027 else
4028 tv_eternity(&t->swexpire);
4029 }
4030 }
4031
willy tarreaub1ff9db2005-12-17 13:51:03 +01004032 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004033 if (rep->l == BUFSIZE) { /* no room to read more data */
4034 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4035 FD_CLR(t->srv_fd, StaticReadEvent);
4036 tv_eternity(&t->srexpire);
4037 }
4038 }
4039 else {
4040 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4041 FD_SET(t->srv_fd, StaticReadEvent);
4042 if (t->proxy->srvtimeout)
4043 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4044 else
4045 tv_eternity(&t->srexpire);
4046 }
4047 }
4048
4049 return 0; /* other cases change nothing */
4050 }
4051 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004052 if (t->res_sw == RES_ERROR) {
4053 //FD_CLR(t->srv_fd, StaticWriteEvent);
4054 tv_eternity(&t->swexpire);
4055 fd_delete(t->srv_fd);
4056 //close(t->srv_fd);
4057 t->srv_state = SV_STCLOSE;
4058 if (!(t->flags & SN_ERR_MASK))
4059 t->flags |= SN_ERR_SRVCL;
4060 if (!(t->flags & SN_FINST_MASK))
4061 t->flags |= SN_FINST_D;
4062 return 1;
4063 }
4064 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004065 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004066 tv_eternity(&t->swexpire);
4067 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004068 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004069 t->srv_state = SV_STCLOSE;
4070 return 1;
4071 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004072 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4073 //FD_CLR(t->srv_fd, StaticWriteEvent);
4074 tv_eternity(&t->swexpire);
4075 fd_delete(t->srv_fd);
4076 //close(t->srv_fd);
4077 t->srv_state = SV_STCLOSE;
4078 if (!(t->flags & SN_ERR_MASK))
4079 t->flags |= SN_ERR_SRVTO;
4080 if (!(t->flags & SN_FINST_MASK))
4081 t->flags |= SN_FINST_D;
4082 return 1;
4083 }
willy tarreau0f7af912005-12-17 12:21:26 +01004084 else if (req->l == 0) {
4085 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4086 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4087 tv_eternity(&t->swexpire);
4088 }
4089 }
4090 else { /* buffer not empty */
4091 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4092 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004093 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004094 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004095 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4096 t->srexpire = t->swexpire;
4097 }
willy tarreau0f7af912005-12-17 12:21:26 +01004098 else
4099 tv_eternity(&t->swexpire);
4100 }
4101 }
4102 return 0;
4103 }
4104 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004105 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004106 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004107 tv_eternity(&t->srexpire);
4108 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004109 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004110 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004111 if (!(t->flags & SN_ERR_MASK))
4112 t->flags |= SN_ERR_SRVCL;
4113 if (!(t->flags & SN_FINST_MASK))
4114 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004115 return 1;
4116 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004117 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4118 //FD_CLR(t->srv_fd, StaticReadEvent);
4119 tv_eternity(&t->srexpire);
4120 fd_delete(t->srv_fd);
4121 //close(t->srv_fd);
4122 t->srv_state = SV_STCLOSE;
4123 return 1;
4124 }
4125 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4126 //FD_CLR(t->srv_fd, StaticReadEvent);
4127 tv_eternity(&t->srexpire);
4128 fd_delete(t->srv_fd);
4129 //close(t->srv_fd);
4130 t->srv_state = SV_STCLOSE;
4131 if (!(t->flags & SN_ERR_MASK))
4132 t->flags |= SN_ERR_SRVTO;
4133 if (!(t->flags & SN_FINST_MASK))
4134 t->flags |= SN_FINST_D;
4135 return 1;
4136 }
willy tarreau0f7af912005-12-17 12:21:26 +01004137 else if (rep->l == BUFSIZE) { /* no room to read more data */
4138 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4139 FD_CLR(t->srv_fd, StaticReadEvent);
4140 tv_eternity(&t->srexpire);
4141 }
4142 }
4143 else {
4144 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4145 FD_SET(t->srv_fd, StaticReadEvent);
4146 if (t->proxy->srvtimeout)
4147 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4148 else
4149 tv_eternity(&t->srexpire);
4150 }
4151 }
4152 return 0;
4153 }
4154 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004155 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004156 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004157 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 +01004158 write(1, trash, len);
4159 }
4160 return 0;
4161 }
4162 return 0;
4163}
4164
4165
willy tarreau5cbea6f2005-12-17 12:48:26 +01004166/* Processes the client and server jobs of a session task, then
4167 * puts it back to the wait queue in a clean state, or
4168 * cleans up its resources if it must be deleted. Returns
4169 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01004170 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004171int process_session(struct task *t) {
4172 struct session *s = t->context;
4173 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004174
willy tarreau5cbea6f2005-12-17 12:48:26 +01004175 do {
4176 fsm_resync = 0;
4177 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4178 fsm_resync |= process_cli(s);
4179 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4180 fsm_resync |= process_srv(s);
4181 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4182 } while (fsm_resync);
4183
4184 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004185 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004186 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004187
willy tarreau5cbea6f2005-12-17 12:48:26 +01004188 tv_min(&min1, &s->crexpire, &s->cwexpire);
4189 tv_min(&min2, &s->srexpire, &s->swexpire);
4190 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004191 tv_min(&t->expire, &min1, &min2);
4192
4193 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004194 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004195
willy tarreau5cbea6f2005-12-17 12:48:26 +01004196 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004197 }
4198
willy tarreau5cbea6f2005-12-17 12:48:26 +01004199 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004200 actconn--;
4201
willy tarreau982249e2005-12-18 00:57:06 +01004202 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004203 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004204 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 +01004205 write(1, trash, len);
4206 }
4207
willy tarreau750a4722005-12-17 13:21:24 +01004208 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004209 if (s->rep != NULL)
4210 s->logs.bytes = s->rep->total;
4211
willy tarreau9fe663a2005-12-17 13:02:59 +01004212 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004213 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004214 sess_log(s);
4215
willy tarreau0f7af912005-12-17 12:21:26 +01004216 /* the task MUST not be in the run queue anymore */
4217 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004218 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004219 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004220 return -1; /* rest in peace for eternity */
4221}
4222
4223
4224
4225/*
4226 * manages a server health-check. Returns
4227 * the time the task accepts to wait, or -1 for infinity.
4228 */
4229int process_chk(struct task *t) {
4230 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004231 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004232 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004233
willy tarreauef900ab2005-12-17 12:52:52 +01004234 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004235
4236 if (fd < 0) { /* no check currently running */
4237 //fprintf(stderr, "process_chk: 2\n");
4238 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4239 task_queue(t); /* restore t to its place in the task list */
4240 return tv_remain(&now, &t->expire);
4241 }
4242
4243 /* we'll initiate a new check */
4244 s->result = 0; /* no result yet */
4245 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004246 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004247 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4248 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4249 //fprintf(stderr, "process_chk: 3\n");
4250
willy tarreaua41a8b42005-12-17 14:02:24 +01004251 /* we'll connect to the check port on the server */
4252 sa = s->addr;
4253 sa.sin_port = htons(s->check_port);
4254
willy tarreau036e1ce2005-12-17 13:46:33 +01004255 /* allow specific binding */
4256 if (s->proxy->options & PR_O_BIND_SRC &&
4257 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4258 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
4259 close(fd);
4260 s->result = -1;
4261 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004262 else if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004263 /* OK, connection in progress or established */
4264
4265 //fprintf(stderr, "process_chk: 4\n");
4266
4267 s->curfd = fd; /* that's how we know a test is in progress ;-) */
4268 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004269 fdtab[fd].read = &event_srv_chk_r;
4270 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004271 fdtab[fd].state = FD_STCONN; /* connection in progress */
4272 FD_SET(fd, StaticWriteEvent); /* for connect status */
4273 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004274 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4275 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004276 task_queue(t); /* restore t to its place in the task list */
4277 return tv_remain(&now, &t->expire);
4278 }
4279 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
4280 s->result = -1; /* a real error */
4281 }
4282 }
4283 //fprintf(stderr, "process_chk: 5\n");
4284 close(fd);
4285 }
4286
4287 if (!s->result) { /* nothing done */
4288 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004289 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004290 task_queue(t); /* restore t to its place in the task list */
4291 return tv_remain(&now, &t->expire);
4292 }
4293
4294 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01004295 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004296 s->health--; /* still good */
4297 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004298 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01004299 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004300 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004301 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01004302
willy tarreaudd07e972005-12-18 00:48:48 +01004303 if (find_server(s->proxy) == NULL) {
4304 Alert("Proxy %s has no server available !\n", s->proxy->id);
4305 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4306 }
4307 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004308 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004309 }
4310
4311 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004312 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4313 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004314 }
4315 else {
4316 //fprintf(stderr, "process_chk: 8\n");
4317 /* there was a test running */
4318 if (s->result > 0) { /* good server detected */
4319 //fprintf(stderr, "process_chk: 9\n");
4320 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01004321 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004322 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004323 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004324 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004325 }
willy tarreauef900ab2005-12-17 12:52:52 +01004326
willy tarreaue47c8d72005-12-17 12:55:52 +01004327 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004328 s->state |= SRV_RUNNING;
4329 }
willy tarreauef900ab2005-12-17 12:52:52 +01004330 s->curfd = -1; /* no check running anymore */
4331 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004332 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004333 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004334 }
4335 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
4336 //fprintf(stderr, "process_chk: 10\n");
4337 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01004338 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004339 s->health--; /* still good */
4340 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004341 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01004342
willy tarreaudd07e972005-12-18 00:48:48 +01004343 if (s->health == s->rise) {
4344 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004345 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01004346
4347 if (find_server(s->proxy) == NULL) {
4348 Alert("Proxy %s has no server available !\n", s->proxy->id);
4349 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4350 }
willy tarreau535ae7a2005-12-17 12:58:00 +01004351 }
willy tarreauef900ab2005-12-17 12:52:52 +01004352
willy tarreau5cbea6f2005-12-17 12:48:26 +01004353 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004354 }
4355 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01004356 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004357 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004358 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004359 }
4360 /* if result is 0 and there's no timeout, we have to wait again */
4361 }
4362 //fprintf(stderr, "process_chk: 11\n");
4363 s->result = 0;
4364 task_queue(t); /* restore t to its place in the task list */
4365 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01004366}
4367
4368
willy tarreau5cbea6f2005-12-17 12:48:26 +01004369
willy tarreau0f7af912005-12-17 12:21:26 +01004370#if STATTIME > 0
4371int stats(void);
4372#endif
4373
4374/*
4375 * Main select() loop.
4376 */
4377
4378void select_loop() {
4379 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01004380 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01004381 int status;
4382 int fd,i;
4383 struct timeval delta;
4384 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004385 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01004386
willy tarreau5cbea6f2005-12-17 12:48:26 +01004387 tv_now(&now);
4388
4389 while (1) {
4390 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01004391
willy tarreau5cbea6f2005-12-17 12:48:26 +01004392 /* look for expired tasks and add them to the run queue.
4393 */
4394 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4395 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4396 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01004397 if (t->state & TASK_RUNNING)
4398 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004399
4400 /* wakeup expired entries. It doesn't matter if they are
4401 * already running because of a previous event
4402 */
4403 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01004404 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004405 task_wakeup(&rq, t);
4406 }
4407 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004408 /* first non-runnable task. Use its expiration date as an upper bound */
4409 int temp_time = tv_remain(&now, &t->expire);
4410 if (temp_time)
4411 next_time = temp_time;
4412 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004413 break;
4414 }
4415 }
4416
4417 /* process each task in the run queue now. Each task may be deleted
4418 * since we only use tnext.
4419 */
4420 tnext = rq;
4421 while ((t = tnext) != NULL) {
4422 int temp_time;
4423
4424 tnext = t->rqnext;
4425 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01004426 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004427 temp_time = t->process(t);
4428 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01004429 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004430 }
4431
willy tarreauef900ab2005-12-17 12:52:52 +01004432 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01004433
4434 /* maintain all proxies in a consistent state. This should quickly become a task */
4435 time2 = maintain_proxies();
4436 next_time = MINTIME(time2, next_time);
4437
4438 /* stop when there's no connection left and we don't allow them anymore */
4439 if (!actconn && listeners == 0)
4440 break;
4441
willy tarreau0f7af912005-12-17 12:21:26 +01004442
4443#if STATTIME > 0
4444 time2 = stats();
4445 // fprintf(stderr," stats = %d\n", time2);
4446 next_time = MINTIME(time2, next_time);
4447#endif
4448
willy tarreau5cbea6f2005-12-17 12:48:26 +01004449 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01004450 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004451 /* to avoid eventual select loops due to timer precision */
4452 next_time += SCHEDULER_RESOLUTION;
4453 delta.tv_sec = next_time / 1000;
4454 delta.tv_usec = (next_time % 1000) * 1000;
4455 }
4456 else if (next_time == 0) { /* allow select to return immediately when needed */
4457 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004458 }
4459
4460
4461 /* let's restore fdset state */
4462
4463 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004464 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004465 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
4466 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
4467 }
4468
4469// /* just a verification code, needs to be removed for performance */
4470// for (i=0; i<maxfd; i++) {
4471// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
4472// abort();
4473// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
4474// abort();
4475//
4476// }
4477
willy tarreau197e8ec2005-12-17 14:10:59 +01004478 status = select(maxfd,
4479 readnotnull ? ReadEvent : NULL,
4480 writenotnull ? WriteEvent : NULL,
4481 NULL,
4482 (next_time >= 0) ? &delta : NULL);
willy tarreau0f7af912005-12-17 12:21:26 +01004483
willy tarreau5cbea6f2005-12-17 12:48:26 +01004484 /* this is an experiment on the separation of the select work */
4485 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4486 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4487
willy tarreau0f7af912005-12-17 12:21:26 +01004488 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004489
willy tarreau0f7af912005-12-17 12:21:26 +01004490 if (status > 0) { /* must proceed with events */
4491
4492 int fds;
4493 char count;
4494
4495 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
4496 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
4497 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
4498
willy tarreau5cbea6f2005-12-17 12:48:26 +01004499 /* if we specify read first, the accepts and zero reads will be
4500 * seen first. Moreover, system buffers will be flushed faster.
4501 */
willy tarreau0f7af912005-12-17 12:21:26 +01004502 if (fdtab[fd].state == FD_STCLOSE)
4503 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01004504
4505 if (FD_ISSET(fd, ReadEvent))
4506 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004507
willy tarreau5cbea6f2005-12-17 12:48:26 +01004508 if (FD_ISSET(fd, WriteEvent))
4509 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004510 }
4511 }
4512 else {
4513 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
4514 }
willy tarreau0f7af912005-12-17 12:21:26 +01004515 }
4516}
4517
4518
4519#if STATTIME > 0
4520/*
4521 * Display proxy statistics regularly. It is designed to be called from the
4522 * select_loop().
4523 */
4524int stats(void) {
4525 static int lines;
4526 static struct timeval nextevt;
4527 static struct timeval lastevt;
4528 static struct timeval starttime = {0,0};
4529 unsigned long totaltime, deltatime;
4530 int ret;
4531
willy tarreau750a4722005-12-17 13:21:24 +01004532 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01004533 deltatime = (tv_diff(&lastevt, &now)?:1);
4534 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01004535
willy tarreau9fe663a2005-12-17 13:02:59 +01004536 if (global.mode & MODE_STATS) {
4537 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004538 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004539 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
4540 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004541 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004542 actconn, totalconn,
4543 stats_tsk_new, stats_tsk_good,
4544 stats_tsk_left, stats_tsk_right,
4545 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
4546 }
4547 }
4548
4549 tv_delayfrom(&nextevt, &now, STATTIME);
4550
4551 lastevt=now;
4552 }
4553 ret = tv_remain(&now, &nextevt);
4554 return ret;
4555}
4556#endif
4557
4558
4559/*
4560 * this function enables proxies when there are enough free sessions,
4561 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01004562 * select_loop(). It returns the time left before next expiration event
4563 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01004564 */
4565static int maintain_proxies(void) {
4566 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01004567 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004568 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01004569
4570 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004571 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01004572
4573 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01004574 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01004575 while (p) {
4576 if (p->nbconn < p->maxconn) {
4577 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004578 for (l = p->listen; l != NULL; l = l->next) {
4579 FD_SET(l->fd, StaticReadEvent);
4580 }
willy tarreau0f7af912005-12-17 12:21:26 +01004581 p->state = PR_STRUN;
4582 }
4583 }
4584 else {
4585 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004586 for (l = p->listen; l != NULL; l = l->next) {
4587 FD_CLR(l->fd, StaticReadEvent);
4588 }
willy tarreau0f7af912005-12-17 12:21:26 +01004589 p->state = PR_STIDLE;
4590 }
4591 }
4592 p = p->next;
4593 }
4594 }
4595 else { /* block all proxies */
4596 while (p) {
4597 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004598 for (l = p->listen; l != NULL; l = l->next) {
4599 FD_CLR(l->fd, StaticReadEvent);
4600 }
willy tarreau0f7af912005-12-17 12:21:26 +01004601 p->state = PR_STIDLE;
4602 }
4603 p = p->next;
4604 }
4605 }
4606
willy tarreau5cbea6f2005-12-17 12:48:26 +01004607 if (stopping) {
4608 p = proxy;
4609 while (p) {
4610 if (p->state != PR_STDISABLED) {
4611 int t;
4612 t = tv_remain(&now, &p->stop_time);
4613 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004614 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004615 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004616
willy tarreaua41a8b42005-12-17 14:02:24 +01004617 for (l = p->listen; l != NULL; l = l->next) {
4618 fd_delete(l->fd);
4619 listeners--;
4620 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004621 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004622 }
4623 else {
4624 tleft = MINTIME(t, tleft);
4625 }
4626 }
4627 p = p->next;
4628 }
4629 }
4630 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004631}
4632
4633/*
4634 * this function disables health-check servers so that the process will quickly be ignored
4635 * by load balancers.
4636 */
4637static void soft_stop(void) {
4638 struct proxy *p;
4639
4640 stopping = 1;
4641 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004642 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004643 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004644 if (p->state != PR_STDISABLED) {
4645 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004646 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004647 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004648 }
willy tarreau0f7af912005-12-17 12:21:26 +01004649 p = p->next;
4650 }
4651}
4652
4653/*
4654 * upon SIGUSR1, let's have a soft stop.
4655 */
4656void sig_soft_stop(int sig) {
4657 soft_stop();
4658 signal(sig, SIG_IGN);
4659}
4660
4661
willy tarreau8337c6b2005-12-17 13:41:01 +01004662/*
4663 * this function dumps every server's state when the process receives SIGHUP.
4664 */
4665void sig_dump_state(int sig) {
4666 struct proxy *p = proxy;
4667
4668 Warning("SIGHUP received, dumping servers states.\n");
4669 while (p) {
4670 struct server *s = p->srv;
4671
4672 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4673 while (s) {
4674 if (s->state & SRV_RUNNING) {
4675 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4676 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4677 }
4678 else {
4679 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4680 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4681 }
4682 s = s->next;
4683 }
willy tarreaudd07e972005-12-18 00:48:48 +01004684
4685 if (find_server(p) == NULL) {
4686 Warning("SIGHUP: proxy %s has no server available !\n", p);
4687 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
4688 }
4689
willy tarreau8337c6b2005-12-17 13:41:01 +01004690 p = p->next;
4691 }
4692 signal(sig, sig_dump_state);
4693}
4694
willy tarreau0f7af912005-12-17 12:21:26 +01004695void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004696 struct task *t, *tnext;
4697 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004698
willy tarreau5cbea6f2005-12-17 12:48:26 +01004699 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4700 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4701 tnext = t->next;
4702 s = t->context;
4703 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4704 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4705 "req=%d, rep=%d, clifd=%d\n",
4706 s, tv_remain(&now, &t->expire),
4707 s->cli_state,
4708 s->srv_state,
4709 FD_ISSET(s->cli_fd, StaticReadEvent),
4710 FD_ISSET(s->cli_fd, StaticWriteEvent),
4711 FD_ISSET(s->srv_fd, StaticReadEvent),
4712 FD_ISSET(s->srv_fd, StaticWriteEvent),
4713 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4714 );
willy tarreau0f7af912005-12-17 12:21:26 +01004715 }
4716}
4717
willy tarreaue39cd132005-12-17 13:00:18 +01004718void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4719 struct hdr_exp *exp;
4720
4721 while (*head != NULL)
4722 head = &(*head)->next;
4723
4724 exp = calloc(1, sizeof(struct hdr_exp));
4725
4726 exp->preg = preg;
4727 exp->replace = replace;
4728 exp->action = action;
4729 *head = exp;
4730}
4731
willy tarreau9fe663a2005-12-17 13:02:59 +01004732
willy tarreau0f7af912005-12-17 12:21:26 +01004733/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004734 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004735 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004736int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004737
willy tarreau9fe663a2005-12-17 13:02:59 +01004738 if (!strcmp(args[0], "global")) { /* new section */
4739 /* no option, nothing special to do */
4740 return 0;
4741 }
4742 else if (!strcmp(args[0], "daemon")) {
4743 global.mode |= MODE_DAEMON;
4744 }
4745 else if (!strcmp(args[0], "debug")) {
4746 global.mode |= MODE_DEBUG;
4747 }
4748 else if (!strcmp(args[0], "quiet")) {
4749 global.mode |= MODE_QUIET;
4750 }
4751 else if (!strcmp(args[0], "stats")) {
4752 global.mode |= MODE_STATS;
4753 }
4754 else if (!strcmp(args[0], "uid")) {
4755 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004756 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004757 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004758 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004759 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004760 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004761 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004762 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004763 global.uid = atol(args[1]);
4764 }
4765 else if (!strcmp(args[0], "gid")) {
4766 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004767 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004768 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004769 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004770 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004771 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004772 return -1;
4773 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004774 global.gid = atol(args[1]);
4775 }
4776 else if (!strcmp(args[0], "nbproc")) {
4777 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004778 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004779 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004781 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004782 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004783 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004784 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004785 global.nbproc = atol(args[1]);
4786 }
4787 else if (!strcmp(args[0], "maxconn")) {
4788 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004789 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004790 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004791 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004792 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004793 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004794 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004795 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004796 global.maxconn = atol(args[1]);
4797 }
4798 else if (!strcmp(args[0], "chroot")) {
4799 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004800 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004801 return 0;
4802 }
4803 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004804 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004805 return -1;
4806 }
4807 global.chroot = strdup(args[1]);
4808 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01004809 else if (!strcmp(args[0], "pidfile")) {
4810 if (global.pidfile != NULL) {
4811 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
4812 return 0;
4813 }
4814 if (*(args[1]) == 0) {
4815 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
4816 return -1;
4817 }
4818 global.pidfile = strdup(args[1]);
4819 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004820 else if (!strcmp(args[0], "log")) { /* syslog server address */
4821 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004822 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004823
4824 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004825 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004826 return -1;
4827 }
4828
4829 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4830 if (!strcmp(log_facilities[facility], args[2]))
4831 break;
4832
4833 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004834 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004835 exit(1);
4836 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004837
4838 level = 7; /* max syslog level = debug */
4839 if (*(args[3])) {
4840 while (level >= 0 && strcmp(log_levels[level], args[3]))
4841 level--;
4842 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004843 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004844 exit(1);
4845 }
4846 }
4847
willy tarreau9fe663a2005-12-17 13:02:59 +01004848 sa = str2sa(args[1]);
4849 if (!sa->sin_port)
4850 sa->sin_port = htons(SYSLOG_PORT);
4851
4852 if (global.logfac1 == -1) {
4853 global.logsrv1 = *sa;
4854 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004855 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004856 }
4857 else if (global.logfac2 == -1) {
4858 global.logsrv2 = *sa;
4859 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004860 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004861 }
4862 else {
4863 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4864 return -1;
4865 }
4866
4867 }
4868 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004869 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004870 return -1;
4871 }
4872 return 0;
4873}
4874
4875
willy tarreaua41a8b42005-12-17 14:02:24 +01004876void init_default_instance() {
4877 memset(&defproxy, 0, sizeof(defproxy));
4878 defproxy.mode = PR_MODE_TCP;
4879 defproxy.state = PR_STNEW;
4880 defproxy.maxconn = cfg_maxpconn;
4881 defproxy.conn_retries = CONN_RETRIES;
4882 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
4883}
4884
willy tarreau9fe663a2005-12-17 13:02:59 +01004885/*
4886 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4887 */
4888int cfg_parse_listen(char *file, int linenum, char **args) {
4889 static struct proxy *curproxy = NULL;
4890 struct server *newsrv = NULL;
4891
4892 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01004893 if (!*args[1]) {
4894 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
4895 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004896 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004897 return -1;
4898 }
4899
4900 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004901 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004902 return -1;
4903 }
4904 curproxy->next = proxy;
4905 proxy = curproxy;
4906 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01004907 if (strchr(args[2], ':') != NULL)
4908 curproxy->listen = str2listener(args[2], curproxy->listen);
4909
willy tarreau9fe663a2005-12-17 13:02:59 +01004910 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01004911 curproxy->state = defproxy.state;
4912 curproxy->maxconn = defproxy.maxconn;
4913 curproxy->conn_retries = defproxy.conn_retries;
4914 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004915
4916 if (defproxy.check_req)
4917 curproxy->check_req = strdup(defproxy.check_req);
4918 curproxy->check_len = defproxy.check_len;
4919
4920 if (defproxy.cookie_name)
4921 curproxy->cookie_name = strdup(defproxy.cookie_name);
4922 curproxy->cookie_len = defproxy.cookie_len;
4923
4924 if (defproxy.capture_name)
4925 curproxy->capture_name = strdup(defproxy.capture_name);
4926 curproxy->capture_namelen = defproxy.capture_namelen;
4927 curproxy->capture_len = defproxy.capture_len;
4928
4929 if (defproxy.errmsg.msg400)
4930 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
4931 curproxy->errmsg.len400 = defproxy.errmsg.len400;
4932
4933 if (defproxy.errmsg.msg403)
4934 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
4935 curproxy->errmsg.len403 = defproxy.errmsg.len403;
4936
4937 if (defproxy.errmsg.msg408)
4938 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
4939 curproxy->errmsg.len408 = defproxy.errmsg.len408;
4940
4941 if (defproxy.errmsg.msg500)
4942 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
4943 curproxy->errmsg.len500 = defproxy.errmsg.len500;
4944
4945 if (defproxy.errmsg.msg502)
4946 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
4947 curproxy->errmsg.len502 = defproxy.errmsg.len502;
4948
4949 if (defproxy.errmsg.msg503)
4950 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
4951 curproxy->errmsg.len503 = defproxy.errmsg.len503;
4952
4953 if (defproxy.errmsg.msg504)
4954 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
4955 curproxy->errmsg.len504 = defproxy.errmsg.len504;
4956
willy tarreaua41a8b42005-12-17 14:02:24 +01004957 curproxy->clitimeout = defproxy.clitimeout;
4958 curproxy->contimeout = defproxy.contimeout;
4959 curproxy->srvtimeout = defproxy.srvtimeout;
4960 curproxy->mode = defproxy.mode;
4961 curproxy->logfac1 = defproxy.logfac1;
4962 curproxy->logsrv1 = defproxy.logsrv1;
4963 curproxy->loglev1 = defproxy.loglev1;
4964 curproxy->logfac2 = defproxy.logfac2;
4965 curproxy->logsrv2 = defproxy.logsrv2;
4966 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01004967 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01004968 curproxy->grace = defproxy.grace;
4969 curproxy->source_addr = defproxy.source_addr;
4970 return 0;
4971 }
4972 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004973 /* some variables may have already been initialized earlier */
4974 if (defproxy.check_req) free(defproxy.check_req);
4975 if (defproxy.cookie_name) free(defproxy.cookie_name);
4976 if (defproxy.capture_name) free(defproxy.capture_name);
4977 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
4978 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
4979 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
4980 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
4981 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
4982 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
4983 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
4984
4985 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01004986 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01004987 return 0;
4988 }
4989 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004990 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004991 return -1;
4992 }
4993
willy tarreaua41a8b42005-12-17 14:02:24 +01004994 if (!strcmp(args[0], "bind")) { /* new listen addresses */
4995 if (curproxy == &defproxy) {
4996 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4997 return -1;
4998 }
4999
5000 if (strchr(args[1], ':') == NULL) {
5001 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
5002 file, linenum, args[0]);
5003 return -1;
5004 }
5005 curproxy->listen = str2listener(args[1], curproxy->listen);
5006 return 0;
5007 }
5008 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01005009 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
5010 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
5011 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
5012 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005013 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005014 return -1;
5015 }
5016 }
5017 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
5018 curproxy->state = PR_STDISABLED;
5019 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005020 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
5021 curproxy->state = PR_STNEW;
5022 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005023 else if (!strcmp(args[0], "cookie")) { /* cookie name */
5024 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005025// if (curproxy == &defproxy) {
5026// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5027// return -1;
5028// }
willy tarreaua41a8b42005-12-17 14:02:24 +01005029
willy tarreau9fe663a2005-12-17 13:02:59 +01005030 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005031// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
5032// file, linenum);
5033// return 0;
5034 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005035 }
5036
5037 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005038 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
5039 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005040 return -1;
5041 }
5042 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005043 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005044
5045 cur_arg = 2;
5046 while (*(args[cur_arg])) {
5047 if (!strcmp(args[cur_arg], "rewrite")) {
5048 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01005049 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005050 else if (!strcmp(args[cur_arg], "indirect")) {
5051 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01005052 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005053 else if (!strcmp(args[cur_arg], "insert")) {
5054 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01005055 }
willy tarreau240afa62005-12-17 13:14:35 +01005056 else if (!strcmp(args[cur_arg], "nocache")) {
5057 curproxy->options |= PR_O_COOK_NOC;
5058 }
willy tarreaucd878942005-12-17 13:27:43 +01005059 else if (!strcmp(args[cur_arg], "postonly")) {
5060 curproxy->options |= PR_O_COOK_POST;
5061 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005062 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005063 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
5064 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005065 return -1;
5066 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005067 cur_arg++;
5068 }
5069 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005070 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005071 file, linenum);
5072 return -1;
5073 }
5074 }
willy tarreau4302f492005-12-18 01:00:37 +01005075 else if (!strcmp(args[0], "capture")) {
5076 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
5077 // if (curproxy == &defproxy) {
5078 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5079 // return -1;
5080 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005081
willy tarreau4302f492005-12-18 01:00:37 +01005082 if (curproxy->capture_name != NULL) {
5083 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
5084 // file, linenum, args[0]);
5085 // return 0;
5086 free(curproxy->capture_name);
5087 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005088
willy tarreau4302f492005-12-18 01:00:37 +01005089 if (*(args[4]) == 0) {
5090 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
5091 file, linenum, args[0]);
5092 return -1;
5093 }
5094 curproxy->capture_name = strdup(args[2]);
5095 curproxy->capture_namelen = strlen(curproxy->capture_name);
5096 curproxy->capture_len = atol(args[4]);
5097 if (curproxy->capture_len >= CAPTURE_LEN) {
5098 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
5099 file, linenum, CAPTURE_LEN - 1);
5100 curproxy->capture_len = CAPTURE_LEN - 1;
5101 }
5102 curproxy->to_log |= LW_COOKIE;
5103 }
5104 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
5105 struct cap_hdr *hdr;
5106
5107 if (curproxy == &defproxy) {
5108 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5109 return -1;
5110 }
5111
5112 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5113 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5114 file, linenum, args[0], args[1]);
5115 return -1;
5116 }
5117
5118 hdr = calloc(sizeof(struct cap_hdr), 1);
5119 hdr->next = curproxy->req_cap;
5120 hdr->name = strdup(args[3]);
5121 hdr->namelen = strlen(args[3]);
5122 hdr->len = atol(args[5]);
5123 hdr->index = curproxy->nb_req_cap++;
5124 curproxy->req_cap = hdr;
5125 curproxy->to_log |= LW_REQHDR;
5126 }
5127 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
5128 struct cap_hdr *hdr;
5129
5130 if (curproxy == &defproxy) {
5131 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5132 return -1;
5133 }
5134
5135 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5136 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5137 file, linenum, args[0], args[1]);
5138 return -1;
5139 }
5140 hdr = calloc(sizeof(struct cap_hdr), 1);
5141 hdr->next = curproxy->rsp_cap;
5142 hdr->name = strdup(args[3]);
5143 hdr->namelen = strlen(args[3]);
5144 hdr->len = atol(args[5]);
5145 hdr->index = curproxy->nb_rsp_cap++;
5146 curproxy->rsp_cap = hdr;
5147 curproxy->to_log |= LW_RSPHDR;
5148 }
5149 else {
5150 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005151 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005152 return -1;
5153 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005154 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005155 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005156 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005157 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005158 return 0;
5159 }
5160 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005161 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5162 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005163 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005164 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005165 curproxy->contimeout = atol(args[1]);
5166 }
5167 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005168 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005169 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
5170 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005171 return 0;
5172 }
5173 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005174 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5175 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005176 return -1;
5177 }
5178 curproxy->clitimeout = atol(args[1]);
5179 }
5180 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005181 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005182 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005183 return 0;
5184 }
5185 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005186 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5187 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005188 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005189 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005190 curproxy->srvtimeout = atol(args[1]);
5191 }
5192 else if (!strcmp(args[0], "retries")) { /* connection retries */
5193 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005194 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
5195 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005196 return -1;
5197 }
5198 curproxy->conn_retries = atol(args[1]);
5199 }
5200 else if (!strcmp(args[0], "option")) {
5201 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005202 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005203 return -1;
5204 }
5205 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005206 /* enable reconnections to dispatch */
5207 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01005208#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01005209 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005210 /* enable transparent proxy connections */
5211 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01005212#endif
5213 else if (!strcmp(args[1], "keepalive"))
5214 /* enable keep-alive */
5215 curproxy->options |= PR_O_KEEPALIVE;
5216 else if (!strcmp(args[1], "forwardfor"))
5217 /* insert x-forwarded-for field */
5218 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01005219 else if (!strcmp(args[1], "logasap"))
5220 /* log as soon as possible, without waiting for the session to complete */
5221 curproxy->options |= PR_O_LOGASAP;
5222 else if (!strcmp(args[1], "httpclose"))
5223 /* force connection: close in both directions in HTTP mode */
5224 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01005225 else if (!strcmp(args[1], "checkcache"))
5226 /* require examination of cacheability of the 'set-cookie' field */
5227 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01005228 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01005229 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01005230 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01005231 else if (!strcmp(args[1], "tcplog"))
5232 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01005233 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01005234 else if (!strcmp(args[1], "dontlognull")) {
5235 /* don't log empty requests */
5236 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005237 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005238 else if (!strcmp(args[1], "httpchk")) {
5239 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005240 if (curproxy->check_req != NULL) {
5241 free(curproxy->check_req);
5242 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005243 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005244 if (!*args[2]) { /* no argument */
5245 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
5246 curproxy->check_len = strlen(DEF_CHECK_REQ);
5247 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01005248 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
5249 curproxy->check_req = (char *)malloc(reqlen);
5250 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
5251 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005252 } else { /* more arguments : METHOD URI [HTTP_VER] */
5253 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
5254 if (*args[4])
5255 reqlen += strlen(args[4]);
5256 else
5257 reqlen += strlen("HTTP/1.0");
5258
5259 curproxy->check_req = (char *)malloc(reqlen);
5260 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
5261 "%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 +01005262 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005263 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005264 else if (!strcmp(args[1], "persist")) {
5265 /* persist on using the server specified by the cookie, even when it's down */
5266 curproxy->options |= PR_O_PERSIST;
5267 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005268 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005269 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005270 return -1;
5271 }
5272 return 0;
5273 }
5274 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
5275 /* enable reconnections to dispatch */
5276 curproxy->options |= PR_O_REDISP;
5277 }
willy tarreaua1598082005-12-17 13:08:06 +01005278#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01005279 else if (!strcmp(args[0], "transparent")) {
5280 /* enable transparent proxy connections */
5281 curproxy->options |= PR_O_TRANSP;
5282 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005283#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01005284 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
5285 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005286 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", 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->maxconn = atol(args[1]);
5290 }
5291 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
5292 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005293 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005294 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005295 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005296 curproxy->grace = atol(args[1]);
5297 }
5298 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01005299 if (curproxy == &defproxy) {
5300 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5301 return -1;
5302 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005303 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005304 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005305 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005306 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005307 curproxy->dispatch_addr = *str2sa(args[1]);
5308 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005309 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01005310 if (*(args[1])) {
5311 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005312 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01005313 }
5314 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005315 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005316 return -1;
5317 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005318 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005319 else /* if no option is set, use round-robin by default */
5320 curproxy->options |= PR_O_BALANCE_RR;
5321 }
5322 else if (!strcmp(args[0], "server")) { /* server address */
5323 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005324 char *rport;
5325 char *raddr;
5326 short realport;
5327 int do_check;
5328
5329 if (curproxy == &defproxy) {
5330 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5331 return -1;
5332 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005333
willy tarreaua41a8b42005-12-17 14:02:24 +01005334 if (!*args[2]) {
5335 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005336 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005337 return -1;
5338 }
5339 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
5340 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
5341 return -1;
5342 }
5343 newsrv->next = curproxy->srv;
5344 curproxy->srv = newsrv;
5345 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01005346
5347 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01005348 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01005349 newsrv->id = strdup(args[1]);
5350
5351 /* several ways to check the port component :
5352 * - IP => port=+0, relative
5353 * - IP: => port=+0, relative
5354 * - IP:N => port=N, absolute
5355 * - IP:+N => port=+N, relative
5356 * - IP:-N => port=-N, relative
5357 */
5358 raddr = strdup(args[2]);
5359 rport = strchr(raddr, ':');
5360 if (rport) {
5361 *rport++ = 0;
5362 realport = atol(rport);
5363 if (!isdigit((int)*rport))
5364 newsrv->state |= SRV_MAPPORTS;
5365 } else {
5366 realport = 0;
5367 newsrv->state |= SRV_MAPPORTS;
5368 }
5369
5370 newsrv->addr = *str2sa(raddr);
5371 newsrv->addr.sin_port = htons(realport);
5372 free(raddr);
5373
willy tarreau9fe663a2005-12-17 13:02:59 +01005374 newsrv->curfd = -1; /* no health-check in progress */
5375 newsrv->inter = DEF_CHKINTR;
5376 newsrv->rise = DEF_RISETIME;
5377 newsrv->fall = DEF_FALLTIME;
5378 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
5379 cur_arg = 3;
5380 while (*args[cur_arg]) {
5381 if (!strcmp(args[cur_arg], "cookie")) {
5382 newsrv->cookie = strdup(args[cur_arg + 1]);
5383 newsrv->cklen = strlen(args[cur_arg + 1]);
5384 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01005385 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005386 else if (!strcmp(args[cur_arg], "rise")) {
5387 newsrv->rise = atol(args[cur_arg + 1]);
5388 newsrv->health = newsrv->rise;
5389 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01005390 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005391 else if (!strcmp(args[cur_arg], "fall")) {
5392 newsrv->fall = atol(args[cur_arg + 1]);
5393 cur_arg += 2;
5394 }
5395 else if (!strcmp(args[cur_arg], "inter")) {
5396 newsrv->inter = atol(args[cur_arg + 1]);
5397 cur_arg += 2;
5398 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005399 else if (!strcmp(args[cur_arg], "port")) {
5400 newsrv->check_port = atol(args[cur_arg + 1]);
5401 cur_arg += 2;
5402 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005403 else if (!strcmp(args[cur_arg], "backup")) {
5404 newsrv->state |= SRV_BACKUP;
5405 cur_arg ++;
5406 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005407 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005408 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005409 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005410 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005411 else {
willy tarreaua41a8b42005-12-17 14:02:24 +01005412 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
5413 file, linenum, newsrv->id);
5414 return -1;
5415 }
5416 }
5417
5418 if (do_check) {
5419 struct task *t;
5420
5421 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
5422 newsrv->check_port = realport; /* by default */
5423 if (!newsrv->check_port) {
5424 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 +01005425 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005426 return -1;
5427 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005428
5429 if ((t = pool_alloc(task)) == NULL) {
5430 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
5431 return -1;
5432 }
5433
5434 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
5435 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
5436 t->state = TASK_IDLE;
5437 t->process = process_chk;
5438 t->context = newsrv;
5439
5440 if (curproxy->state != PR_STDISABLED) {
5441 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
5442 task_queue(t);
5443 task_wakeup(&rq, t);
5444 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005445 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005446
willy tarreau9fe663a2005-12-17 13:02:59 +01005447 curproxy->nbservers++;
5448 }
5449 else if (!strcmp(args[0], "log")) { /* syslog server address */
5450 struct sockaddr_in *sa;
5451 int facility;
5452
5453 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
5454 curproxy->logfac1 = global.logfac1;
5455 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005456 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005457 curproxy->logfac2 = global.logfac2;
5458 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01005459 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01005460 }
5461 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01005462 int level;
5463
willy tarreau0f7af912005-12-17 12:21:26 +01005464 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5465 if (!strcmp(log_facilities[facility], args[2]))
5466 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01005467
willy tarreau0f7af912005-12-17 12:21:26 +01005468 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005469 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01005470 exit(1);
5471 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005472
willy tarreau8337c6b2005-12-17 13:41:01 +01005473 level = 7; /* max syslog level = debug */
5474 if (*(args[3])) {
5475 while (level >= 0 && strcmp(log_levels[level], args[3]))
5476 level--;
5477 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005478 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005479 exit(1);
5480 }
5481 }
5482
willy tarreau0f7af912005-12-17 12:21:26 +01005483 sa = str2sa(args[1]);
5484 if (!sa->sin_port)
5485 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01005486
willy tarreau0f7af912005-12-17 12:21:26 +01005487 if (curproxy->logfac1 == -1) {
5488 curproxy->logsrv1 = *sa;
5489 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005490 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005491 }
5492 else if (curproxy->logfac2 == -1) {
5493 curproxy->logsrv2 = *sa;
5494 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005495 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005496 }
5497 else {
5498 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005499 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005500 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005501 }
5502 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005503 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005504 file, linenum);
5505 return -1;
5506 }
5507 }
willy tarreaua1598082005-12-17 13:08:06 +01005508 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01005509 if (!*args[1]) {
5510 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005511 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01005512 return -1;
5513 }
5514
5515 curproxy->source_addr = *str2sa(args[1]);
5516 curproxy->options |= PR_O_BIND_SRC;
5517 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005518 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
5519 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005520 if (curproxy == &defproxy) {
5521 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5522 return -1;
5523 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005524
5525 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005526 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5527 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005528 return -1;
5529 }
5530
5531 preg = calloc(1, sizeof(regex_t));
5532 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005533 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005534 return -1;
5535 }
5536
5537 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5538 }
5539 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
5540 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005541 if (curproxy == &defproxy) {
5542 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5543 return -1;
5544 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005545
5546 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005547 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005548 return -1;
5549 }
5550
5551 preg = calloc(1, sizeof(regex_t));
5552 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005553 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005554 return -1;
5555 }
5556
5557 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5558 }
5559 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
5560 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005561 if (curproxy == &defproxy) {
5562 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5563 return -1;
5564 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005565
5566 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005567 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005568 return -1;
5569 }
5570
5571 preg = calloc(1, sizeof(regex_t));
5572 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005573 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005574 return -1;
5575 }
5576
5577 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5578 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005579 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
5580 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005581 if (curproxy == &defproxy) {
5582 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5583 return -1;
5584 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005585
5586 if (*(args[1]) == 0) {
5587 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5588 return -1;
5589 }
5590
5591 preg = calloc(1, sizeof(regex_t));
5592 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5593 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5594 return -1;
5595 }
5596
5597 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5598 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005599 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
5600 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005601 if (curproxy == &defproxy) {
5602 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5603 return -1;
5604 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005605
5606 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005607 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005608 return -1;
5609 }
5610
5611 preg = calloc(1, sizeof(regex_t));
5612 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005613 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005614 return -1;
5615 }
5616
5617 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5618 }
5619 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
5620 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005621 if (curproxy == &defproxy) {
5622 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5623 return -1;
5624 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005625
5626 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005627 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5628 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005629 return -1;
5630 }
5631
5632 preg = calloc(1, sizeof(regex_t));
5633 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005634 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005635 return -1;
5636 }
5637
5638 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5639 }
5640 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
5641 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005642 if (curproxy == &defproxy) {
5643 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5644 return -1;
5645 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005646
5647 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005648 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005649 return -1;
5650 }
5651
5652 preg = calloc(1, sizeof(regex_t));
5653 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005654 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005655 return -1;
5656 }
5657
5658 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5659 }
5660 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
5661 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005662 if (curproxy == &defproxy) {
5663 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5664 return -1;
5665 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005666
5667 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005668 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005669 return -1;
5670 }
5671
5672 preg = calloc(1, sizeof(regex_t));
5673 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005674 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005675 return -1;
5676 }
5677
5678 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5679 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005680 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
5681 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005682 if (curproxy == &defproxy) {
5683 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5684 return -1;
5685 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005686
5687 if (*(args[1]) == 0) {
5688 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5689 return -1;
5690 }
5691
5692 preg = calloc(1, sizeof(regex_t));
5693 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5694 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5695 return -1;
5696 }
5697
5698 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5699 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005700 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
5701 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005702 if (curproxy == &defproxy) {
5703 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5704 return -1;
5705 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005706
5707 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005708 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005709 return -1;
5710 }
5711
5712 preg = calloc(1, sizeof(regex_t));
5713 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005714 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005715 return -1;
5716 }
5717
5718 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5719 }
5720 else if (!strcmp(args[0], "reqadd")) { /* add request header */
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 }
5725
willy tarreau9fe663a2005-12-17 13:02:59 +01005726 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005727 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005728 return 0;
5729 }
5730
5731 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005732 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005733 return -1;
5734 }
5735
willy tarreau4302f492005-12-18 01:00:37 +01005736 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
5737 }
5738 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
5739 regex_t *preg;
5740
5741 if (*(args[1]) == 0 || *(args[2]) == 0) {
5742 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5743 file, linenum, args[0]);
5744 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005745 }
willy tarreau4302f492005-12-18 01:00:37 +01005746
5747 preg = calloc(1, sizeof(regex_t));
5748 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5749 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5750 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005751 }
willy tarreau4302f492005-12-18 01:00:37 +01005752
5753 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5754 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005755 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
5756 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005757 if (curproxy == &defproxy) {
5758 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5759 return -1;
5760 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005761
5762 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005763 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005764 return -1;
5765 }
willy tarreaue39cd132005-12-17 13:00:18 +01005766
willy tarreau9fe663a2005-12-17 13:02:59 +01005767 preg = calloc(1, sizeof(regex_t));
5768 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005769 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005770 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005771 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005772
5773 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5774 }
willy tarreau982249e2005-12-18 00:57:06 +01005775 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
5776 regex_t *preg;
5777 if (curproxy == &defproxy) {
5778 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5779 return -1;
5780 }
5781
5782 if (*(args[1]) == 0) {
5783 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
5784 return -1;
5785 }
5786
5787 preg = calloc(1, sizeof(regex_t));
5788 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5789 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5790 return -1;
5791 }
5792
5793 chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
5794 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005795 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01005796 regex_t *preg;
5797 if (curproxy == &defproxy) {
5798 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5799 return -1;
5800 }
willy tarreaue39cd132005-12-17 13:00:18 +01005801
willy tarreaua41a8b42005-12-17 14:02:24 +01005802 if (*(args[1]) == 0 || *(args[2]) == 0) {
5803 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5804 file, linenum, args[0]);
5805 return -1;
5806 }
willy tarreaue39cd132005-12-17 13:00:18 +01005807
willy tarreaua41a8b42005-12-17 14:02:24 +01005808 preg = calloc(1, sizeof(regex_t));
5809 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5810 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5811 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005812 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005813
5814 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5815 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005816 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
5817 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005818 if (curproxy == &defproxy) {
5819 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5820 return -1;
5821 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005822
5823 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005824 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005825 return -1;
5826 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005827
willy tarreau9fe663a2005-12-17 13:02:59 +01005828 preg = calloc(1, sizeof(regex_t));
5829 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005830 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005831 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005832 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005833
5834 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5835 }
willy tarreau982249e2005-12-18 00:57:06 +01005836 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
5837 regex_t *preg;
5838 if (curproxy == &defproxy) {
5839 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5840 return -1;
5841 }
5842
5843 if (*(args[1]) == 0) {
5844 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
5845 return -1;
5846 }
5847
5848 preg = calloc(1, sizeof(regex_t));
5849 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5850 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5851 return -1;
5852 }
5853
5854 chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
5855 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005856 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005857 if (curproxy == &defproxy) {
5858 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5859 return -1;
5860 }
5861
willy tarreau9fe663a2005-12-17 13:02:59 +01005862 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005863 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005864 return 0;
5865 }
5866
5867 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005868 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005869 return -1;
5870 }
5871
5872 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
5873 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005874 else if (!strcmp(args[0], "errorloc")) { /* error location */
5875 int errnum;
5876 char *err;
5877
willy tarreaueedaa9f2005-12-17 14:08:03 +01005878 // if (curproxy == &defproxy) {
5879 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5880 // return -1;
5881 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005882
willy tarreau8337c6b2005-12-17 13:41:01 +01005883 if (*(args[2]) == 0) {
5884 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
5885 return -1;
5886 }
5887
5888 errnum = atol(args[1]);
5889 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
5890 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
5891
5892 if (errnum == 400) {
5893 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005894 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005895 free(curproxy->errmsg.msg400);
5896 }
5897 curproxy->errmsg.msg400 = err;
5898 curproxy->errmsg.len400 = strlen(err);
5899 }
5900 else if (errnum == 403) {
5901 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005902 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005903 free(curproxy->errmsg.msg403);
5904 }
5905 curproxy->errmsg.msg403 = err;
5906 curproxy->errmsg.len403 = strlen(err);
5907 }
5908 else if (errnum == 408) {
5909 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005910 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005911 free(curproxy->errmsg.msg408);
5912 }
5913 curproxy->errmsg.msg408 = err;
5914 curproxy->errmsg.len408 = strlen(err);
5915 }
5916 else if (errnum == 500) {
5917 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005918 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005919 free(curproxy->errmsg.msg500);
5920 }
5921 curproxy->errmsg.msg500 = err;
5922 curproxy->errmsg.len500 = strlen(err);
5923 }
5924 else if (errnum == 502) {
5925 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005926 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005927 free(curproxy->errmsg.msg502);
5928 }
5929 curproxy->errmsg.msg502 = err;
5930 curproxy->errmsg.len502 = strlen(err);
5931 }
5932 else if (errnum == 503) {
5933 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005934 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005935 free(curproxy->errmsg.msg503);
5936 }
5937 curproxy->errmsg.msg503 = err;
5938 curproxy->errmsg.len503 = strlen(err);
5939 }
5940 else if (errnum == 504) {
5941 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005942 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005943 free(curproxy->errmsg.msg504);
5944 }
5945 curproxy->errmsg.msg504 = err;
5946 curproxy->errmsg.len504 = strlen(err);
5947 }
5948 else {
5949 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
5950 free(err);
5951 }
5952 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005953 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005954 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01005955 return -1;
5956 }
5957 return 0;
5958}
willy tarreaue39cd132005-12-17 13:00:18 +01005959
willy tarreau5cbea6f2005-12-17 12:48:26 +01005960
willy tarreau9fe663a2005-12-17 13:02:59 +01005961/*
5962 * This function reads and parses the configuration file given in the argument.
5963 * returns 0 if OK, -1 if error.
5964 */
5965int readcfgfile(char *file) {
5966 char thisline[256];
5967 char *line;
5968 FILE *f;
5969 int linenum = 0;
5970 char *end;
5971 char *args[MAX_LINE_ARGS];
5972 int arg;
5973 int cfgerr = 0;
5974 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01005975
willy tarreau9fe663a2005-12-17 13:02:59 +01005976 struct proxy *curproxy = NULL;
5977 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005978
willy tarreau9fe663a2005-12-17 13:02:59 +01005979 if ((f=fopen(file,"r")) == NULL)
5980 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005981
willy tarreaueedaa9f2005-12-17 14:08:03 +01005982 init_default_instance();
5983
willy tarreau9fe663a2005-12-17 13:02:59 +01005984 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
5985 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005986
willy tarreau9fe663a2005-12-17 13:02:59 +01005987 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005988
willy tarreau9fe663a2005-12-17 13:02:59 +01005989 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01005990 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01005991 line++;
5992
5993 arg = 0;
5994 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01005995
willy tarreau9fe663a2005-12-17 13:02:59 +01005996 while (*line && arg < MAX_LINE_ARGS) {
5997 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
5998 * C equivalent value. Other combinations left unchanged (eg: \1).
5999 */
6000 if (*line == '\\') {
6001 int skip = 0;
6002 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
6003 *line = line[1];
6004 skip = 1;
6005 }
6006 else if (line[1] == 'r') {
6007 *line = '\r';
6008 skip = 1;
6009 }
6010 else if (line[1] == 'n') {
6011 *line = '\n';
6012 skip = 1;
6013 }
6014 else if (line[1] == 't') {
6015 *line = '\t';
6016 skip = 1;
6017 }
6018 else if (line[1] == 'x' && (line + 3 < end )) {
6019 unsigned char hex1, hex2;
6020 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
6021 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
6022 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
6023 *line = (hex1<<4) + hex2;
6024 skip = 3;
6025 }
6026 if (skip) {
6027 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
6028 end -= skip;
6029 }
6030 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006031 }
willy tarreaua1598082005-12-17 13:08:06 +01006032 else if (*line == '#' || *line == '\n' || *line == '\r') {
6033 /* end of string, end of loop */
6034 *line = 0;
6035 break;
6036 }
willy tarreauc29948c2005-12-17 13:10:27 +01006037 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006038 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01006039 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01006040 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01006041 line++;
6042 args[++arg] = line;
6043 }
6044 else {
6045 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006046 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006047 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006048
willy tarreau9fe663a2005-12-17 13:02:59 +01006049 /* empty line */
6050 if (!**args)
6051 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01006052
willy tarreau9fe663a2005-12-17 13:02:59 +01006053 /* zero out remaining args */
6054 while (++arg < MAX_LINE_ARGS) {
6055 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006056 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006057
willy tarreaua41a8b42005-12-17 14:02:24 +01006058 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01006059 confsect = CFG_LISTEN;
6060 else if (!strcmp(args[0], "global")) /* global config */
6061 confsect = CFG_GLOBAL;
6062 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006063
willy tarreau9fe663a2005-12-17 13:02:59 +01006064 switch (confsect) {
6065 case CFG_LISTEN:
6066 if (cfg_parse_listen(file, linenum, args) < 0)
6067 return -1;
6068 break;
6069 case CFG_GLOBAL:
6070 if (cfg_parse_global(file, linenum, args) < 0)
6071 return -1;
6072 break;
6073 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01006074 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006075 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006076 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006077
6078
willy tarreau0f7af912005-12-17 12:21:26 +01006079 }
6080 fclose(f);
6081
6082 /*
6083 * Now, check for the integrity of all that we have collected.
6084 */
6085
6086 if ((curproxy = proxy) == NULL) {
6087 Alert("parsing %s : no <listen> line. Nothing to do !\n",
6088 file);
6089 return -1;
6090 }
6091
6092 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01006093 if (curproxy->state == PR_STDISABLED) {
6094 curproxy = curproxy->next;
6095 continue;
6096 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006097 if ((curproxy->mode != PR_MODE_HEALTH) &&
6098 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01006099 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006100 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
6101 file, curproxy->id);
6102 cfgerr++;
6103 }
6104 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
6105 if (curproxy->options & PR_O_TRANSP) {
6106 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
6107 file, curproxy->id);
6108 cfgerr++;
6109 }
6110 else if (curproxy->srv == NULL) {
6111 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
6112 file, curproxy->id);
6113 cfgerr++;
6114 }
willy tarreaua1598082005-12-17 13:08:06 +01006115 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006116 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
6117 file, curproxy->id);
6118 }
6119 }
6120 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01006121 if (curproxy->cookie_name != NULL) {
6122 Warning("parsing %s : cookie will be ignored for listener %s.\n",
6123 file, curproxy->id);
6124 }
6125 if ((newsrv = curproxy->srv) != NULL) {
6126 Warning("parsing %s : servers will be ignored for listener %s.\n",
6127 file, curproxy->id);
6128 }
willy tarreaue39cd132005-12-17 13:00:18 +01006129 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01006130 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
6131 file, curproxy->id);
6132 }
willy tarreaue39cd132005-12-17 13:00:18 +01006133 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01006134 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
6135 file, curproxy->id);
6136 }
6137 }
6138 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
6139 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
6140 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
6141 file, curproxy->id);
6142 cfgerr++;
6143 }
6144 else {
6145 while (newsrv != NULL) {
6146 /* nothing to check for now */
6147 newsrv = newsrv->next;
6148 }
6149 }
6150 }
willy tarreau25c4ea52005-12-18 00:49:49 +01006151
6152 if (curproxy->options & PR_O_LOGASAP)
6153 curproxy->to_log &= ~LW_BYTES;
6154
willy tarreau8337c6b2005-12-17 13:41:01 +01006155 if (curproxy->errmsg.msg400 == NULL) {
6156 curproxy->errmsg.msg400 = (char *)HTTP_400;
6157 curproxy->errmsg.len400 = strlen(HTTP_400);
6158 }
6159 if (curproxy->errmsg.msg403 == NULL) {
6160 curproxy->errmsg.msg403 = (char *)HTTP_403;
6161 curproxy->errmsg.len403 = strlen(HTTP_403);
6162 }
6163 if (curproxy->errmsg.msg408 == NULL) {
6164 curproxy->errmsg.msg408 = (char *)HTTP_408;
6165 curproxy->errmsg.len408 = strlen(HTTP_408);
6166 }
6167 if (curproxy->errmsg.msg500 == NULL) {
6168 curproxy->errmsg.msg500 = (char *)HTTP_500;
6169 curproxy->errmsg.len500 = strlen(HTTP_500);
6170 }
6171 if (curproxy->errmsg.msg502 == NULL) {
6172 curproxy->errmsg.msg502 = (char *)HTTP_502;
6173 curproxy->errmsg.len502 = strlen(HTTP_502);
6174 }
6175 if (curproxy->errmsg.msg503 == NULL) {
6176 curproxy->errmsg.msg503 = (char *)HTTP_503;
6177 curproxy->errmsg.len503 = strlen(HTTP_503);
6178 }
6179 if (curproxy->errmsg.msg504 == NULL) {
6180 curproxy->errmsg.msg504 = (char *)HTTP_504;
6181 curproxy->errmsg.len504 = strlen(HTTP_504);
6182 }
willy tarreau0f7af912005-12-17 12:21:26 +01006183 curproxy = curproxy->next;
6184 }
6185 if (cfgerr > 0) {
6186 Alert("Errors found in configuration file, aborting.\n");
6187 return -1;
6188 }
6189 else
6190 return 0;
6191}
6192
6193
6194/*
6195 * This function initializes all the necessary variables. It only returns
6196 * if everything is OK. If something fails, it exits.
6197 */
6198void init(int argc, char **argv) {
6199 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01006200 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01006201 char *old_argv = *argv;
6202 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006203 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006204 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01006205
6206 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01006207 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006208 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01006209 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01006210 exit(1);
6211 }
6212
willy tarreau4302f492005-12-18 01:00:37 +01006213 /* initialize the log header encoding map : '{|}"#' should be encoded with
6214 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
6215 * URL encoding only requires '"', '#' to be encoded as well as non-
6216 * printable characters above.
6217 */
6218 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
6219 memset(url_encode_map, 0, sizeof(url_encode_map));
6220 for (i = 0; i < 32; i++) {
6221 FD_SET(i, hdr_encode_map);
6222 FD_SET(i, url_encode_map);
6223 }
6224 for (i = 127; i < 256; i++) {
6225 FD_SET(i, hdr_encode_map);
6226 FD_SET(i, url_encode_map);
6227 }
6228
6229 tmp = "\"#{|}";
6230 while (*tmp) {
6231 FD_SET(*tmp, hdr_encode_map);
6232 tmp++;
6233 }
6234
6235 tmp = "\"#";
6236 while (*tmp) {
6237 FD_SET(*tmp, url_encode_map);
6238 tmp++;
6239 }
6240
willy tarreau0f7af912005-12-17 12:21:26 +01006241 pid = getpid();
6242 progname = *argv;
6243 while ((tmp = strchr(progname, '/')) != NULL)
6244 progname = tmp + 1;
6245
6246 argc--; argv++;
6247 while (argc > 0) {
6248 char *flag;
6249
6250 if (**argv == '-') {
6251 flag = *argv+1;
6252
6253 /* 1 arg */
6254 if (*flag == 'v') {
6255 display_version();
6256 exit(0);
6257 }
willy tarreau982249e2005-12-18 00:57:06 +01006258 else if (*flag == 'V')
6259 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01006260 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01006261 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01006262 else if (*flag == 'c')
6263 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01006264 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01006265 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006266 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01006267 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01006268#if STATTIME > 0
6269 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01006270 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01006271 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01006272 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01006273#endif
6274 else { /* >=2 args */
6275 argv++; argc--;
6276 if (argc == 0)
6277 usage(old_argv);
6278
6279 switch (*flag) {
6280 case 'n' : cfg_maxconn = atol(*argv); break;
6281 case 'N' : cfg_maxpconn = atol(*argv); break;
6282 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006283 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01006284 default: usage(old_argv);
6285 }
6286 }
6287 }
6288 else
6289 usage(old_argv);
6290 argv++; argc--;
6291 }
6292
willy tarreau982249e2005-12-18 00:57:06 +01006293 global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01006294
willy tarreau0f7af912005-12-17 12:21:26 +01006295 if (!cfg_cfgfile)
6296 usage(old_argv);
6297
6298 gethostname(hostname, MAX_HOSTNAME_LEN);
6299
6300 if (readcfgfile(cfg_cfgfile) < 0) {
6301 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
6302 exit(1);
6303 }
6304
willy tarreau982249e2005-12-18 00:57:06 +01006305 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01006306 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
6307 exit(0);
6308 }
6309
willy tarreau9fe663a2005-12-17 13:02:59 +01006310 if (cfg_maxconn > 0)
6311 global.maxconn = cfg_maxconn;
6312
willy tarreaufe2c5c12005-12-17 14:14:34 +01006313 if (cfg_pidfile) {
6314 if (global.pidfile)
6315 free(global.pidfile);
6316 global.pidfile = strdup(cfg_pidfile);
6317 }
6318
willy tarreau9fe663a2005-12-17 13:02:59 +01006319 if (global.maxconn == 0)
6320 global.maxconn = DEFAULT_MAXCONN;
6321
6322 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
6323
6324 if (arg_mode & MODE_DEBUG) {
6325 /* command line debug mode inhibits configuration mode */
6326 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
6327 }
willy tarreau982249e2005-12-18 00:57:06 +01006328 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
6329 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01006330
6331 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
6332 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
6333 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
6334 }
6335
6336 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
6337 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
6338 global.nbproc = 1;
6339 }
6340
6341 if (global.nbproc < 1)
6342 global.nbproc = 1;
6343
willy tarreau0f7af912005-12-17 12:21:26 +01006344 ReadEvent = (fd_set *)calloc(1,
6345 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006346 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006347 WriteEvent = (fd_set *)calloc(1,
6348 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006349 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006350 StaticReadEvent = (fd_set *)calloc(1,
6351 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006352 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006353 StaticWriteEvent = (fd_set *)calloc(1,
6354 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006355 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006356
6357 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01006358 sizeof(struct fdtab) * (global.maxsock));
6359 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01006360 fdtab[i].state = FD_STCLOSE;
6361 }
6362}
6363
6364/*
6365 * this function starts all the proxies. It returns 0 if OK, -1 if not.
6366 */
6367int start_proxies() {
6368 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006369 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01006370 int fd;
6371
6372 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01006373 if (curproxy->state == PR_STDISABLED)
6374 continue;
6375
willy tarreaua41a8b42005-12-17 14:02:24 +01006376 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
6377 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01006378 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006379 Alert("cannot create listening socket for proxy %s. Aborting.\n",
6380 curproxy->id);
6381 return -1;
6382 }
willy tarreau0f7af912005-12-17 12:21:26 +01006383
willy tarreaua41a8b42005-12-17 14:02:24 +01006384 if (fd >= global.maxsock) {
6385 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
6386 curproxy->id);
6387 close(fd);
6388 return -1;
6389 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006390
willy tarreaua41a8b42005-12-17 14:02:24 +01006391 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
6392 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
6393 (char *) &one, sizeof(one)) == -1)) {
6394 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
6395 curproxy->id);
6396 close(fd);
6397 return -1;
6398 }
willy tarreau0f7af912005-12-17 12:21:26 +01006399
willy tarreaua41a8b42005-12-17 14:02:24 +01006400 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
6401 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
6402 curproxy->id);
6403 }
willy tarreau0f7af912005-12-17 12:21:26 +01006404
willy tarreaua41a8b42005-12-17 14:02:24 +01006405 if (bind(fd,
6406 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01006407 listener->addr.ss_family == AF_INET6 ?
6408 sizeof(struct sockaddr_in6) :
6409 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006410 Alert("cannot bind socket for proxy %s. Aborting.\n",
6411 curproxy->id);
6412 close(fd);
6413 return -1;
6414 }
willy tarreau0f7af912005-12-17 12:21:26 +01006415
willy tarreaua41a8b42005-12-17 14:02:24 +01006416 if (listen(fd, curproxy->maxconn) == -1) {
6417 Alert("cannot listen to socket for proxy %s. Aborting.\n",
6418 curproxy->id);
6419 close(fd);
6420 return -1;
6421 }
willy tarreau0f7af912005-12-17 12:21:26 +01006422
willy tarreaua41a8b42005-12-17 14:02:24 +01006423 /* the function for the accept() event */
6424 fdtab[fd].read = &event_accept;
6425 fdtab[fd].write = NULL; /* never called */
6426 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
6427 curproxy->state = PR_STRUN;
6428 fdtab[fd].state = FD_STLISTEN;
6429 FD_SET(fd, StaticReadEvent);
6430 fd_insert(fd);
6431 listeners++;
6432 }
willy tarreaua1598082005-12-17 13:08:06 +01006433 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006434 }
6435 return 0;
6436}
6437
6438
6439int main(int argc, char **argv) {
willy tarreaufe2c5c12005-12-17 14:14:34 +01006440 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01006441 init(argc, argv);
6442
willy tarreau9fe663a2005-12-17 13:02:59 +01006443 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01006444 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006445 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01006446 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01006447 }
6448
6449 signal(SIGQUIT, dump);
6450 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01006451 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01006452
6453 /* on very high loads, a sigpipe sometimes happen just between the
6454 * getsockopt() which tells "it's OK to write", and the following write :-(
6455 */
willy tarreau3242e862005-12-17 12:27:53 +01006456#ifndef MSG_NOSIGNAL
6457 signal(SIGPIPE, SIG_IGN);
6458#endif
willy tarreau0f7af912005-12-17 12:21:26 +01006459
6460 if (start_proxies() < 0)
6461 exit(1);
6462
willy tarreaufe2c5c12005-12-17 14:14:34 +01006463 /* open log & pid files before the chroot */
6464 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
6465 int pidfd;
6466 unlink(global.pidfile);
6467 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
6468 if (pidfd < 0) {
6469 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
6470 exit(1);
6471 }
6472 pidfile = fdopen(pidfd, "w");
6473 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006474
6475 /* chroot if needed */
6476 if (global.chroot != NULL) {
6477 if (chroot(global.chroot) == -1) {
6478 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
6479 exit(1);
6480 }
6481 chdir("/");
6482 }
6483
6484 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01006485 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006486 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
6487 exit(1);
6488 }
6489
willy tarreau036e1ce2005-12-17 13:46:33 +01006490 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006491 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
6492 exit(1);
6493 }
6494
6495 if (global.mode & MODE_DAEMON) {
6496 int ret = 0;
6497 int proc;
6498
6499 /* the father launches the required number of processes */
6500 for (proc = 0; proc < global.nbproc; proc++) {
6501 ret = fork();
6502 if (ret < 0) {
6503 Alert("[%s.main()] Cannot fork.\n", argv[0]);
6504 exit(1); /* there has been an error */
6505 }
6506 else if (ret == 0) /* child breaks here */
6507 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006508 if (pidfile != NULL) {
6509 fprintf(pidfile, "%d\n", ret);
6510 fflush(pidfile);
6511 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006512 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006513 /* close the pidfile both in children and father */
6514 if (pidfile != NULL)
6515 fclose(pidfile);
6516 free(global.pidfile);
6517
willy tarreau9fe663a2005-12-17 13:02:59 +01006518 if (proc == global.nbproc)
6519 exit(0); /* parent must leave */
6520
willy tarreau750a4722005-12-17 13:21:24 +01006521 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
6522 * that we can detach from the TTY. We MUST NOT do it in other cases since
6523 * it would have already be done, and 0-2 would have been affected to listening
6524 * sockets
6525 */
6526 if (!(global.mode & MODE_QUIET)) {
6527 /* detach from the tty */
6528 fclose(stdin); fclose(stdout); fclose(stderr);
6529 close(0); close(1); close(2); /* close all fd's */
6530 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
6531 }
willy tarreaua1598082005-12-17 13:08:06 +01006532 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01006533 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01006534 }
6535
willy tarreau0f7af912005-12-17 12:21:26 +01006536 select_loop();
6537
6538 exit(0);
6539}