blob: 776a235219beb4e24bc21c048684e4c2e7ff04dc [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 tarreau036e1ce2005-12-17 13:46:33 +01003 * 2000-2003 - 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
11 * RFC2965 for informations about cookies usage.
12 *
13 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010014 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
15 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010016 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010017 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
18 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010019 * - a proxy with an invalid config will prevent the startup even if disabled.
20 *
willy tarreau036e1ce2005-12-17 13:46:33 +010021 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010022 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010023 * TODO:
24 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010025 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010026 * - fix client/server state transition when server is in connect or headers state
27 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
28 * still handle HTTP headers.
willy tarreau0f7af912005-12-17 12:21:26 +010029 *
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <string.h>
36#include <ctype.h>
37#include <sys/time.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <netinet/tcp.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <netdb.h>
44#include <fcntl.h>
45#include <errno.h>
46#include <signal.h>
47#include <stdarg.h>
48#include <sys/resource.h>
49#include <time.h>
50#include <regex.h>
51#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010052#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010053#include <linux/netfilter_ipv4.h>
54#endif
willy tarreau0f7af912005-12-17 12:21:26 +010055
willy tarreauc58fc692005-12-17 14:13:08 +010056#define HAPROXY_VERSION "1.1.26"
57#define HAPROXY_DATE "2003/10/22"
willy tarreau0f7af912005-12-17 12:21:26 +010058
59/* this is for libc5 for example */
60#ifndef TCP_NODELAY
61#define TCP_NODELAY 1
62#endif
63
64#ifndef SHUT_RD
65#define SHUT_RD 0
66#endif
67
68#ifndef SHUT_WR
69#define SHUT_WR 1
70#endif
71
willy tarreau535ae7a2005-12-17 12:58:00 +010072#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +010073
74// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +010075#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +010076#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +010077#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +010078
willy tarreau5cbea6f2005-12-17 12:48:26 +010079// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +010080#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +010081
willy tarreaue39cd132005-12-17 13:00:18 +010082// max # of added headers per request
83#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +010084
85// max # of matches per regexp
86#define MAX_MATCH 10
87
willy tarreau5cbea6f2005-12-17 12:48:26 +010088/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +010089#define COOKIENAME_LEN 16
90#define SERVERID_LEN 16
91#define CONN_RETRIES 3
92
willy tarreau5cbea6f2005-12-17 12:48:26 +010093#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +010094#define DEF_CHKINTR 2000
95#define DEF_FALLTIME 3
96#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +010097#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +010098
willy tarreau9fe663a2005-12-17 13:02:59 +010099/* default connections limit */
100#define DEFAULT_MAXCONN 2000
101
willy tarreau0f7af912005-12-17 12:21:26 +0100102/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
103#define INTBITS 5
104
105/* show stats this every millisecond, 0 to disable */
106#ifndef STATTIME
107#define STATTIME 2000
108#endif
109
willy tarreau5cbea6f2005-12-17 12:48:26 +0100110/* this reduces the number of calls to select() by choosing appropriate
111 * sheduler precision in milliseconds. It should be near the minimum
112 * time that is needed by select() to collect all events. All timeouts
113 * are rounded up by adding this value prior to pass it to select().
114 */
115#define SCHEDULER_RESOLUTION 9
116
willy tarreau0f7af912005-12-17 12:21:26 +0100117#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
118#define SETNOW(a) (*a=now)
119
willy tarreau9da061b2005-12-17 12:29:56 +0100120/****** string-specific macros and functions ******/
121/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
122#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
123
124/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
125#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
126
willy tarreau9da061b2005-12-17 12:29:56 +0100127/*
128 * copies at most <size-1> chars from <src> to <dst>. Last char is always
129 * set to 0, unless <size> is 0. The number of chars copied is returned
130 * (excluding the terminating zero).
131 * This code has been optimized for size and speed : on x86, it's 45 bytes
132 * long, uses only registers, and consumes only 4 cycles per char.
133 */
willy tarreau750a4722005-12-17 13:21:24 +0100134int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100135 char *orig = dst;
136 if (size) {
137 while (--size && (*dst = *src)) {
138 src++; dst++;
139 }
140 *dst = 0;
141 }
142 return dst - orig;
143}
willy tarreau9da061b2005-12-17 12:29:56 +0100144
willy tarreau0f7af912005-12-17 12:21:26 +0100145#define MEM_OPTIM
146#ifdef MEM_OPTIM
147/*
148 * Returns a pointer to type <type> taken from the
149 * pool <pool_type> or dynamically allocated. In the
150 * first case, <pool_type> is updated to point to the
151 * next element in the list.
152 */
153#define pool_alloc(type) ({ \
154 void *p; \
155 if ((p = pool_##type) == NULL) \
156 p = malloc(sizeof_##type); \
157 else { \
158 pool_##type = *(void **)pool_##type; \
159 } \
160 p; \
161})
162
163/*
164 * Puts a memory area back to the corresponding pool.
165 * Items are chained directly through a pointer that
166 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100167 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100168 * that each memory area is at least as big as one
169 * pointer.
170 */
171#define pool_free(type, ptr) ({ \
172 *(void **)ptr = (void *)pool_##type; \
173 pool_##type = (void *)ptr; \
174})
175
176#else
177#define pool_alloc(type) (calloc(1,sizeof_##type));
178#define pool_free(type, ptr) (free(ptr));
179#endif /* MEM_OPTIM */
180
willy tarreau5cbea6f2005-12-17 12:48:26 +0100181#define sizeof_task sizeof(struct task)
182#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100183#define sizeof_buffer sizeof(struct buffer)
184#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100185#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100186#define sizeof_capture CAPTURE_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100187
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define FD_STCLOSE 0
190#define FD_STLISTEN 1
191#define FD_STCONN 2
192#define FD_STREADY 3
193#define FD_STERROR 4
194
willy tarreau5cbea6f2005-12-17 12:48:26 +0100195/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100196#define TASK_IDLE 0
197#define TASK_RUNNING 1
198
willy tarreau5cbea6f2005-12-17 12:48:26 +0100199/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100200#define PR_STNEW 0
201#define PR_STIDLE 1
202#define PR_STRUN 2
203#define PR_STDISABLED 3
204
willy tarreau5cbea6f2005-12-17 12:48:26 +0100205/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100206#define PR_MODE_TCP 0
207#define PR_MODE_HTTP 1
208#define PR_MODE_HEALTH 2
209
willy tarreau5cbea6f2005-12-17 12:48:26 +0100210/* bits for proxy->options */
211#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
212#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
213#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
214#define PR_O_COOK_IND 8 /* keep only indirect cookies */
215#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
216#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
217#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
218#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100219#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
220#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100221#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
222#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100223#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100224#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100225#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
willy tarreau8337c6b2005-12-17 13:41:01 +0100226#define PR_O_PERSIST 8192 /* server persistence stays effective even when server is down */
willy tarreau9fe663a2005-12-17 13:02:59 +0100227
willy tarreau5cbea6f2005-12-17 12:48:26 +0100228
willy tarreaue39cd132005-12-17 13:00:18 +0100229/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100230#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
231#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
232#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
233#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
234#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
235#define SN_POST 0x00000020 /* the request was an HTTP POST */
236
237#define SN_CK_NONE 0x00000000 /* this session had no cookie */
238#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
239#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
240#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
241#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
242#define SN_CK_SHIFT 6 /* bit shift */
243
244#define SN_ERR_CLITO 0x00000100 /* client time-out */
245#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
246#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
247#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
248#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
249#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
250#define SN_ERR_SHIFT 8 /* bit shift */
251
252#define SN_FINST_R 0x00001000 /* session ended during client request */
253#define SN_FINST_C 0x00002000 /* session ended during server connect */
254#define SN_FINST_H 0x00003000 /* session ended during server headers */
255#define SN_FINST_D 0x00004000 /* session ended during data phase */
256#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
257#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
258#define SN_FINST_SHIFT 12 /* bit shift */
259
260#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
261#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
262#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
263#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
264#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
265#define SN_SCK_SHIFT 16 /* bit shift */
266
willy tarreau5cbea6f2005-12-17 12:48:26 +0100267
268/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100269#define CL_STHEADERS 0
270#define CL_STDATA 1
271#define CL_STSHUTR 2
272#define CL_STSHUTW 3
273#define CL_STCLOSE 4
274
willy tarreau5cbea6f2005-12-17 12:48:26 +0100275/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100276#define SV_STIDLE 0
277#define SV_STCONN 1
278#define SV_STHEADERS 2
279#define SV_STDATA 3
280#define SV_STSHUTR 4
281#define SV_STSHUTW 5
282#define SV_STCLOSE 6
283
284/* result of an I/O event */
285#define RES_SILENT 0 /* didn't happen */
286#define RES_DATA 1 /* data were sent or received */
287#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
288#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
289
willy tarreau9fe663a2005-12-17 13:02:59 +0100290/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100291#define MODE_DEBUG 1
292#define MODE_STATS 2
293#define MODE_LOG 4
294#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295#define MODE_QUIET 16
296
297/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100298#define SRV_RUNNING 1 /* the server is UP */
299#define SRV_BACKUP 2 /* this server is a backup server */
300#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0f7af912005-12-17 12:21:26 +0100301
willy tarreaue39cd132005-12-17 13:00:18 +0100302/* what to do when a header matches a regex */
303#define ACT_ALLOW 0 /* allow the request */
304#define ACT_REPLACE 1 /* replace the matching header */
305#define ACT_REMOVE 2 /* remove the matching header */
306#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100307#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100308
willy tarreau9fe663a2005-12-17 13:02:59 +0100309/* configuration sections */
310#define CFG_NONE 0
311#define CFG_GLOBAL 1
312#define CFG_LISTEN 2
313
willy tarreaua1598082005-12-17 13:08:06 +0100314/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100315#define LW_DATE 1 /* date */
316#define LW_CLIP 2 /* CLient IP */
317#define LW_SVIP 4 /* SerVer IP */
318#define LW_SVID 8 /* server ID */
319#define LW_REQ 16 /* http REQuest */
320#define LW_RESP 32 /* http RESPonse */
321#define LW_PXIP 64 /* proxy IP */
322#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100323#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100324
willy tarreau0f7af912005-12-17 12:21:26 +0100325/*********************************************************************/
326
327#define LIST_HEAD(a) ((void *)(&(a)))
328
329/*********************************************************************/
330
331struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100332 struct hdr_exp *next;
333 regex_t *preg; /* expression to look for */
334 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
335 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100336};
337
338struct buffer {
339 unsigned int l; /* data length */
340 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100341 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100342 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100343 char data[BUFSIZE];
344};
345
346struct server {
347 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100348 int state; /* server state (SRV_*) */
349 int cklen; /* the len of the cookie, to speed up checks */
350 char *cookie; /* the id set in the cookie */
351 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100352 struct sockaddr_in addr; /* the address to connect to */
willy tarreaua41a8b42005-12-17 14:02:24 +0100353 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100355 int rise, fall; /* time in iterations */
356 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100357 int result; /* 0 = connect OK, -1 = connect KO */
358 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100359 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100360};
361
willy tarreau5cbea6f2005-12-17 12:48:26 +0100362/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100363struct task {
364 struct task *next, *prev; /* chaining ... */
365 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100366 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100367 int state; /* task state : IDLE or RUNNING */
368 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100369 int (*process)(struct task *t); /* the function which processes the task */
370 void *context; /* the task's context */
371};
372
373/* WARNING: if new fields are added, they must be initialized in event_accept() */
374struct session {
375 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100376 /* application specific below */
377 struct timeval crexpire; /* expiration date for a client read */
378 struct timeval cwexpire; /* expiration date for a client write */
379 struct timeval srexpire; /* expiration date for a server read */
380 struct timeval swexpire; /* expiration date for a server write */
381 struct timeval cnexpire; /* expiration date for a connect */
382 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
383 struct proxy *proxy; /* the proxy this socket belongs to */
384 int cli_fd; /* the client side fd */
385 int srv_fd; /* the server side fd */
386 int cli_state; /* state of the client side */
387 int srv_state; /* state of the server side */
388 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100389 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100390 struct buffer *req; /* request buffer */
391 struct buffer *rep; /* response buffer */
392 struct sockaddr_in cli_addr; /* the client address */
393 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100394 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100395 struct {
396 int logwait; /* log fields waiting to be collected : LW_* */
397 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
398 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
399 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
400 long t_data; /* delay before the first data byte from the server ... */
401 unsigned long t_close; /* total session duration */
402 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100403 char *cli_cookie; /* cookie presented by the client, in capture mode */
404 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100405 int status; /* HTTP status from the server, negative if from proxy */
406 long long bytes; /* number of bytes transferred from the server */
407 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100408 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100409};
410
willy tarreaua41a8b42005-12-17 14:02:24 +0100411struct listener {
412 int fd; /* the listen socket */
413 struct sockaddr_in addr; /* the address we listen to */
414 struct listener *next; /* next address or NULL */
415};
416
417
willy tarreau0f7af912005-12-17 12:21:26 +0100418struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100419 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100420 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100421 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100422 struct server *srv, *cursrv; /* known servers, current server */
423 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100424 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100425 int cookie_len; /* strlen(cookie_len), computed only once */
426 char *capture_name; /* beginning of the name of the cookie to capture */
427 int capture_namelen; /* length of the cookie name to match */
428 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100429 int clitimeout; /* client I/O timeout (in milliseconds) */
430 int srvtimeout; /* server I/O timeout (in milliseconds) */
431 int contimeout; /* connect timeout (in milliseconds) */
432 char *id; /* proxy id */
433 int nbconn; /* # of active sessions */
434 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100435 int conn_retries; /* maximum number of connect retries */
436 int options; /* PR_O_REDISP, PR_O_TRANSP */
437 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100438 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100439 struct proxy *next;
440 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
441 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100442 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100443 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100444 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100445 int nb_reqadd, nb_rspadd;
446 struct hdr_exp *req_exp; /* regular expressions for request headers */
447 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
448 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100449 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100450 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
451 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100452 struct {
453 char *msg400; /* message for error 400 */
454 int len400; /* message length for error 400 */
455 char *msg403; /* message for error 403 */
456 int len403; /* message length for error 403 */
457 char *msg408; /* message for error 408 */
458 int len408; /* message length for error 408 */
459 char *msg500; /* message for error 500 */
460 int len500; /* message length for error 500 */
461 char *msg502; /* message for error 502 */
462 int len502; /* message length for error 502 */
463 char *msg503; /* message for error 503 */
464 int len503; /* message length for error 503 */
465 char *msg504; /* message for error 504 */
466 int len504; /* message length for error 504 */
467 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100468};
469
470/* info about one given fd */
471struct fdtab {
472 int (*read)(int fd); /* read function */
473 int (*write)(int fd); /* write function */
474 struct task *owner; /* the session (or proxy) associated with this fd */
475 int state; /* the state of this fd */
476};
477
478/*********************************************************************/
479
willy tarreau0f7af912005-12-17 12:21:26 +0100480int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100481char *cfg_cfgfile = NULL; /* configuration file */
482char *progname = NULL; /* program name */
483int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100484
485/* global options */
486static struct {
487 int uid;
488 int gid;
489 int nbproc;
490 int maxconn;
491 int maxsock; /* max # of sockets */
492 int mode;
493 char *chroot;
494 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100495 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100496 struct sockaddr_in logsrv1, logsrv2;
497} global = {
498 logfac1 : -1,
499 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100500 loglev1 : 7, /* max syslog level : debug */
501 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100502 /* others NULL OK */
503};
504
willy tarreau0f7af912005-12-17 12:21:26 +0100505/*********************************************************************/
506
507fd_set *ReadEvent,
508 *WriteEvent,
509 *StaticReadEvent,
510 *StaticWriteEvent;
511
512void **pool_session = NULL,
513 **pool_buffer = NULL,
514 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100515 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100516 **pool_task = NULL,
517 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100518
519struct proxy *proxy = NULL; /* list of all existing proxies */
520struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100521struct task *rq = NULL; /* global run queue */
522struct task wait_queue = { /* global wait queue */
523 prev:LIST_HEAD(wait_queue),
524 next:LIST_HEAD(wait_queue)
525};
willy tarreau0f7af912005-12-17 12:21:26 +0100526
willy tarreau0f7af912005-12-17 12:21:26 +0100527static int totalconn = 0; /* total # of terminated sessions */
528static int actconn = 0; /* # of active sessions */
529static int maxfd = 0; /* # of the highest fd + 1 */
530static int listeners = 0; /* # of listeners */
531static int stopping = 0; /* non zero means stopping in progress */
532static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100533static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100534
535static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100536/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100537static char trash[BUFSIZE];
538
539/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100540 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100541 */
542
543#define MAX_SYSLOG_LEN 1024
544#define NB_LOG_FACILITIES 24
545const char *log_facilities[NB_LOG_FACILITIES] = {
546 "kern", "user", "mail", "daemon",
547 "auth", "syslog", "lpr", "news",
548 "uucp", "cron", "auth2", "ftp",
549 "ntp", "audit", "alert", "cron2",
550 "local0", "local1", "local2", "local3",
551 "local4", "local5", "local6", "local7"
552};
553
554
555#define NB_LOG_LEVELS 8
556const char *log_levels[NB_LOG_LEVELS] = {
557 "emerg", "alert", "crit", "err",
558 "warning", "notice", "info", "debug"
559};
560
561#define SYSLOG_PORT 514
562
563const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
564 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100565
566const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
567const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
568const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
569const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
570 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
571 unknown, Set-cookie Rewritten */
572
willy tarreau0f7af912005-12-17 12:21:26 +0100573#define MAX_HOSTNAME_LEN 32
574static char hostname[MAX_HOSTNAME_LEN] = "";
575
willy tarreau8337c6b2005-12-17 13:41:01 +0100576const char *HTTP_302 =
577 "HTTP/1.0 302 Found\r\n"
578 "Cache-Control: no-cache\r\n"
579 "Connection: close\r\n"
580 "Location: "; /* not terminated since it will be concatenated with the URL */
581
willy tarreaua1598082005-12-17 13:08:06 +0100582const char *HTTP_400 =
583 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100584 "Cache-Control: no-cache\r\n"
585 "Connection: close\r\n"
586 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100587 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100588
willy tarreaua1598082005-12-17 13:08:06 +0100589const char *HTTP_403 =
590 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100591 "Cache-Control: no-cache\r\n"
592 "Connection: close\r\n"
593 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100594 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
595
willy tarreau8337c6b2005-12-17 13:41:01 +0100596const char *HTTP_408 =
597 "HTTP/1.0 408 Request Time-out\r\n"
598 "Cache-Control: no-cache\r\n"
599 "Connection: close\r\n"
600 "\r\n"
601 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
602
willy tarreau750a4722005-12-17 13:21:24 +0100603const char *HTTP_500 =
604 "HTTP/1.0 500 Server Error\r\n"
605 "Cache-Control: no-cache\r\n"
606 "Connection: close\r\n"
607 "\r\n"
608 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100609
610const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100611 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100612 "Cache-Control: no-cache\r\n"
613 "Connection: close\r\n"
614 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100615 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
616
617const char *HTTP_503 =
618 "HTTP/1.0 503 Service Unavailable\r\n"
619 "Cache-Control: no-cache\r\n"
620 "Connection: close\r\n"
621 "\r\n"
622 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
623
624const char *HTTP_504 =
625 "HTTP/1.0 504 Gateway Time-out\r\n"
626 "Cache-Control: no-cache\r\n"
627 "Connection: close\r\n"
628 "\r\n"
629 "<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 +0100630
willy tarreau0f7af912005-12-17 12:21:26 +0100631/*********************************************************************/
632/* statistics ******************************************************/
633/*********************************************************************/
634
willy tarreau750a4722005-12-17 13:21:24 +0100635#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100636static int stats_tsk_lsrch, stats_tsk_rsrch,
637 stats_tsk_good, stats_tsk_right, stats_tsk_left,
638 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100639#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100640
641
642/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100643/* debugging *******************************************************/
644/*********************************************************************/
645#ifdef DEBUG_FULL
646static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
647static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
648#endif
649
650/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100651/* function prototypes *********************************************/
652/*********************************************************************/
653
654int event_accept(int fd);
655int event_cli_read(int fd);
656int event_cli_write(int fd);
657int event_srv_read(int fd);
658int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100659int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100660
661/*********************************************************************/
662/* general purpose functions ***************************************/
663/*********************************************************************/
664
665void display_version() {
666 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreauc1cae632005-12-17 14:12:23 +0100667 printf("Copyright 2000-2003 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100668}
669
670/*
671 * This function prints the command line usage and exits
672 */
673void usage(char *name) {
674 display_version();
675 fprintf(stderr,
676 "Usage : %s -f <cfgfile> [ -vd"
677#if STATTIME > 0
678 "sl"
679#endif
680 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
681 " -v displays version\n"
682 " -d enters debug mode\n"
683#if STATTIME > 0
684 " -s enables statistics output\n"
685 " -l enables long statistics format\n"
686#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100687 " -D goes daemon ; implies -q\n"
688 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100689 " -n sets the maximum total # of connections (%d)\n"
690 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100691 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100692 exit(1);
693}
694
695
696/*
697 * Displays the message on stderr with the date and pid.
698 */
699void Alert(char *fmt, ...) {
700 va_list argp;
701 struct timeval tv;
702 struct tm *tm;
703
willy tarreau9fe663a2005-12-17 13:02:59 +0100704 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100705 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100706
willy tarreau5cbea6f2005-12-17 12:48:26 +0100707 gettimeofday(&tv, NULL);
708 tm=localtime(&tv.tv_sec);
709 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100710 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100711 vfprintf(stderr, fmt, argp);
712 fflush(stderr);
713 va_end(argp);
714 }
willy tarreau0f7af912005-12-17 12:21:26 +0100715}
716
717
718/*
719 * Displays the message on stderr with the date and pid.
720 */
721void Warning(char *fmt, ...) {
722 va_list argp;
723 struct timeval tv;
724 struct tm *tm;
725
willy tarreau9fe663a2005-12-17 13:02:59 +0100726 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100727 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100728
willy tarreau5cbea6f2005-12-17 12:48:26 +0100729 gettimeofday(&tv, NULL);
730 tm=localtime(&tv.tv_sec);
731 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100732 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100733 vfprintf(stderr, fmt, argp);
734 fflush(stderr);
735 va_end(argp);
736 }
737}
738
739/*
740 * Displays the message on <out> only if quiet mode is not set.
741 */
742void qfprintf(FILE *out, char *fmt, ...) {
743 va_list argp;
744
willy tarreau9fe663a2005-12-17 13:02:59 +0100745 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100746 va_start(argp, fmt);
747 vfprintf(out, fmt, argp);
748 fflush(out);
749 va_end(argp);
750 }
willy tarreau0f7af912005-12-17 12:21:26 +0100751}
752
753
754/*
755 * converts <str> to a struct sockaddr_in* which is locally allocated.
756 * The format is "addr:port", where "addr" can be empty or "*" to indicate
757 * INADDR_ANY.
758 */
759struct sockaddr_in *str2sa(char *str) {
760 static struct sockaddr_in sa;
761 char *c;
762 int port;
763
willy tarreaua1598082005-12-17 13:08:06 +0100764 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100765 str=strdup(str);
766
767 if ((c=strrchr(str,':')) != NULL) {
768 *c++=0;
769 port=atol(c);
770 }
771 else
772 port=0;
773
774 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
775 sa.sin_addr.s_addr = INADDR_ANY;
776 }
777 else if (
778#ifndef SOLARIS
779 !inet_aton(str, &sa.sin_addr)
780#else
781 !inet_pton(AF_INET, str, &sa.sin_addr)
782#endif
783 ) {
784 struct hostent *he;
785
786 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100787 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100788 }
789 else
790 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
791 }
792 sa.sin_port=htons(port);
793 sa.sin_family=AF_INET;
794
795 free(str);
796 return &sa;
797}
798
willy tarreau9fe663a2005-12-17 13:02:59 +0100799
800/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100801 * converts <str> to a list of listeners which are dynamically allocated.
802 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
803 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
804 * - <port> is a numerical port from 1 to 65535 ;
805 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
806 * This can be repeated as many times as necessary, separated by a coma.
807 * The <tail> argument is a pointer to a current list which should be appended
808 * to the tail of the new list. The pointer to the new list is returned.
809 */
810struct listener *str2listener(char *str, struct listener *tail) {
811 struct listener *l;
812 char *c, *next, *range, *dupstr;
813 int port, end;
814
815 next = dupstr = strdup(str);
816
817 while (next && *next) {
818 str = next;
819 /* 1) look for the end of the first address */
820 if ((next = strrchr(str, ',')) != NULL) {
821 *next++ = 0;
822 }
823
824 /* 2) look for the addr/port delimiter */
825 if ((range = strrchr(str, ':')) != NULL) {
826 *range++ = 0;
827 }
828 else {
829 Alert("Missing port number: '%s'\n", str);
830 }
831
832 /* 3) look for the port-end delimiter */
833 if ((c = strchr(range, '-')) != NULL) {
834 *c++ = 0;
835 end = atol(c);
836 }
837 else {
838 end = atol(range);
839 }
840
841 for (port = atol(range); port <= end; port++) {
842 l = (struct listener *)calloc(1, sizeof(struct listener));
843 l->next = tail;
844 tail = l;
845
846 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
847 l->addr.sin_addr.s_addr = INADDR_ANY;
848 }
849 else if (
850#ifndef SOLARIS
851 !inet_aton(str, &l->addr.sin_addr)
852#else
853 !inet_pton(AF_INET, str, &l->addr.sin_addr)
854#endif
855 ) {
856 struct hostent *he;
857
858 if ((he = gethostbyname(str)) == NULL) {
859 Alert("Invalid server name: '%s'\n", str);
860 }
861 else
862 l->addr.sin_addr = *(struct in_addr *) *(he->h_addr_list);
863 }
864 l->addr.sin_port=htons(port);
865 l->addr.sin_family=AF_INET;
866 } /* end for(port) */
867 } /* end while(next) */
868 free(dupstr);
869 return tail;
870}
871
872
873/*
willy tarreau9fe663a2005-12-17 13:02:59 +0100874 * This function sends a syslog message to both log servers of a proxy,
875 * or to global log servers if the proxy is NULL.
876 * It also tries not to waste too much time computing the message header.
877 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100878 */
879void send_log(struct proxy *p, int level, char *message, ...) {
880 static int logfd = -1; /* syslog UDP socket */
881 static long tvsec = -1; /* to force the string to be initialized */
882 struct timeval tv;
883 va_list argp;
884 static char logmsg[MAX_SYSLOG_LEN];
885 static char *dataptr = NULL;
886 int fac_level;
887 int hdr_len, data_len;
888 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +0100889 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +0100890 int nbloggers = 0;
891 char *log_ptr;
892
893 if (logfd < 0) {
894 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
895 return;
896 }
897
898 if (level < 0 || progname == NULL || message == NULL)
899 return;
900
901 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100902 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100903 /* this string is rebuild only once a second */
904 struct tm *tm = localtime(&tv.tv_sec);
905 tvsec = tv.tv_sec;
906
willy tarreauc29948c2005-12-17 13:10:27 +0100907 hdr_len = snprintf(logmsg, sizeof(logmsg),
908 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
909 monthname[tm->tm_mon],
910 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
911 progname, pid);
912 /* WARNING: depending upon implementations, snprintf may return
913 * either -1 or the number of bytes that would be needed to store
914 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100915 */
willy tarreauc29948c2005-12-17 13:10:27 +0100916 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
917 hdr_len = sizeof(logmsg);
918
919 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100920 }
921
922 va_start(argp, message);
923 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100924 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
925 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100926 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100927 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100928
929 if (p == NULL) {
930 if (global.logfac1 >= 0) {
931 sa[nbloggers] = &global.logsrv1;
932 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100933 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100934 nbloggers++;
935 }
936 if (global.logfac2 >= 0) {
937 sa[nbloggers] = &global.logsrv2;
938 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100939 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100940 nbloggers++;
941 }
942 } else {
943 if (p->logfac1 >= 0) {
944 sa[nbloggers] = &p->logsrv1;
945 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100946 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100947 nbloggers++;
948 }
949 if (p->logfac2 >= 0) {
950 sa[nbloggers] = &p->logsrv2;
951 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100952 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100953 nbloggers++;
954 }
955 }
956
957 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +0100958 /* we can filter the level of the messages that are sent to each logger */
959 if (level > loglevel[nbloggers])
960 continue;
961
willy tarreauc29948c2005-12-17 13:10:27 +0100962 /* For each target, we may have a different facility.
963 * We can also have a different log level for each message.
964 * This induces variations in the message header length.
965 * Since we don't want to recompute it each time, nor copy it every
966 * time, we only change the facility in the pre-computed header,
967 * and we change the pointer to the header accordingly.
968 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100969 fac_level = (facilities[nbloggers] << 3) + level;
970 log_ptr = logmsg + 3; /* last digit of the log level */
971 do {
972 *log_ptr = '0' + fac_level % 10;
973 fac_level /= 10;
974 log_ptr--;
975 } while (fac_level && log_ptr > logmsg);
976 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100977
willy tarreauc29948c2005-12-17 13:10:27 +0100978 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100979
980#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100981 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100982 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
983#else
willy tarreauc29948c2005-12-17 13:10:27 +0100984 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100985 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
986#endif
987 }
willy tarreau0f7af912005-12-17 12:21:26 +0100988}
989
990
991/* sets <tv> to the current time */
992static inline struct timeval *tv_now(struct timeval *tv) {
993 if (tv)
994 gettimeofday(tv, NULL);
995 return tv;
996}
997
998/*
999 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1000 */
1001static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1002 if (!tv || !from)
1003 return NULL;
1004 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1005 tv->tv_sec = from->tv_sec + (ms/1000);
1006 while (tv->tv_usec >= 1000000) {
1007 tv->tv_usec -= 1000000;
1008 tv->tv_sec++;
1009 }
1010 return tv;
1011}
1012
1013/*
1014 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1015 */
1016static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001017 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001018 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001019 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001020 return 1;
1021 else if (tv1->tv_usec < tv2->tv_usec)
1022 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001023 else if (tv1->tv_usec > tv2->tv_usec)
1024 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001025 else
1026 return 0;
1027}
1028
1029/*
1030 * returns the absolute difference, in ms, between tv1 and tv2
1031 */
1032unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1033 int cmp;
1034 unsigned long ret;
1035
1036
willy tarreauef900ab2005-12-17 12:52:52 +01001037 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001038 if (!cmp)
1039 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001040 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001041 struct timeval *tmp = tv1;
1042 tv1 = tv2;
1043 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001044 }
willy tarreauef900ab2005-12-17 12:52:52 +01001045 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001046 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001047 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001048 else
willy tarreauef900ab2005-12-17 12:52:52 +01001049 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001050 return (unsigned long) ret;
1051}
1052
1053/*
willy tarreau750a4722005-12-17 13:21:24 +01001054 * returns the difference, in ms, between tv1 and tv2
1055 */
1056static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1057 unsigned long ret;
1058
willy tarreau6e682ce2005-12-17 13:26:49 +01001059 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1060 if (tv2->tv_usec > tv1->tv_usec)
1061 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001062 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001063 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001064 return (unsigned long) ret;
1065}
1066
1067/*
willy tarreau0f7af912005-12-17 12:21:26 +01001068 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1069 */
1070static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001071 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001072 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001073 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001074 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1075 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001076 else
1077 return 0;
1078 }
willy tarreau0f7af912005-12-17 12:21:26 +01001079 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001080 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001081 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001082 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1083 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1084 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001085 else
1086 return 0;
1087}
1088
1089/*
1090 * returns the remaining time between tv1=now and event=tv2
1091 * if tv2 is passed, 0 is returned.
1092 */
1093static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1094 unsigned long ret;
1095
willy tarreau0f7af912005-12-17 12:21:26 +01001096 if (tv_cmp_ms(tv1, tv2) >= 0)
1097 return 0; /* event elapsed */
1098
willy tarreauef900ab2005-12-17 12:52:52 +01001099 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001100 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001101 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001102 else
willy tarreauef900ab2005-12-17 12:52:52 +01001103 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001104 return (unsigned long) ret;
1105}
1106
1107
1108/*
1109 * zeroes a struct timeval
1110 */
1111
1112static inline struct timeval *tv_eternity(struct timeval *tv) {
1113 tv->tv_sec = tv->tv_usec = 0;
1114 return tv;
1115}
1116
1117/*
1118 * returns 1 if tv is null, else 0
1119 */
1120static inline int tv_iseternity(struct timeval *tv) {
1121 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1122 return 1;
1123 else
1124 return 0;
1125}
1126
1127/*
1128 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1129 * considering that 0 is the eternity.
1130 */
1131static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1132 if (tv_iseternity(tv1))
1133 if (tv_iseternity(tv2))
1134 return 0; /* same */
1135 else
1136 return 1; /* tv1 later than tv2 */
1137 else if (tv_iseternity(tv2))
1138 return -1; /* tv2 later than tv1 */
1139
1140 if (tv1->tv_sec > tv2->tv_sec)
1141 return 1;
1142 else if (tv1->tv_sec < tv2->tv_sec)
1143 return -1;
1144 else if (tv1->tv_usec > tv2->tv_usec)
1145 return 1;
1146 else if (tv1->tv_usec < tv2->tv_usec)
1147 return -1;
1148 else
1149 return 0;
1150}
1151
1152/*
1153 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1154 * considering that 0 is the eternity.
1155 */
1156static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1157 if (tv_iseternity(tv1))
1158 if (tv_iseternity(tv2))
1159 return 0; /* same */
1160 else
1161 return 1; /* tv1 later than tv2 */
1162 else if (tv_iseternity(tv2))
1163 return -1; /* tv2 later than tv1 */
1164
willy tarreauefae1842005-12-17 12:51:03 +01001165 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001166 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001167 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001168 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001169 return -1;
1170 else
1171 return 0;
1172 }
1173 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001174 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001175 return 1;
1176 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001177 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001178 return -1;
1179 else
1180 return 0;
1181}
1182
1183/*
1184 * returns the first event between tv1 and tv2 into tvmin.
1185 * a zero tv is ignored. tvmin is returned.
1186 */
1187static inline struct timeval *tv_min(struct timeval *tvmin,
1188 struct timeval *tv1, struct timeval *tv2) {
1189
1190 if (tv_cmp2(tv1, tv2) <= 0)
1191 *tvmin = *tv1;
1192 else
1193 *tvmin = *tv2;
1194
1195 return tvmin;
1196}
1197
1198
1199
1200/***********************************************************/
1201/* fd management ***************************************/
1202/***********************************************************/
1203
1204
1205
willy tarreau5cbea6f2005-12-17 12:48:26 +01001206/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1207 * The file descriptor is also closed.
1208 */
willy tarreau0f7af912005-12-17 12:21:26 +01001209static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001210 FD_CLR(fd, StaticReadEvent);
1211 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001212 close(fd);
1213 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001214
1215 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1216 maxfd--;
1217}
1218
1219/* recomputes the maxfd limit from the fd */
1220static inline void fd_insert(int fd) {
1221 if (fd+1 > maxfd)
1222 maxfd = fd+1;
1223}
1224
1225/*************************************************************/
1226/* task management ***************************************/
1227/*************************************************************/
1228
willy tarreau5cbea6f2005-12-17 12:48:26 +01001229/* puts the task <t> in run queue <q>, and returns <t> */
1230static inline struct task *task_wakeup(struct task **q, struct task *t) {
1231 if (t->state == TASK_RUNNING)
1232 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001233 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001234 t->rqnext = *q;
1235 t->state = TASK_RUNNING;
1236 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001237 }
1238}
1239
willy tarreau5cbea6f2005-12-17 12:48:26 +01001240/* removes the task <t> from the queue <q>
1241 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001242 * set the run queue to point to the next one, and return it
1243 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001244static inline struct task *task_sleep(struct task **q, struct task *t) {
1245 if (t->state == TASK_RUNNING) {
1246 *q = t->rqnext;
1247 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001248 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001249 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001250}
1251
1252/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001253 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001254 * from the run queue. A pointer to the task itself is returned.
1255 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001256static inline struct task *task_delete(struct task *t) {
1257 t->prev->next = t->next;
1258 t->next->prev = t->prev;
1259 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001260}
1261
1262/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001263 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001264 */
1265static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001266 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001267}
1268
willy tarreau5cbea6f2005-12-17 12:48:26 +01001269/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001270 * may be only moved or left where it was, depending on its timing requirements.
1271 * <task> is returned.
1272 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001273struct task *task_queue(struct task *task) {
1274 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001275 struct task *start_from;
1276
1277 /* first, test if the task was already in a list */
1278 if (task->prev == NULL) {
1279 // start_from = list;
1280 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001281#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001282 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001283#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001284 /* insert the unlinked <task> into the list, searching back from the last entry */
1285 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1286 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001287#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001288 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001289#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001290 }
1291
1292 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1293 // start_from = start_from->next;
1294 // stats_tsk_nsrch++;
1295 // }
1296 }
1297 else if (task->prev == list ||
1298 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1299 start_from = task->next;
1300 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001301#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001302 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001303#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001304 return task; /* it's already in the right place */
1305 }
1306
willy tarreau750a4722005-12-17 13:21:24 +01001307#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001308 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001309#endif
1310
1311 /* if the task is not at the right place, there's little chance that
1312 * it has only shifted a bit, and it will nearly always be queued
1313 * at the end of the list because of constant timeouts
1314 * (observed in real case).
1315 */
1316#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1317 start_from = list->prev; /* assume we'll queue to the end of the list */
1318 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1319 start_from = start_from->prev;
1320#if STATTIME > 0
1321 stats_tsk_lsrch++;
1322#endif
1323 }
1324#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001325 /* insert the unlinked <task> into the list, searching after position <start_from> */
1326 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1327 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001328#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001329 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001330#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001331 }
willy tarreau750a4722005-12-17 13:21:24 +01001332#endif /* WE_REALLY_... */
1333
willy tarreau0f7af912005-12-17 12:21:26 +01001334 /* we need to unlink it now */
1335 task_delete(task);
1336 }
1337 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001338#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001339 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001340#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001341#ifdef LEFT_TO_TOP /* not very good */
1342 start_from = list;
1343 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1344 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001345#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001346 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001347#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001348 }
1349#else
1350 start_from = task->prev->prev; /* valid because of the previous test above */
1351 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1352 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001353#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001354 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001355#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001356 }
1357#endif
1358 /* we need to unlink it now */
1359 task_delete(task);
1360 }
1361 task->prev = start_from;
1362 task->next = start_from->next;
1363 task->next->prev = task;
1364 start_from->next = task;
1365 return task;
1366}
1367
1368
1369/*********************************************************************/
1370/* more specific functions ***************************************/
1371/*********************************************************************/
1372
1373/* some prototypes */
1374static int maintain_proxies(void);
1375
willy tarreau5cbea6f2005-12-17 12:48:26 +01001376/* this either returns the sockname or the original destination address. Code
1377 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1378 */
1379static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001380#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001381 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1382#else
willy tarreaua1598082005-12-17 13:08:06 +01001383#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001384 return getsockname(fd, (struct sockaddr *)sa, salen);
1385#else
1386 return -1;
1387#endif
1388#endif
1389}
1390
1391/*
1392 * frees the context associated to a session. It must have been removed first.
1393 */
1394static inline void session_free(struct session *s) {
1395 if (s->req)
1396 pool_free(buffer, s->req);
1397 if (s->rep)
1398 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001399 if (s->logs.uri)
1400 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001401 if (s->logs.cli_cookie)
1402 pool_free(capture, s->logs.cli_cookie);
1403 if (s->logs.srv_cookie)
1404 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001405
willy tarreau5cbea6f2005-12-17 12:48:26 +01001406 pool_free(session, s);
1407}
1408
willy tarreau0f7af912005-12-17 12:21:26 +01001409
1410/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001411 * This function tries to find a running server for the proxy <px>. A first
1412 * pass looks for active servers, and if none is found, a second pass also
1413 * looks for backup servers.
1414 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1415 */
1416static inline struct server *find_server(struct proxy *px) {
1417 struct server *srv = px->cursrv;
1418 int ignore_backup = 1;
1419
1420 do {
1421 do {
1422 if (srv == NULL)
1423 srv = px->srv;
1424 if (srv->state & SRV_RUNNING
1425 && !((srv->state & SRV_BACKUP) && ignore_backup))
1426 return srv;
1427 srv = srv->next;
1428 } while (srv != px->cursrv);
1429 } while (ignore_backup--);
1430 return NULL;
1431}
1432
1433/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001434 * This function initiates a connection to the current server (s->srv) if (s->direct)
1435 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001436 * it's OK, -1 if it's impossible.
1437 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001438int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001439 int one = 1;
1440 int fd;
1441
1442 // fprintf(stderr,"connect_server : s=%p\n",s);
1443
willy tarreaue39cd132005-12-17 13:00:18 +01001444 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001445 s->srv_addr = s->srv->addr;
1446 }
1447 else if (s->proxy->options & PR_O_BALANCE) {
1448 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001449 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001450
willy tarreau8337c6b2005-12-17 13:41:01 +01001451 srv = find_server(s->proxy);
1452
1453 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001454 return -1;
1455
willy tarreau8337c6b2005-12-17 13:41:01 +01001456 s->srv_addr = srv->addr;
1457 s->srv = srv;
1458 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001459 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001460 else /* unknown balancing algorithm */
1461 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001462 }
willy tarreaua1598082005-12-17 13:08:06 +01001463 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001464 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001465 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001466 }
1467 else if (s->proxy->options & PR_O_TRANSP) {
1468 /* in transparent mode, use the original dest addr if no dispatch specified */
1469 int salen = sizeof(struct sockaddr_in);
1470 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1471 qfprintf(stderr, "Cannot get original server address.\n");
1472 return -1;
1473 }
1474 }
willy tarreau0f7af912005-12-17 12:21:26 +01001475
willy tarreaua41a8b42005-12-17 14:02:24 +01001476 /* if this server remaps proxied ports, we'll use
1477 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001478 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001479 struct sockaddr_in sockname;
1480 int namelen;
1481
1482 namelen = sizeof(sockname);
1483 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1484 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1485 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1486 }
1487
willy tarreau0f7af912005-12-17 12:21:26 +01001488 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001489 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001490 return -1;
1491 }
1492
willy tarreau9fe663a2005-12-17 13:02:59 +01001493 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001494 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1495 close(fd);
1496 return -1;
1497 }
1498
willy tarreau0f7af912005-12-17 12:21:26 +01001499 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1500 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001501 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001502 close(fd);
1503 return -1;
1504 }
1505
willy tarreaua1598082005-12-17 13:08:06 +01001506 /* allow specific binding */
1507 if (s->proxy->options & PR_O_BIND_SRC &&
1508 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1509 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1510 close(fd);
1511 return -1;
1512 }
1513
willy tarreau0f7af912005-12-17 12:21:26 +01001514 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1515 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001516 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001517 close(fd);
1518 return -1;
1519 }
1520 else if (errno != EALREADY && errno != EISCONN) {
1521 close(fd);
1522 return -1;
1523 }
1524 }
1525
willy tarreau5cbea6f2005-12-17 12:48:26 +01001526 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001527 fdtab[fd].read = &event_srv_read;
1528 fdtab[fd].write = &event_srv_write;
1529 fdtab[fd].state = FD_STCONN; /* connection in progress */
1530
1531 FD_SET(fd, StaticWriteEvent); /* for connect status */
1532
1533 fd_insert(fd);
1534
1535 if (s->proxy->contimeout)
1536 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1537 else
1538 tv_eternity(&s->cnexpire);
1539 return 0;
1540}
1541
1542/*
1543 * this function is called on a read event from a client socket.
1544 * It returns 0.
1545 */
1546int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001547 struct task *t = fdtab[fd].owner;
1548 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001549 struct buffer *b = s->req;
1550 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001551
1552 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1553
willy tarreau0f7af912005-12-17 12:21:26 +01001554 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001555 while (1) {
1556 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1557 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001558 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001559 }
1560 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001561 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562 }
1563 else {
1564 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001565 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1566 * since it means that the rewrite protection has been removed. This
1567 * implies that the if statement can be removed.
1568 */
1569 if (max > b->rlim - b->data)
1570 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001571 }
1572
1573 if (max == 0) { /* not anymore room to store data */
1574 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001575 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001576 }
1577
willy tarreau3242e862005-12-17 12:27:53 +01001578#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001579 {
1580 int skerr, lskerr;
1581
1582 lskerr = sizeof(skerr);
1583 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1584 if (skerr)
1585 ret = -1;
1586 else
1587 ret = recv(fd, b->r, max, 0);
1588 }
willy tarreau3242e862005-12-17 12:27:53 +01001589#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001590 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001591#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001592 if (ret > 0) {
1593 b->r += ret;
1594 b->l += ret;
1595 s->res_cr = RES_DATA;
1596
1597 if (b->r == b->data + BUFSIZE) {
1598 b->r = b->data; /* wrap around the buffer */
1599 }
willy tarreaua1598082005-12-17 13:08:06 +01001600
1601 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001602 /* we hope to read more data or to get a close on next round */
1603 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001604 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001605 else if (ret == 0) {
1606 s->res_cr = RES_NULL;
1607 break;
1608 }
1609 else if (errno == EAGAIN) {/* ignore EAGAIN */
1610 break;
1611 }
1612 else {
1613 s->res_cr = RES_ERROR;
1614 fdtab[fd].state = FD_STERROR;
1615 break;
1616 }
1617 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001618 }
1619 else {
1620 s->res_cr = RES_ERROR;
1621 fdtab[fd].state = FD_STERROR;
1622 }
1623
willy tarreau5cbea6f2005-12-17 12:48:26 +01001624 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001625 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001626 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1627 else
1628 tv_eternity(&s->crexpire);
1629
1630 task_wakeup(&rq, t);
1631 }
willy tarreau0f7af912005-12-17 12:21:26 +01001632
willy tarreau0f7af912005-12-17 12:21:26 +01001633 return 0;
1634}
1635
1636
1637/*
1638 * this function is called on a read event from a server socket.
1639 * It returns 0.
1640 */
1641int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001642 struct task *t = fdtab[fd].owner;
1643 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001644 struct buffer *b = s->rep;
1645 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001646
1647 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1648
willy tarreau0f7af912005-12-17 12:21:26 +01001649 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001650 while (1) {
1651 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1652 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001653 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001654 }
1655 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001656 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001657 }
1658 else {
1659 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001660 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1661 * since it means that the rewrite protection has been removed. This
1662 * implies that the if statement can be removed.
1663 */
1664 if (max > b->rlim - b->data)
1665 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001666 }
1667
1668 if (max == 0) { /* not anymore room to store data */
1669 FD_CLR(fd, StaticReadEvent);
1670 break;
1671 }
1672
willy tarreau3242e862005-12-17 12:27:53 +01001673#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001674 {
1675 int skerr, lskerr;
1676
1677 lskerr = sizeof(skerr);
1678 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1679 if (skerr)
1680 ret = -1;
1681 else
1682 ret = recv(fd, b->r, max, 0);
1683 }
willy tarreau3242e862005-12-17 12:27:53 +01001684#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001685 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001686#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001687 if (ret > 0) {
1688 b->r += ret;
1689 b->l += ret;
1690 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001691
willy tarreau5cbea6f2005-12-17 12:48:26 +01001692 if (b->r == b->data + BUFSIZE) {
1693 b->r = b->data; /* wrap around the buffer */
1694 }
willy tarreaua1598082005-12-17 13:08:06 +01001695
1696 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 /* we hope to read more data or to get a close on next round */
1698 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001699 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700 else if (ret == 0) {
1701 s->res_sr = RES_NULL;
1702 break;
1703 }
1704 else if (errno == EAGAIN) {/* ignore EAGAIN */
1705 break;
1706 }
1707 else {
1708 s->res_sr = RES_ERROR;
1709 fdtab[fd].state = FD_STERROR;
1710 break;
1711 }
1712 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001713 }
1714 else {
1715 s->res_sr = RES_ERROR;
1716 fdtab[fd].state = FD_STERROR;
1717 }
1718
willy tarreau5cbea6f2005-12-17 12:48:26 +01001719 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001720 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001721 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1722 else
1723 tv_eternity(&s->srexpire);
1724
1725 task_wakeup(&rq, t);
1726 }
willy tarreau0f7af912005-12-17 12:21:26 +01001727
willy tarreau0f7af912005-12-17 12:21:26 +01001728 return 0;
1729}
1730
1731/*
1732 * this function is called on a write event from a client socket.
1733 * It returns 0.
1734 */
1735int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001736 struct task *t = fdtab[fd].owner;
1737 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001738 struct buffer *b = s->rep;
1739 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001740
1741 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1742
1743 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001744 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001745 // max = BUFSIZE; BUG !!!!
1746 max = 0;
1747 }
1748 else if (b->r > b->w) {
1749 max = b->r - b->w;
1750 }
1751 else
1752 max = b->data + BUFSIZE - b->w;
1753
willy tarreau0f7af912005-12-17 12:21:26 +01001754 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001755#ifndef MSG_NOSIGNAL
1756 int skerr, lskerr;
1757#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001758
1759 if (max == 0) {
1760 s->res_cw = RES_NULL;
1761 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001762 tv_eternity(&s->cwexpire);
1763 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001764 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001765 }
1766
willy tarreau3242e862005-12-17 12:27:53 +01001767#ifndef MSG_NOSIGNAL
1768 lskerr=sizeof(skerr);
1769 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1770 if (skerr)
1771 ret = -1;
1772 else
1773 ret = send(fd, b->w, max, MSG_DONTWAIT);
1774#else
willy tarreau0f7af912005-12-17 12:21:26 +01001775 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001776#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001777
1778 if (ret > 0) {
1779 b->l -= ret;
1780 b->w += ret;
1781
1782 s->res_cw = RES_DATA;
1783
1784 if (b->w == b->data + BUFSIZE) {
1785 b->w = b->data; /* wrap around the buffer */
1786 }
1787 }
1788 else if (ret == 0) {
1789 /* nothing written, just make as if we were never called */
1790// s->res_cw = RES_NULL;
1791 return 0;
1792 }
1793 else if (errno == EAGAIN) /* ignore EAGAIN */
1794 return 0;
1795 else {
1796 s->res_cw = RES_ERROR;
1797 fdtab[fd].state = FD_STERROR;
1798 }
1799 }
1800 else {
1801 s->res_cw = RES_ERROR;
1802 fdtab[fd].state = FD_STERROR;
1803 }
1804
willy tarreaub1ff9db2005-12-17 13:51:03 +01001805 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001806 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001807 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
1808 s->crexpire = s->cwexpire;
1809 }
willy tarreau0f7af912005-12-17 12:21:26 +01001810 else
1811 tv_eternity(&s->cwexpire);
1812
willy tarreau5cbea6f2005-12-17 12:48:26 +01001813 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001814 return 0;
1815}
1816
1817
1818/*
1819 * this function is called on a write event from a server socket.
1820 * It returns 0.
1821 */
1822int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001823 struct task *t = fdtab[fd].owner;
1824 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001825 struct buffer *b = s->req;
1826 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001827
1828 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1829
1830 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001831 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001832 // max = BUFSIZE; BUG !!!!
1833 max = 0;
1834 }
1835 else if (b->r > b->w) {
1836 max = b->r - b->w;
1837 }
1838 else
1839 max = b->data + BUFSIZE - b->w;
1840
willy tarreau0f7af912005-12-17 12:21:26 +01001841 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001842#ifndef MSG_NOSIGNAL
1843 int skerr, lskerr;
1844#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001845 if (max == 0) {
1846 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001847 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001848 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001849 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01001850 tv_eternity(&s->swexpire);
1851 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01001852 return 0;
1853 }
1854
willy tarreauef900ab2005-12-17 12:52:52 +01001855
willy tarreau3242e862005-12-17 12:27:53 +01001856#ifndef MSG_NOSIGNAL
1857 lskerr=sizeof(skerr);
1858 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1859 if (skerr)
1860 ret = -1;
1861 else
1862 ret = send(fd, b->w, max, MSG_DONTWAIT);
1863#else
willy tarreau0f7af912005-12-17 12:21:26 +01001864 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001865#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001866 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001867 if (ret > 0) {
1868 b->l -= ret;
1869 b->w += ret;
1870
1871 s->res_sw = RES_DATA;
1872
1873 if (b->w == b->data + BUFSIZE) {
1874 b->w = b->data; /* wrap around the buffer */
1875 }
1876 }
1877 else if (ret == 0) {
1878 /* nothing written, just make as if we were never called */
1879 // s->res_sw = RES_NULL;
1880 return 0;
1881 }
1882 else if (errno == EAGAIN) /* ignore EAGAIN */
1883 return 0;
1884 else {
1885 s->res_sw = RES_ERROR;
1886 fdtab[fd].state = FD_STERROR;
1887 }
1888 }
1889 else {
1890 s->res_sw = RES_ERROR;
1891 fdtab[fd].state = FD_STERROR;
1892 }
1893
willy tarreaub1ff9db2005-12-17 13:51:03 +01001894 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001895 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001896 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
1897 s->srexpire = s->swexpire;
1898 }
willy tarreau0f7af912005-12-17 12:21:26 +01001899 else
1900 tv_eternity(&s->swexpire);
1901
willy tarreau5cbea6f2005-12-17 12:48:26 +01001902 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001903 return 0;
1904}
1905
1906
1907/*
willy tarreaue39cd132005-12-17 13:00:18 +01001908 * returns a message to the client ; the connection is shut down for read,
1909 * and the request is cleared so that no server connection can be initiated.
1910 * The client must be in a valid state for this (HEADER, DATA ...).
1911 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01001912 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001913 */
1914void client_retnclose(struct session *s, int len, const char *msg) {
1915 FD_CLR(s->cli_fd, StaticReadEvent);
1916 FD_SET(s->cli_fd, StaticWriteEvent);
1917 tv_eternity(&s->crexpire);
1918 shutdown(s->cli_fd, SHUT_RD);
1919 s->cli_state = CL_STSHUTR;
1920 strcpy(s->rep->data, msg);
1921 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001922 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001923 s->rep->r += len;
1924 s->req->l = 0;
1925}
1926
1927
1928/*
1929 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01001930 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001931 */
1932void client_return(struct session *s, int len, const char *msg) {
1933 strcpy(s->rep->data, msg);
1934 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001935 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001936 s->rep->r += len;
1937 s->req->l = 0;
1938}
1939
willy tarreau9fe663a2005-12-17 13:02:59 +01001940/*
1941 * send a log for the session when we have enough info about it
1942 */
1943void sess_log(struct session *s) {
1944 unsigned char *pn;
1945 struct proxy *p = s->proxy;
1946 int log;
1947 char *uri;
1948 char *pxid;
1949 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01001950 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01001951
1952 /* This is a first attempt at a better logging system.
1953 * For now, we rely on send_log() to provide the date, although it obviously
1954 * is the date of the log and not of the request, and most fields are not
1955 * computed.
1956 */
1957
willy tarreaua1598082005-12-17 13:08:06 +01001958 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001959
1960 pn = (log & LW_CLIP) ?
1961 (unsigned char *)&s->cli_addr.sin_addr :
1962 (unsigned char *)"\0\0\0\0";
1963
willy tarreauc1cae632005-12-17 14:12:23 +01001964 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01001965 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01001966 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01001967
willy tarreauc1cae632005-12-17 14:12:23 +01001968 tm = localtime(&s->logs.tv_accept.tv_sec);
1969 if (p->to_log & LW_REQ) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001970 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
willy tarreaua1598082005-12-17 13:08:06 +01001971 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1972 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1973 tm->tm_hour, tm->tm_min, tm->tm_sec,
1974 pxid, srv,
1975 s->logs.t_request,
1976 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1977 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1978 s->logs.t_close,
1979 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001980 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1981 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01001982 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
1983 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
1984 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
1985 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01001986 uri);
1987 }
1988 else {
willy tarreauc1cae632005-12-17 14:12:23 +01001989 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d %lld %c%c\n",
willy tarreaua1598082005-12-17 13:08:06 +01001990 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
willy tarreauc1cae632005-12-17 14:12:23 +01001991 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1992 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01001993 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01001994 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreaua1598082005-12-17 13:08:06 +01001995 s->logs.t_close,
willy tarreauc1cae632005-12-17 14:12:23 +01001996 s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01001997 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01001998 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01001999 }
2000
2001 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002002}
2003
willy tarreaue39cd132005-12-17 13:00:18 +01002004
2005/*
willy tarreau0f7af912005-12-17 12:21:26 +01002006 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007 * to an accept. It tries to accept as many connections as possible.
2008 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002009 */
2010int event_accept(int fd) {
2011 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012 struct session *s;
2013 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002014 int cfd;
2015 int one = 1;
2016
willy tarreau5cbea6f2005-12-17 12:48:26 +01002017 while (p->nbconn < p->maxconn) {
2018 struct sockaddr_in addr;
2019 int laddr = sizeof(addr);
2020 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2021 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002022
willy tarreau5cbea6f2005-12-17 12:48:26 +01002023 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2024 Alert("out of memory in event_accept().\n");
2025 FD_CLR(fd, StaticReadEvent);
2026 p->state = PR_STIDLE;
2027 close(cfd);
2028 return 0;
2029 }
willy tarreau0f7af912005-12-17 12:21:26 +01002030
willy tarreau5cbea6f2005-12-17 12:48:26 +01002031 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2032 Alert("out of memory in event_accept().\n");
2033 FD_CLR(fd, StaticReadEvent);
2034 p->state = PR_STIDLE;
2035 close(cfd);
2036 pool_free(session, s);
2037 return 0;
2038 }
willy tarreau0f7af912005-12-17 12:21:26 +01002039
willy tarreau5cbea6f2005-12-17 12:48:26 +01002040 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002041 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002042 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2043 close(cfd);
2044 pool_free(task, t);
2045 pool_free(session, s);
2046 return 0;
2047 }
willy tarreau0f7af912005-12-17 12:21:26 +01002048
willy tarreau5cbea6f2005-12-17 12:48:26 +01002049 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2050 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2051 (char *) &one, sizeof(one)) == -1)) {
2052 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2053 close(cfd);
2054 pool_free(task, t);
2055 pool_free(session, s);
2056 return 0;
2057 }
willy tarreau0f7af912005-12-17 12:21:26 +01002058
willy tarreau9fe663a2005-12-17 13:02:59 +01002059 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2060 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2061 t->state = TASK_IDLE;
2062 t->process = process_session;
2063 t->context = s;
2064
2065 s->task = t;
2066 s->proxy = p;
2067 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2068 s->srv_state = SV_STIDLE;
2069 s->req = s->rep = NULL; /* will be allocated later */
2070 s->flags = 0;
2071 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2072 s->cli_fd = cfd;
2073 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002074 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002075 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002076
2077 s->logs.logwait = p->to_log;
2078 s->logs.tv_accept = now;
2079 s->logs.t_request = -1;
2080 s->logs.t_connect = -1;
2081 s->logs.t_data = -1;
2082 s->logs.t_close = 0;
2083 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002084 s->logs.cli_cookie = NULL;
2085 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002086 s->logs.status = -1;
2087 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002088
willy tarreau2f6ba652005-12-17 13:57:42 +01002089 s->uniq_id = totalconn;
2090
willy tarreau5cbea6f2005-12-17 12:48:26 +01002091 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2092 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01002093 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002094 unsigned char *pn, *sn;
2095 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002096
willy tarreau5cbea6f2005-12-17 12:48:26 +01002097 namelen = sizeof(sockname);
2098 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2099 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
2100 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01002101 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01002102
willy tarreau9fe663a2005-12-17 13:02:59 +01002103 if (p->to_log) {
2104 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002105 if (s->logs.logwait & LW_CLIP)
2106 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002107 sess_log(s);
2108 }
2109 else
2110 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
2111 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
2112 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
2113 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01002114 }
willy tarreau0f7af912005-12-17 12:21:26 +01002115
willy tarreau9fe663a2005-12-17 13:02:59 +01002116 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002117 struct sockaddr_in sockname;
2118 unsigned char *pn, *sn;
2119 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002120 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002121
2122 namelen = sizeof(sockname);
2123 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2124 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
2125 sn = (unsigned char *)&sockname.sin_addr;
2126 pn = (unsigned char *)&s->cli_addr.sin_addr;
2127
2128 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%d.%d.%d.%d:%d]\n",
2129 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2130 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port));
willy tarreauef900ab2005-12-17 12:52:52 +01002131 write(1, trash, len);
2132 }
willy tarreau0f7af912005-12-17 12:21:26 +01002133
willy tarreau5cbea6f2005-12-17 12:48:26 +01002134 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2135 close(cfd); /* nothing can be done for this fd without memory */
2136 pool_free(task, t);
2137 pool_free(session, s);
2138 return 0;
2139 }
2140 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002141 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002142 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2143 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002144 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002145 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002146
willy tarreau5cbea6f2005-12-17 12:48:26 +01002147 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2148 pool_free(buffer, s->req);
2149 close(cfd); /* nothing can be done for this fd without memory */
2150 pool_free(task, t);
2151 pool_free(session, s);
2152 return 0;
2153 }
2154 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002155 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002156 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 +01002157
willy tarreau5cbea6f2005-12-17 12:48:26 +01002158 fdtab[cfd].read = &event_cli_read;
2159 fdtab[cfd].write = &event_cli_write;
2160 fdtab[cfd].owner = t;
2161 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002162
willy tarreau5cbea6f2005-12-17 12:48:26 +01002163 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002164 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2165 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2166 else
2167 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002168 }
2169 else {
2170 FD_SET(cfd, StaticReadEvent);
2171 }
2172
2173 fd_insert(cfd);
2174
2175 tv_eternity(&s->cnexpire);
2176 tv_eternity(&s->srexpire);
2177 tv_eternity(&s->swexpire);
2178 tv_eternity(&s->cwexpire);
2179
2180 if (s->proxy->clitimeout)
2181 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2182 else
2183 tv_eternity(&s->crexpire);
2184
2185 t->expire = s->crexpire;
2186
2187 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002188
2189 if (p->mode != PR_MODE_HEALTH)
2190 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002191
2192 p->nbconn++;
2193 actconn++;
2194 totalconn++;
2195
2196 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2197 } /* end of while (p->nbconn < p->maxconn) */
2198 return 0;
2199}
willy tarreau0f7af912005-12-17 12:21:26 +01002200
willy tarreau0f7af912005-12-17 12:21:26 +01002201
willy tarreau5cbea6f2005-12-17 12:48:26 +01002202/*
2203 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002204 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2205 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002206 * or -1 if an error occured.
2207 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002208int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002209 struct task *t = fdtab[fd].owner;
2210 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002211
willy tarreau5cbea6f2005-12-17 12:48:26 +01002212 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002213 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002214 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002215 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002216 if (skerr)
2217 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002218 else {
2219 if (s->proxy->options & PR_O_HTTP_CHK) {
2220 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002221 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002222 * so we'll send the request, and won't wake the checker up now.
2223 */
2224#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002225 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002226#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002227 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002228#endif
2229 if (ret == 22) {
2230 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2231 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2232 return 0;
2233 }
2234 else
2235 s->result = -1;
2236 }
2237 else {
2238 /* good TCP connection is enough */
2239 s->result = 1;
2240 }
2241 }
2242
2243 task_wakeup(&rq, t);
2244 return 0;
2245}
2246
willy tarreau0f7af912005-12-17 12:21:26 +01002247
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002248/*
2249 * This function is used only for server health-checks. It handles
2250 * the server's reply to an HTTP request. It returns 1 if the server replies
2251 * 2xx or 3xx (valid responses), or -1 in other cases.
2252 */
2253int event_srv_chk_r(int fd) {
2254 char reply[64];
2255 int len;
2256 struct task *t = fdtab[fd].owner;
2257 struct server *s = t->context;
2258
2259 int skerr, lskerr;
2260 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002261
2262 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002263#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002264 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2265 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002266 len = recv(fd, reply, sizeof(reply), 0);
2267#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002268 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2269 * but the connection was closed on the remote end. Fortunately, recv still
2270 * works correctly and we don't need to do the getsockopt() on linux.
2271 */
2272 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002273#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002274 if ((len >= sizeof("HTTP/1.0 000")) &&
2275 !memcmp(reply, "HTTP/1.", 7) &&
2276 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2277 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002278
2279 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002280 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002281 return 0;
2282}
2283
2284
2285/*
2286 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2287 * and moves <end> just after the end of <str>.
2288 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2289 * the shift value (positive or negative) is returned.
2290 * If there's no space left, the move is not done.
2291 *
2292 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002293int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002294 int delta;
2295 int len;
2296
2297 len = strlen(str);
2298 delta = len - (end - pos);
2299
2300 if (delta + b->r >= b->data + BUFSIZE)
2301 return 0; /* no space left */
2302
2303 /* first, protect the end of the buffer */
2304 memmove(end + delta, end, b->data + b->l - end);
2305
2306 /* now, copy str over pos */
2307 memcpy(pos, str,len);
2308
willy tarreau5cbea6f2005-12-17 12:48:26 +01002309 /* we only move data after the displaced zone */
2310 if (b->r > pos) b->r += delta;
2311 if (b->w > pos) b->w += delta;
2312 if (b->h > pos) b->h += delta;
2313 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002314 b->l += delta;
2315
2316 return delta;
2317}
2318
willy tarreau8337c6b2005-12-17 13:41:01 +01002319/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002320 * len is 0.
2321 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002322int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002323 int delta;
2324
2325 delta = len - (end - pos);
2326
2327 if (delta + b->r >= b->data + BUFSIZE)
2328 return 0; /* no space left */
2329
2330 /* first, protect the end of the buffer */
2331 memmove(end + delta, end, b->data + b->l - end);
2332
2333 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002334 if (len)
2335 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002336
willy tarreau5cbea6f2005-12-17 12:48:26 +01002337 /* we only move data after the displaced zone */
2338 if (b->r > pos) b->r += delta;
2339 if (b->w > pos) b->w += delta;
2340 if (b->h > pos) b->h += delta;
2341 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002342 b->l += delta;
2343
2344 return delta;
2345}
2346
2347
2348int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2349 char *old_dst = dst;
2350
2351 while (*str) {
2352 if (*str == '\\') {
2353 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002354 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002355 int len, num;
2356
2357 num = *str - '0';
2358 str++;
2359
2360 if (matches[num].rm_so > -1) {
2361 len = matches[num].rm_eo - matches[num].rm_so;
2362 memcpy(dst, src + matches[num].rm_so, len);
2363 dst += len;
2364 }
2365
2366 }
2367 else if (*str == 'x') {
2368 unsigned char hex1, hex2;
2369 str++;
2370
2371 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2372
2373 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2374 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2375 *dst++ = (hex1<<4) + hex2;
2376 }
2377 else
2378 *dst++ = *str++;
2379 }
2380 else
2381 *dst++ = *str++;
2382 }
2383 *dst = 0;
2384 return dst - old_dst;
2385}
2386
willy tarreau9fe663a2005-12-17 13:02:59 +01002387
willy tarreau0f7af912005-12-17 12:21:26 +01002388/*
2389 * manages the client FSM and its socket. BTW, it also tries to handle the
2390 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2391 * 0 else.
2392 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002393int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002394 int s = t->srv_state;
2395 int c = t->cli_state;
2396 struct buffer *req = t->req;
2397 struct buffer *rep = t->rep;
2398
willy tarreau750a4722005-12-17 13:21:24 +01002399#ifdef DEBUG_FULL
2400 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2401#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002402 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2403 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2404 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2405 //);
2406 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002407 /* now parse the partial (or complete) headers */
2408 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2409 char *ptr;
2410 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002411
willy tarreau5cbea6f2005-12-17 12:48:26 +01002412 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002413
willy tarreau0f7af912005-12-17 12:21:26 +01002414 /* look for the end of the current header */
2415 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2416 ptr++;
2417
willy tarreau5cbea6f2005-12-17 12:48:26 +01002418 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002419 int line, len;
2420 /* we can only get here after an end of headers */
2421 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002422
willy tarreaue39cd132005-12-17 13:00:18 +01002423 if (t->flags & SN_CLDENY) {
2424 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002425 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002426 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002427 if (!(t->flags & SN_ERR_MASK))
2428 t->flags |= SN_ERR_PRXCOND;
2429 if (!(t->flags & SN_FINST_MASK))
2430 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002431 return 1;
2432 }
2433
willy tarreau5cbea6f2005-12-17 12:48:26 +01002434 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002435 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2436 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002437 }
willy tarreau0f7af912005-12-17 12:21:26 +01002438
willy tarreau9fe663a2005-12-17 13:02:59 +01002439 if (t->proxy->options & PR_O_FWDFOR) {
2440 /* insert an X-Forwarded-For header */
2441 unsigned char *pn;
2442 pn = (unsigned char *)&t->cli_addr.sin_addr;
willy tarreau750a4722005-12-17 13:21:24 +01002443 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01002444 pn[0], pn[1], pn[2], pn[3]);
willy tarreau750a4722005-12-17 13:21:24 +01002445 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau9fe663a2005-12-17 13:02:59 +01002446 }
2447
willy tarreaucd878942005-12-17 13:27:43 +01002448 if (!memcmp(req->data, "POST ", 5))
2449 t->flags |= SN_POST; /* this is a POST request */
2450
willy tarreau5cbea6f2005-12-17 12:48:26 +01002451 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002452 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002453
willy tarreau750a4722005-12-17 13:21:24 +01002454 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002455 /* FIXME: we'll set the client in a wait state while we try to
2456 * connect to the server. Is this really needed ? wouldn't it be
2457 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002458 //FD_CLR(t->cli_fd, StaticReadEvent);
2459 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002460
2461 /* FIXME: if we break here (as up to 1.1.23), having the client
2462 * shutdown its connection can lead to an abort further.
2463 * it's better to either return 1 or even jump directly to the
2464 * data state which will save one schedule.
2465 */
2466 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002467
2468 if (!t->proxy->clitimeout ||
2469 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2470 /* If the client has no timeout, or if the server is not ready yet,
2471 * and we know for sure that it can expire, then it's cleaner to
2472 * disable the timeout on the client side so that too low values
2473 * cannot make the sessions abort too early.
2474 */
2475 tv_eternity(&t->crexpire);
2476
willy tarreau197e8ec2005-12-17 14:10:59 +01002477 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002478 }
willy tarreau0f7af912005-12-17 12:21:26 +01002479
willy tarreau5cbea6f2005-12-17 12:48:26 +01002480 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2481 if (ptr > req->r - 2) {
2482 /* this is a partial header, let's wait for more to come */
2483 req->lr = ptr;
2484 break;
2485 }
willy tarreau0f7af912005-12-17 12:21:26 +01002486
willy tarreau5cbea6f2005-12-17 12:48:26 +01002487 /* now we know that *ptr is either \r or \n,
2488 * and that there are at least 1 char after it.
2489 */
2490 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2491 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2492 else
2493 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002494
willy tarreau5cbea6f2005-12-17 12:48:26 +01002495 /*
2496 * now we know that we have a full header ; we can do whatever
2497 * we want with these pointers :
2498 * req->h = beginning of header
2499 * ptr = end of header (first \r or \n)
2500 * req->lr = beginning of next line (next rep->h)
2501 * req->r = end of data (not used at this stage)
2502 */
willy tarreau0f7af912005-12-17 12:21:26 +01002503
willy tarreau8337c6b2005-12-17 13:41:01 +01002504 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002505 /* we have a complete HTTP request that we must log */
2506 int urilen;
2507
willy tarreaua1598082005-12-17 13:08:06 +01002508 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002509 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002510 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002511 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002512 if (!(t->flags & SN_ERR_MASK))
2513 t->flags |= SN_ERR_PRXCOND;
2514 if (!(t->flags & SN_FINST_MASK))
2515 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002516 return 1;
2517 }
2518
2519 urilen = ptr - req->h;
2520 if (urilen >= REQURI_LEN)
2521 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002522 memcpy(t->logs.uri, req->h, urilen);
2523 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002524
willy tarreaua1598082005-12-17 13:08:06 +01002525 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002526 sess_log(t);
2527 }
2528
willy tarreau5cbea6f2005-12-17 12:48:26 +01002529 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002530
willy tarreau9fe663a2005-12-17 13:02:59 +01002531 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002532 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002533 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 +01002534 max = ptr - req->h;
2535 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002536 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002537 trash[len++] = '\n';
2538 write(1, trash, len);
2539 }
willy tarreau0f7af912005-12-17 12:21:26 +01002540
willy tarreau5cbea6f2005-12-17 12:48:26 +01002541 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002542 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2543 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002544 char term;
2545
2546 term = *ptr;
2547 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002548 exp = t->proxy->req_exp;
2549 do {
2550 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2551 switch (exp->action) {
2552 case ACT_ALLOW:
2553 if (!(t->flags & SN_CLDENY))
2554 t->flags |= SN_CLALLOW;
2555 break;
2556 case ACT_REPLACE:
2557 if (!(t->flags & SN_CLDENY)) {
2558 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2559 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2560 }
2561 break;
2562 case ACT_REMOVE:
2563 if (!(t->flags & SN_CLDENY))
2564 delete_header = 1;
2565 break;
2566 case ACT_DENY:
2567 if (!(t->flags & SN_CLALLOW))
2568 t->flags |= SN_CLDENY;
2569 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002570 case ACT_PASS: /* we simply don't deny this one */
2571 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002572 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002573 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002574 }
willy tarreaue39cd132005-12-17 13:00:18 +01002575 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002576 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002577 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002578
willy tarreau240afa62005-12-17 13:14:35 +01002579 /* Now look for cookies. Conforming to RFC2109, we have to support
2580 * attributes whose name begin with a '$', and associate them with
2581 * the right cookie, if we want to delete this cookie.
2582 * So there are 3 cases for each cookie read :
2583 * 1) it's a special attribute, beginning with a '$' : ignore it.
2584 * 2) it's a server id cookie that we *MAY* want to delete : save
2585 * some pointers on it (last semi-colon, beginning of cookie...)
2586 * 3) it's an application cookie : we *MAY* have to delete a previous
2587 * "special" cookie.
2588 * At the end of loop, if a "special" cookie remains, we may have to
2589 * remove it. If no application cookie persists in the header, we
2590 * *MUST* delete it
2591 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002592 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002593 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01002594 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002595 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002596 char *del_colon, *del_cookie, *colon;
2597 int app_cookies;
2598
willy tarreau5cbea6f2005-12-17 12:48:26 +01002599 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002600 colon = p1;
2601 /* del_cookie == NULL => nothing to be deleted */
2602 del_colon = del_cookie = NULL;
2603 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002604
2605 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002606 /* skip spaces and colons, but keep an eye on these ones */
2607 while (p1 < ptr) {
2608 if (*p1 == ';' || *p1 == ',')
2609 colon = p1;
2610 else if (!isspace((int)*p1))
2611 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002612 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002613 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002614
2615 if (p1 == ptr)
2616 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002617
2618 /* p1 is at the beginning of the cookie name */
2619 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002620 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002621 p2++;
2622
2623 if (p2 == ptr)
2624 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002625
2626 p3 = p2 + 1; /* skips the '=' sign */
2627 if (p3 == ptr)
2628 break;
2629
willy tarreau240afa62005-12-17 13:14:35 +01002630 p4 = p3;
2631 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002632 p4++;
2633
2634 /* here, we have the cookie name between p1 and p2,
2635 * and its value between p3 and p4.
2636 * we can process it.
2637 */
2638
willy tarreau240afa62005-12-17 13:14:35 +01002639 if (*p1 == '$') {
2640 /* skip this one */
2641 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002642 else {
2643 /* first, let's see if we want to capture it */
2644 if (t->proxy->capture_name != NULL &&
2645 t->logs.cli_cookie == NULL &&
2646 (p4 - p1 >= t->proxy->capture_namelen) &&
2647 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2648 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002649
willy tarreau8337c6b2005-12-17 13:41:01 +01002650 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2651 Alert("HTTP logging : out of memory.\n");
2652 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002653
willy tarreau8337c6b2005-12-17 13:41:01 +01002654 if (log_len > t->proxy->capture_len)
2655 log_len = t->proxy->capture_len;
2656 memcpy(t->logs.cli_cookie, p1, log_len);
2657 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002658 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002659
2660 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2661 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2662 /* Cool... it's the right one */
2663 struct server *srv = t->proxy->srv;
2664
2665 while (srv &&
2666 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2667 srv = srv->next;
2668 }
2669
willy tarreau036e1ce2005-12-17 13:46:33 +01002670 if (!srv) {
2671 t->flags &= ~SN_CK_MASK;
2672 t->flags |= SN_CK_INVALID;
2673 }
2674 else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002675 /* we found the server and it's usable */
willy tarreau036e1ce2005-12-17 13:46:33 +01002676 t->flags &= ~SN_CK_MASK;
2677 t->flags |= SN_CK_VALID | SN_DIRECT;
willy tarreau8337c6b2005-12-17 13:41:01 +01002678 t->srv = srv;
2679 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002680 else {
2681 t->flags &= ~SN_CK_MASK;
2682 t->flags |= SN_CK_DOWN;
2683 }
2684
willy tarreau8337c6b2005-12-17 13:41:01 +01002685 /* if this cookie was set in insert+indirect mode, then it's better that the
2686 * server never sees it.
2687 */
2688 if (del_cookie == NULL &&
2689 (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 +01002690 del_cookie = p1;
2691 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002692 }
willy tarreau240afa62005-12-17 13:14:35 +01002693 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002694 else {
2695 /* now we know that we must keep this cookie since it's
2696 * not ours. But if we wanted to delete our cookie
2697 * earlier, we cannot remove the complete header, but we
2698 * can remove the previous block itself.
2699 */
2700 app_cookies++;
2701
2702 if (del_cookie != NULL) {
2703 buffer_replace2(req, del_cookie, p1, NULL, 0);
2704 p4 -= (p1 - del_cookie);
2705 ptr -= (p1 - del_cookie);
2706 del_cookie = del_colon = NULL;
2707 }
willy tarreau240afa62005-12-17 13:14:35 +01002708 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002709 }
willy tarreau240afa62005-12-17 13:14:35 +01002710
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711 /* we'll have to look for another cookie ... */
2712 p1 = p4;
2713 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002714
2715 /* There's no more cookie on this line.
2716 * We may have marked the last one(s) for deletion.
2717 * We must do this now in two ways :
2718 * - if there is no app cookie, we simply delete the header ;
2719 * - if there are app cookies, we must delete the end of the
2720 * string properly, including the colon/semi-colon before
2721 * the cookie name.
2722 */
2723 if (del_cookie != NULL) {
2724 if (app_cookies) {
2725 buffer_replace2(req, del_colon, ptr, NULL, 0);
2726 /* WARNING! <ptr> becomes invalid for now. If some code
2727 * below needs to rely on it before the end of the global
2728 * header loop, we need to correct it with this code :
2729 * ptr = del_colon;
2730 */
2731 }
2732 else
2733 delete_header = 1;
2734 }
2735 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002736
2737 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002738 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002739 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002740 }
willy tarreau240afa62005-12-17 13:14:35 +01002741 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2742
willy tarreau5cbea6f2005-12-17 12:48:26 +01002743 req->h = req->lr;
2744 } /* while (req->lr < req->r) */
2745
2746 /* end of header processing (even if incomplete) */
2747
willy tarreauef900ab2005-12-17 12:52:52 +01002748 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2749 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2750 * full. We cannot loop here since event_cli_read will disable it only if
2751 * req->l == rlim-data
2752 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002753 FD_SET(t->cli_fd, StaticReadEvent);
2754 if (t->proxy->clitimeout)
2755 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2756 else
2757 tv_eternity(&t->crexpire);
2758 }
2759
willy tarreaue39cd132005-12-17 13:00:18 +01002760 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002761 * won't be able to free more later, so the session will never terminate.
2762 */
willy tarreaue39cd132005-12-17 13:00:18 +01002763 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002764 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01002765 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01002766 if (!(t->flags & SN_ERR_MASK))
2767 t->flags |= SN_ERR_PRXCOND;
2768 if (!(t->flags & SN_FINST_MASK))
2769 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002770 return 1;
2771 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002772 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002773 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002774 tv_eternity(&t->crexpire);
2775 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002776 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002777 if (!(t->flags & SN_ERR_MASK))
2778 t->flags |= SN_ERR_CLICL;
2779 if (!(t->flags & SN_FINST_MASK))
2780 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002781 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002782 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002783 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2784
2785 /* read timeout : give up with an error message.
2786 */
2787 t->logs.status = 408;
2788 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01002789 if (!(t->flags & SN_ERR_MASK))
2790 t->flags |= SN_ERR_CLITO;
2791 if (!(t->flags & SN_FINST_MASK))
2792 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01002793 return 1;
2794 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002795
2796 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002797 }
2798 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01002799 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01002800 /* FIXME: this error handling is partly buggy because we always report
2801 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2802 * or HEADER phase. BTW, it's not logical to expire the client while
2803 * we're waiting for the server to connect.
2804 */
willy tarreau0f7af912005-12-17 12:21:26 +01002805 /* read or write error */
2806 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002807 tv_eternity(&t->crexpire);
2808 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002809 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002810 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002811 if (!(t->flags & SN_ERR_MASK))
2812 t->flags |= SN_ERR_CLICL;
2813 if (!(t->flags & SN_FINST_MASK))
2814 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002815 return 1;
2816 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002817 /* last read, or end of server write */
2818 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002819 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002820 tv_eternity(&t->crexpire);
2821 shutdown(t->cli_fd, SHUT_RD);
2822 t->cli_state = CL_STSHUTR;
2823 return 1;
2824 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002825 /* last server read and buffer empty */
2826 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002827 FD_CLR(t->cli_fd, StaticWriteEvent);
2828 tv_eternity(&t->cwexpire);
2829 shutdown(t->cli_fd, SHUT_WR);
2830 t->cli_state = CL_STSHUTW;
2831 return 1;
2832 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002833 /* read timeout */
2834 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2835 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01002836 tv_eternity(&t->crexpire);
2837 shutdown(t->cli_fd, SHUT_RD);
2838 t->cli_state = CL_STSHUTR;
2839 if (!(t->flags & SN_ERR_MASK))
2840 t->flags |= SN_ERR_CLITO;
2841 if (!(t->flags & SN_FINST_MASK))
2842 t->flags |= SN_FINST_D;
2843 return 1;
2844 }
2845 /* write timeout */
2846 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2847 FD_CLR(t->cli_fd, StaticWriteEvent);
2848 tv_eternity(&t->cwexpire);
2849 shutdown(t->cli_fd, SHUT_WR);
2850 t->cli_state = CL_STSHUTW;
2851 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01002852 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01002853 if (!(t->flags & SN_FINST_MASK))
2854 t->flags |= SN_FINST_D;
2855 return 1;
2856 }
willy tarreau0f7af912005-12-17 12:21:26 +01002857
willy tarreauc58fc692005-12-17 14:13:08 +01002858 if (req->l >= req->rlim - req->data) {
2859 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002860 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002861 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002862 FD_CLR(t->cli_fd, StaticReadEvent);
2863 tv_eternity(&t->crexpire);
2864 }
2865 }
2866 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002867 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002868 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2869 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01002870 if (!t->proxy->clitimeout ||
2871 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2872 /* If the client has no timeout, or if the server not ready yet, and we
2873 * know for sure that it can expire, then it's cleaner to disable the
2874 * timeout on the client side so that too low values cannot make the
2875 * sessions abort too early.
2876 */
willy tarreau0f7af912005-12-17 12:21:26 +01002877 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01002878 else
2879 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01002880 }
2881 }
2882
2883 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01002884 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002885 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2886 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2887 tv_eternity(&t->cwexpire);
2888 }
2889 }
2890 else { /* buffer not empty */
2891 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2892 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002893 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002894 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002895 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2896 t->crexpire = t->cwexpire;
2897 }
willy tarreau0f7af912005-12-17 12:21:26 +01002898 else
2899 tv_eternity(&t->cwexpire);
2900 }
2901 }
2902 return 0; /* other cases change nothing */
2903 }
2904 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002905 if (t->res_cw == RES_ERROR) {
2906 tv_eternity(&t->cwexpire);
2907 fd_delete(t->cli_fd);
2908 t->cli_state = CL_STCLOSE;
2909 if (!(t->flags & SN_ERR_MASK))
2910 t->flags |= SN_ERR_CLICL;
2911 if (!(t->flags & SN_FINST_MASK))
2912 t->flags |= SN_FINST_D;
2913 return 1;
2914 }
2915 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002916 tv_eternity(&t->cwexpire);
2917 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002918 t->cli_state = CL_STCLOSE;
2919 return 1;
2920 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002921 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2922 tv_eternity(&t->cwexpire);
2923 fd_delete(t->cli_fd);
2924 t->cli_state = CL_STCLOSE;
2925 if (!(t->flags & SN_ERR_MASK))
2926 t->flags |= SN_ERR_CLITO;
2927 if (!(t->flags & SN_FINST_MASK))
2928 t->flags |= SN_FINST_D;
2929 return 1;
2930 }
willy tarreau0f7af912005-12-17 12:21:26 +01002931 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002932 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002933 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2934 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2935 tv_eternity(&t->cwexpire);
2936 }
2937 }
2938 else { /* buffer not empty */
2939 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2940 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002941 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002942 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002943 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2944 t->crexpire = t->cwexpire;
2945 }
willy tarreau0f7af912005-12-17 12:21:26 +01002946 else
2947 tv_eternity(&t->cwexpire);
2948 }
2949 }
2950 return 0;
2951 }
2952 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002953 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002954 tv_eternity(&t->crexpire);
2955 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002956 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002957 if (!(t->flags & SN_ERR_MASK))
2958 t->flags |= SN_ERR_CLICL;
2959 if (!(t->flags & SN_FINST_MASK))
2960 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002961 return 1;
2962 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002963 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
2964 tv_eternity(&t->crexpire);
2965 fd_delete(t->cli_fd);
2966 t->cli_state = CL_STCLOSE;
2967 return 1;
2968 }
2969 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2970 tv_eternity(&t->crexpire);
2971 fd_delete(t->cli_fd);
2972 t->cli_state = CL_STCLOSE;
2973 if (!(t->flags & SN_ERR_MASK))
2974 t->flags |= SN_ERR_CLITO;
2975 if (!(t->flags & SN_FINST_MASK))
2976 t->flags |= SN_FINST_D;
2977 return 1;
2978 }
willy tarreauef900ab2005-12-17 12:52:52 +01002979 else if (req->l >= req->rlim - req->data) {
2980 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002981 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002982 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002983 FD_CLR(t->cli_fd, StaticReadEvent);
2984 tv_eternity(&t->crexpire);
2985 }
2986 }
2987 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002988 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002989 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2990 FD_SET(t->cli_fd, StaticReadEvent);
2991 if (t->proxy->clitimeout)
2992 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2993 else
2994 tv_eternity(&t->crexpire);
2995 }
2996 }
2997 return 0;
2998 }
2999 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003000 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003001 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003002 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 +01003003 write(1, trash, len);
3004 }
3005 return 0;
3006 }
3007 return 0;
3008}
3009
3010
3011/*
3012 * manages the server FSM and its socket. It returns 1 if a state has changed
3013 * (and a resync may be needed), 0 else.
3014 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003015int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003016 int s = t->srv_state;
3017 int c = t->cli_state;
3018 struct buffer *req = t->req;
3019 struct buffer *rep = t->rep;
3020
willy tarreau750a4722005-12-17 13:21:24 +01003021#ifdef DEBUG_FULL
3022 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3023#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003024 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3025 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3026 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3027 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003028 if (s == SV_STIDLE) {
3029 if (c == CL_STHEADERS)
3030 return 0; /* stay in idle, waiting for data to reach the client side */
3031 else if (c == CL_STCLOSE ||
3032 c == CL_STSHUTW ||
3033 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3034 tv_eternity(&t->cnexpire);
3035 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003036 if (!(t->flags & SN_ERR_MASK))
3037 t->flags |= SN_ERR_CLICL;
3038 if (!(t->flags & SN_FINST_MASK))
3039 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003040 return 1;
3041 }
3042 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003043 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003044 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3045 t->srv_state = SV_STCONN;
3046 }
3047 else { /* try again */
3048 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003049 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003050 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003051 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003052 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3053 t->flags &= ~SN_CK_MASK;
3054 t->flags |= SN_CK_DOWN;
3055 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003056 }
3057
3058 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003059 t->srv_state = SV_STCONN;
3060 break;
3061 }
3062 }
3063 if (t->conn_retries < 0) {
3064 /* if conn_retries < 0 or other error, let's abort */
3065 tv_eternity(&t->cnexpire);
3066 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003067 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003068 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003069 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003070 if (!(t->flags & SN_ERR_MASK))
3071 t->flags |= SN_ERR_SRVCL;
3072 if (!(t->flags & SN_FINST_MASK))
3073 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003074 }
3075 }
3076 return 1;
3077 }
3078 }
3079 else if (s == SV_STCONN) { /* connection in progress */
3080 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3081 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3082 return 0; /* nothing changed */
3083 }
3084 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3085 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3086 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003087 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003088 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003089 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003090 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003091 if (t->conn_retries >= 0) {
3092 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003093 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003094 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003095 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3096 t->flags &= ~SN_CK_MASK;
3097 t->flags |= SN_CK_DOWN;
3098 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003099 }
3100 if (connect_server(t) == 0)
3101 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003102 }
3103 /* if conn_retries < 0 or other error, let's abort */
3104 tv_eternity(&t->cnexpire);
3105 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003106 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003107 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003108 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003109 if (!(t->flags & SN_ERR_MASK))
3110 t->flags |= SN_ERR_SRVCL;
3111 if (!(t->flags & SN_FINST_MASK))
3112 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003113 return 1;
3114 }
3115 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003116 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003117
willy tarreau0f7af912005-12-17 12:21:26 +01003118 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003119 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003120 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003121 tv_eternity(&t->swexpire);
3122 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003123 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003124 if (t->proxy->srvtimeout) {
3125 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3126 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3127 t->srexpire = t->swexpire;
3128 }
3129 else
3130 tv_eternity(&t->swexpire);
3131 }
willy tarreau0f7af912005-12-17 12:21:26 +01003132
3133 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3134 FD_SET(t->srv_fd, StaticReadEvent);
3135 if (t->proxy->srvtimeout)
3136 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3137 else
3138 tv_eternity(&t->srexpire);
3139
3140 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003141 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003142 }
willy tarreauef900ab2005-12-17 12:52:52 +01003143 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003144 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003145 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3146 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003147 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003148 return 1;
3149 }
3150 }
3151 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003152 /* now parse the partial (or complete) headers */
3153 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3154 char *ptr;
3155 int delete_header;
3156
3157 ptr = rep->lr;
3158
3159 /* look for the end of the current header */
3160 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3161 ptr++;
3162
3163 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003164 int line, len;
3165
3166 /* we can only get here after an end of headers */
3167 /* we'll have something else to do here : add new headers ... */
3168
willy tarreaucd878942005-12-17 13:27:43 +01003169 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3170 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003171 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003172 * insert a set-cookie here, except if we want to insert only on POST
3173 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003174 */
willy tarreau750a4722005-12-17 13:21:24 +01003175 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003176 t->proxy->cookie_name,
3177 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003178
willy tarreau036e1ce2005-12-17 13:46:33 +01003179 t->flags |= SN_SCK_INSERTED;
3180
willy tarreau750a4722005-12-17 13:21:24 +01003181 /* Here, we will tell an eventual cache on the client side that we don't
3182 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3183 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3184 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3185 */
willy tarreau240afa62005-12-17 13:14:35 +01003186 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003187 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3188 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003189
willy tarreau750a4722005-12-17 13:21:24 +01003190 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003191 }
3192
3193 /* headers to be added */
3194 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003195 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3196 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003197 }
3198
3199 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003200 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003201 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003202 break;
3203 }
3204
3205 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3206 if (ptr > rep->r - 2) {
3207 /* this is a partial header, let's wait for more to come */
3208 rep->lr = ptr;
3209 break;
3210 }
3211
3212 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3213 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3214
3215 /* now we know that *ptr is either \r or \n,
3216 * and that there are at least 1 char after it.
3217 */
3218 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3219 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3220 else
3221 rep->lr = ptr + 2; /* \r\n or \n\r */
3222
3223 /*
3224 * now we know that we have a full header ; we can do whatever
3225 * we want with these pointers :
3226 * rep->h = beginning of header
3227 * ptr = end of header (first \r or \n)
3228 * rep->lr = beginning of next line (next rep->h)
3229 * rep->r = end of data (not used at this stage)
3230 */
3231
willy tarreaua1598082005-12-17 13:08:06 +01003232
3233 if (t->logs.logwait & LW_RESP) {
3234 t->logs.logwait &= ~LW_RESP;
3235 t->logs.status = atoi(rep->h + 9);
3236 }
3237
willy tarreau5cbea6f2005-12-17 12:48:26 +01003238 delete_header = 0;
3239
willy tarreau9fe663a2005-12-17 13:02:59 +01003240 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003241 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003242 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 +01003243 max = ptr - rep->h;
3244 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003245 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003246 trash[len++] = '\n';
3247 write(1, trash, len);
3248 }
3249
3250 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01003251 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
3252 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003253 char term;
3254
3255 term = *ptr;
3256 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003257 exp = t->proxy->rsp_exp;
3258 do {
3259 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3260 switch (exp->action) {
3261 case ACT_ALLOW:
3262 if (!(t->flags & SN_SVDENY))
3263 t->flags |= SN_SVALLOW;
3264 break;
3265 case ACT_REPLACE:
3266 if (!(t->flags & SN_SVDENY)) {
3267 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3268 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3269 }
3270 break;
3271 case ACT_REMOVE:
3272 if (!(t->flags & SN_SVDENY))
3273 delete_header = 1;
3274 break;
3275 case ACT_DENY:
3276 if (!(t->flags & SN_SVALLOW))
3277 t->flags |= SN_SVDENY;
3278 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003279 case ACT_PASS: /* we simply don't deny this one */
3280 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003281 }
3282 break;
3283 }
willy tarreaue39cd132005-12-17 13:00:18 +01003284 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003285 *ptr = term; /* restore the string terminator */
3286 }
3287
3288 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003289 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3290 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
3291 && (ptr >= rep->h + 12)
willy tarreau906b2682005-12-17 13:49:52 +01003292 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003293 char *p1, *p2, *p3, *p4;
3294
3295 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3296
3297 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003298 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003299 p1++;
3300
3301 if (p1 == ptr || *p1 == ';') /* end of cookie */
3302 break;
3303
3304 /* p1 is at the beginning of the cookie name */
3305 p2 = p1;
3306
3307 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3308 p2++;
3309
3310 if (p2 == ptr || *p2 == ';') /* next cookie */
3311 break;
3312
3313 p3 = p2 + 1; /* skips the '=' sign */
3314 if (p3 == ptr)
3315 break;
3316
3317 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003318 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003319 p4++;
3320
3321 /* here, we have the cookie name between p1 and p2,
3322 * and its value between p3 and p4.
3323 * we can process it.
3324 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003325
3326 /* first, let's see if we want to capture it */
3327 if (t->proxy->capture_name != NULL &&
3328 t->logs.srv_cookie == NULL &&
3329 (p4 - p1 >= t->proxy->capture_namelen) &&
3330 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3331 int log_len = p4 - p1;
3332
3333 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3334 Alert("HTTP logging : out of memory.\n");
3335 }
3336
3337 if (log_len > t->proxy->capture_len)
3338 log_len = t->proxy->capture_len;
3339 memcpy(t->logs.srv_cookie, p1, log_len);
3340 t->logs.srv_cookie[log_len] = 0;
3341 }
3342
3343 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3344 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003345 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003346 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003347
3348 /* If the cookie is in insert mode on a known server, we'll delete
3349 * this occurrence because we'll insert another one later.
3350 * We'll delete it too if the "indirect" option is set and we're in
3351 * a direct access. */
3352 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003353 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003354 /* this header must be deleted */
3355 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003356 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003357 }
3358 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3359 /* replace bytes p3->p4 with the cookie name associated
3360 * with this server since we know it.
3361 */
3362 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003363 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003364 }
3365 break;
3366 }
3367 else {
3368 // fprintf(stderr,"Ignoring unknown cookie : ");
3369 // write(2, p1, p2-p1);
3370 // fprintf(stderr," = ");
3371 // write(2, p3, p4-p3);
3372 // fprintf(stderr,"\n");
3373 }
3374 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3375 } /* we're now at the end of the cookie value */
3376 } /* end of cookie processing */
3377
3378 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003379 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003380 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003381
willy tarreau5cbea6f2005-12-17 12:48:26 +01003382 rep->h = rep->lr;
3383 } /* while (rep->lr < rep->r) */
3384
3385 /* end of header processing (even if incomplete) */
3386
willy tarreauef900ab2005-12-17 12:52:52 +01003387 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3388 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3389 * full. We cannot loop here since event_srv_read will disable it only if
3390 * rep->l == rlim-data
3391 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003392 FD_SET(t->srv_fd, StaticReadEvent);
3393 if (t->proxy->srvtimeout)
3394 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3395 else
3396 tv_eternity(&t->srexpire);
3397 }
willy tarreau0f7af912005-12-17 12:21:26 +01003398
willy tarreau8337c6b2005-12-17 13:41:01 +01003399 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003400 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003401 tv_eternity(&t->srexpire);
3402 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003403 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003404 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003405 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003406 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003407 if (!(t->flags & SN_ERR_MASK))
3408 t->flags |= SN_ERR_SRVCL;
3409 if (!(t->flags & SN_FINST_MASK))
3410 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003411 return 1;
3412 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003413 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003414 * since we are in header mode, if there's no space left for headers, we
3415 * won't be able to free more later, so the session will never terminate.
3416 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003417 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 +01003418 FD_CLR(t->srv_fd, StaticReadEvent);
3419 tv_eternity(&t->srexpire);
3420 shutdown(t->srv_fd, SHUT_RD);
3421 t->srv_state = SV_STSHUTR;
3422 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003423 }
3424 /* read timeout : return a 504 to the client.
3425 */
3426 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3427 tv_eternity(&t->srexpire);
3428 tv_eternity(&t->swexpire);
3429 fd_delete(t->srv_fd);
3430 t->srv_state = SV_STCLOSE;
3431 t->logs.status = 504;
3432 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003433 if (!(t->flags & SN_ERR_MASK))
3434 t->flags |= SN_ERR_SRVTO;
3435 if (!(t->flags & SN_FINST_MASK))
3436 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003437 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003438
3439 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003440 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003441 /* FIXME!!! here, we don't want to switch to SHUTW if the
3442 * client shuts read too early, because we may still have
3443 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01003444 * The side-effect is that if the client completely closes its
3445 * connection during SV_STHEADER, the connection to the server
3446 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01003447 */
willy tarreau036e1ce2005-12-17 13:46:33 +01003448 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003449 FD_CLR(t->srv_fd, StaticWriteEvent);
3450 tv_eternity(&t->swexpire);
3451 shutdown(t->srv_fd, SHUT_WR);
3452 t->srv_state = SV_STSHUTW;
3453 return 1;
3454 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003455 /* write timeout */
3456 /* FIXME!!! here, we don't want to switch to SHUTW if the
3457 * client shuts read too early, because we may still have
3458 * some work to do on the headers.
3459 */
3460 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3461 FD_CLR(t->srv_fd, StaticWriteEvent);
3462 tv_eternity(&t->swexpire);
3463 shutdown(t->srv_fd, SHUT_WR);
3464 t->srv_state = SV_STSHUTW;
3465 if (!(t->flags & SN_ERR_MASK))
3466 t->flags |= SN_ERR_SRVTO;
3467 if (!(t->flags & SN_FINST_MASK))
3468 t->flags |= SN_FINST_H;
3469 return 1;
3470 }
willy tarreau0f7af912005-12-17 12:21:26 +01003471
3472 if (req->l == 0) {
3473 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3474 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3475 tv_eternity(&t->swexpire);
3476 }
3477 }
3478 else { /* client buffer not empty */
3479 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3480 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003481 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003482 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003483 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3484 t->srexpire = t->swexpire;
3485 }
willy tarreau0f7af912005-12-17 12:21:26 +01003486 else
3487 tv_eternity(&t->swexpire);
3488 }
3489 }
3490
willy tarreau5cbea6f2005-12-17 12:48:26 +01003491 /* be nice with the client side which would like to send a complete header
3492 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3493 * would read all remaining data at once ! The client should not write past rep->lr
3494 * when the server is in header state.
3495 */
3496 //return header_processed;
3497 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003498 }
3499 else if (s == SV_STDATA) {
3500 /* read or write error */
3501 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003502 tv_eternity(&t->srexpire);
3503 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003504 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003505 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003506 if (!(t->flags & SN_ERR_MASK))
3507 t->flags |= SN_ERR_SRVCL;
3508 if (!(t->flags & SN_FINST_MASK))
3509 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003510 return 1;
3511 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003512 /* last read, or end of client write */
3513 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003514 FD_CLR(t->srv_fd, StaticReadEvent);
3515 tv_eternity(&t->srexpire);
3516 shutdown(t->srv_fd, SHUT_RD);
3517 t->srv_state = SV_STSHUTR;
3518 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01003519 }
3520 /* end of client read and no more data to send */
3521 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
3522 FD_CLR(t->srv_fd, StaticWriteEvent);
3523 tv_eternity(&t->swexpire);
3524 shutdown(t->srv_fd, SHUT_WR);
3525 t->srv_state = SV_STSHUTW;
3526 return 1;
3527 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003528 /* read timeout */
3529 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3530 FD_CLR(t->srv_fd, StaticReadEvent);
3531 tv_eternity(&t->srexpire);
3532 shutdown(t->srv_fd, SHUT_RD);
3533 t->srv_state = SV_STSHUTR;
3534 if (!(t->flags & SN_ERR_MASK))
3535 t->flags |= SN_ERR_SRVTO;
3536 if (!(t->flags & SN_FINST_MASK))
3537 t->flags |= SN_FINST_D;
3538 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003539 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003540 /* write timeout */
3541 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003542 FD_CLR(t->srv_fd, StaticWriteEvent);
3543 tv_eternity(&t->swexpire);
3544 shutdown(t->srv_fd, SHUT_WR);
3545 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01003546 if (!(t->flags & SN_ERR_MASK))
3547 t->flags |= SN_ERR_SRVTO;
3548 if (!(t->flags & SN_FINST_MASK))
3549 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003550 return 1;
3551 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003552
3553 /* recompute request time-outs */
3554 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003555 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3556 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3557 tv_eternity(&t->swexpire);
3558 }
3559 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003560 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01003561 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3562 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003563 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003564 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003565 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3566 t->srexpire = t->swexpire;
3567 }
willy tarreau0f7af912005-12-17 12:21:26 +01003568 else
3569 tv_eternity(&t->swexpire);
3570 }
3571 }
3572
willy tarreaub1ff9db2005-12-17 13:51:03 +01003573 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01003574 if (rep->l == BUFSIZE) { /* no room to read more data */
3575 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3576 FD_CLR(t->srv_fd, StaticReadEvent);
3577 tv_eternity(&t->srexpire);
3578 }
3579 }
3580 else {
3581 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3582 FD_SET(t->srv_fd, StaticReadEvent);
3583 if (t->proxy->srvtimeout)
3584 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3585 else
3586 tv_eternity(&t->srexpire);
3587 }
3588 }
3589
3590 return 0; /* other cases change nothing */
3591 }
3592 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003593 if (t->res_sw == RES_ERROR) {
3594 //FD_CLR(t->srv_fd, StaticWriteEvent);
3595 tv_eternity(&t->swexpire);
3596 fd_delete(t->srv_fd);
3597 //close(t->srv_fd);
3598 t->srv_state = SV_STCLOSE;
3599 if (!(t->flags & SN_ERR_MASK))
3600 t->flags |= SN_ERR_SRVCL;
3601 if (!(t->flags & SN_FINST_MASK))
3602 t->flags |= SN_FINST_D;
3603 return 1;
3604 }
3605 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003606 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003607 tv_eternity(&t->swexpire);
3608 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003609 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003610 t->srv_state = SV_STCLOSE;
3611 return 1;
3612 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003613 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3614 //FD_CLR(t->srv_fd, StaticWriteEvent);
3615 tv_eternity(&t->swexpire);
3616 fd_delete(t->srv_fd);
3617 //close(t->srv_fd);
3618 t->srv_state = SV_STCLOSE;
3619 if (!(t->flags & SN_ERR_MASK))
3620 t->flags |= SN_ERR_SRVTO;
3621 if (!(t->flags & SN_FINST_MASK))
3622 t->flags |= SN_FINST_D;
3623 return 1;
3624 }
willy tarreau0f7af912005-12-17 12:21:26 +01003625 else if (req->l == 0) {
3626 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3627 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3628 tv_eternity(&t->swexpire);
3629 }
3630 }
3631 else { /* buffer not empty */
3632 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3633 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003634 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003635 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003636 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3637 t->srexpire = t->swexpire;
3638 }
willy tarreau0f7af912005-12-17 12:21:26 +01003639 else
3640 tv_eternity(&t->swexpire);
3641 }
3642 }
3643 return 0;
3644 }
3645 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003646 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003647 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003648 tv_eternity(&t->srexpire);
3649 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003650 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003651 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003652 if (!(t->flags & SN_ERR_MASK))
3653 t->flags |= SN_ERR_SRVCL;
3654 if (!(t->flags & SN_FINST_MASK))
3655 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003656 return 1;
3657 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003658 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
3659 //FD_CLR(t->srv_fd, StaticReadEvent);
3660 tv_eternity(&t->srexpire);
3661 fd_delete(t->srv_fd);
3662 //close(t->srv_fd);
3663 t->srv_state = SV_STCLOSE;
3664 return 1;
3665 }
3666 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3667 //FD_CLR(t->srv_fd, StaticReadEvent);
3668 tv_eternity(&t->srexpire);
3669 fd_delete(t->srv_fd);
3670 //close(t->srv_fd);
3671 t->srv_state = SV_STCLOSE;
3672 if (!(t->flags & SN_ERR_MASK))
3673 t->flags |= SN_ERR_SRVTO;
3674 if (!(t->flags & SN_FINST_MASK))
3675 t->flags |= SN_FINST_D;
3676 return 1;
3677 }
willy tarreau0f7af912005-12-17 12:21:26 +01003678 else if (rep->l == BUFSIZE) { /* no room to read more data */
3679 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3680 FD_CLR(t->srv_fd, StaticReadEvent);
3681 tv_eternity(&t->srexpire);
3682 }
3683 }
3684 else {
3685 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3686 FD_SET(t->srv_fd, StaticReadEvent);
3687 if (t->proxy->srvtimeout)
3688 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3689 else
3690 tv_eternity(&t->srexpire);
3691 }
3692 }
3693 return 0;
3694 }
3695 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003696 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003697 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003698 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 +01003699 write(1, trash, len);
3700 }
3701 return 0;
3702 }
3703 return 0;
3704}
3705
3706
willy tarreau5cbea6f2005-12-17 12:48:26 +01003707/* Processes the client and server jobs of a session task, then
3708 * puts it back to the wait queue in a clean state, or
3709 * cleans up its resources if it must be deleted. Returns
3710 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003711 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003712int process_session(struct task *t) {
3713 struct session *s = t->context;
3714 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003715
willy tarreau5cbea6f2005-12-17 12:48:26 +01003716 do {
3717 fsm_resync = 0;
3718 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3719 fsm_resync |= process_cli(s);
3720 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3721 fsm_resync |= process_srv(s);
3722 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3723 } while (fsm_resync);
3724
3725 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003726 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003727 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003728
willy tarreau5cbea6f2005-12-17 12:48:26 +01003729 tv_min(&min1, &s->crexpire, &s->cwexpire);
3730 tv_min(&min2, &s->srexpire, &s->swexpire);
3731 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003732 tv_min(&t->expire, &min1, &min2);
3733
3734 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003735 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003736
willy tarreau5cbea6f2005-12-17 12:48:26 +01003737 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003738 }
3739
willy tarreau5cbea6f2005-12-17 12:48:26 +01003740 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003741 actconn--;
3742
willy tarreau9fe663a2005-12-17 13:02:59 +01003743 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003744 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003745 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 +01003746 write(1, trash, len);
3747 }
3748
willy tarreau750a4722005-12-17 13:21:24 +01003749 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003750 if (s->rep != NULL)
3751 s->logs.bytes = s->rep->total;
3752
willy tarreau9fe663a2005-12-17 13:02:59 +01003753 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003754 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003755 sess_log(s);
3756
willy tarreau0f7af912005-12-17 12:21:26 +01003757 /* the task MUST not be in the run queue anymore */
3758 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003759 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003760 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003761 return -1; /* rest in peace for eternity */
3762}
3763
3764
3765
3766/*
3767 * manages a server health-check. Returns
3768 * the time the task accepts to wait, or -1 for infinity.
3769 */
3770int process_chk(struct task *t) {
3771 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01003772 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003773 int fd = s->curfd;
3774 int one = 1;
3775
willy tarreauef900ab2005-12-17 12:52:52 +01003776 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003777
3778 if (fd < 0) { /* no check currently running */
3779 //fprintf(stderr, "process_chk: 2\n");
3780 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3781 task_queue(t); /* restore t to its place in the task list */
3782 return tv_remain(&now, &t->expire);
3783 }
3784
3785 /* we'll initiate a new check */
3786 s->result = 0; /* no result yet */
3787 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003788 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003789 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3790 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3791 //fprintf(stderr, "process_chk: 3\n");
3792
willy tarreaua41a8b42005-12-17 14:02:24 +01003793 /* we'll connect to the check port on the server */
3794 sa = s->addr;
3795 sa.sin_port = htons(s->check_port);
3796
willy tarreau036e1ce2005-12-17 13:46:33 +01003797 /* allow specific binding */
3798 if (s->proxy->options & PR_O_BIND_SRC &&
3799 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
3800 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
3801 close(fd);
3802 s->result = -1;
3803 }
willy tarreaua41a8b42005-12-17 14:02:24 +01003804 else if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003805 /* OK, connection in progress or established */
3806
3807 //fprintf(stderr, "process_chk: 4\n");
3808
3809 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3810 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003811 fdtab[fd].read = &event_srv_chk_r;
3812 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003813 fdtab[fd].state = FD_STCONN; /* connection in progress */
3814 FD_SET(fd, StaticWriteEvent); /* for connect status */
3815 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003816 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3817 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003818 task_queue(t); /* restore t to its place in the task list */
3819 return tv_remain(&now, &t->expire);
3820 }
3821 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3822 s->result = -1; /* a real error */
3823 }
3824 }
3825 //fprintf(stderr, "process_chk: 5\n");
3826 close(fd);
3827 }
3828
3829 if (!s->result) { /* nothing done */
3830 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003831 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003832 task_queue(t); /* restore t to its place in the task list */
3833 return tv_remain(&now, &t->expire);
3834 }
3835
3836 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003837 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003838 s->health--; /* still good */
3839 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003840 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003841 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003842 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003843
willy tarreau9fe663a2005-12-17 13:02:59 +01003844 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003845 }
willy tarreauef900ab2005-12-17 12:52:52 +01003846
willy tarreau5cbea6f2005-12-17 12:48:26 +01003847 s->health = 0; /* failure */
3848 s->state &= ~SRV_RUNNING;
3849 }
3850
3851 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003852 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3853 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003854 }
3855 else {
3856 //fprintf(stderr, "process_chk: 8\n");
3857 /* there was a test running */
3858 if (s->result > 0) { /* good server detected */
3859 //fprintf(stderr, "process_chk: 9\n");
3860 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003861 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003862 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003863 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003864 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003865 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003866 }
willy tarreauef900ab2005-12-17 12:52:52 +01003867
willy tarreaue47c8d72005-12-17 12:55:52 +01003868 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003869 s->state |= SRV_RUNNING;
3870 }
willy tarreauef900ab2005-12-17 12:52:52 +01003871 s->curfd = -1; /* no check running anymore */
3872 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003873 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003874 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003875 }
3876 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3877 //fprintf(stderr, "process_chk: 10\n");
3878 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003879 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003880 s->health--; /* still good */
3881 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003882 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003883 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003884 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003885
3886 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003887 }
willy tarreauef900ab2005-12-17 12:52:52 +01003888
willy tarreau5cbea6f2005-12-17 12:48:26 +01003889 s->health = 0; /* failure */
3890 s->state &= ~SRV_RUNNING;
3891 }
3892 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003893 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003894 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003895 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003896 }
3897 /* if result is 0 and there's no timeout, we have to wait again */
3898 }
3899 //fprintf(stderr, "process_chk: 11\n");
3900 s->result = 0;
3901 task_queue(t); /* restore t to its place in the task list */
3902 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003903}
3904
3905
willy tarreau5cbea6f2005-12-17 12:48:26 +01003906
willy tarreau0f7af912005-12-17 12:21:26 +01003907#if STATTIME > 0
3908int stats(void);
3909#endif
3910
3911/*
3912 * Main select() loop.
3913 */
3914
3915void select_loop() {
3916 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003917 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003918 int status;
3919 int fd,i;
3920 struct timeval delta;
3921 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003923
willy tarreau5cbea6f2005-12-17 12:48:26 +01003924 tv_now(&now);
3925
3926 while (1) {
3927 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003928
willy tarreau5cbea6f2005-12-17 12:48:26 +01003929 /* look for expired tasks and add them to the run queue.
3930 */
3931 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3932 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3933 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003934 if (t->state & TASK_RUNNING)
3935 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003936
3937 /* wakeup expired entries. It doesn't matter if they are
3938 * already running because of a previous event
3939 */
3940 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003941 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003942 task_wakeup(&rq, t);
3943 }
3944 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003945 /* first non-runnable task. Use its expiration date as an upper bound */
3946 int temp_time = tv_remain(&now, &t->expire);
3947 if (temp_time)
3948 next_time = temp_time;
3949 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003950 break;
3951 }
3952 }
3953
3954 /* process each task in the run queue now. Each task may be deleted
3955 * since we only use tnext.
3956 */
3957 tnext = rq;
3958 while ((t = tnext) != NULL) {
3959 int temp_time;
3960
3961 tnext = t->rqnext;
3962 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003963 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003964 temp_time = t->process(t);
3965 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003966 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003967 }
3968
willy tarreauef900ab2005-12-17 12:52:52 +01003969 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003970
3971 /* maintain all proxies in a consistent state. This should quickly become a task */
3972 time2 = maintain_proxies();
3973 next_time = MINTIME(time2, next_time);
3974
3975 /* stop when there's no connection left and we don't allow them anymore */
3976 if (!actconn && listeners == 0)
3977 break;
3978
willy tarreau0f7af912005-12-17 12:21:26 +01003979
3980#if STATTIME > 0
3981 time2 = stats();
3982 // fprintf(stderr," stats = %d\n", time2);
3983 next_time = MINTIME(time2, next_time);
3984#endif
3985
willy tarreau5cbea6f2005-12-17 12:48:26 +01003986 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003987 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003988 /* to avoid eventual select loops due to timer precision */
3989 next_time += SCHEDULER_RESOLUTION;
3990 delta.tv_sec = next_time / 1000;
3991 delta.tv_usec = (next_time % 1000) * 1000;
3992 }
3993 else if (next_time == 0) { /* allow select to return immediately when needed */
3994 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003995 }
3996
3997
3998 /* let's restore fdset state */
3999
4000 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004001 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004002 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
4003 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
4004 }
4005
4006// /* just a verification code, needs to be removed for performance */
4007// for (i=0; i<maxfd; i++) {
4008// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
4009// abort();
4010// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
4011// abort();
4012//
4013// }
4014
willy tarreau197e8ec2005-12-17 14:10:59 +01004015 status = select(maxfd,
4016 readnotnull ? ReadEvent : NULL,
4017 writenotnull ? WriteEvent : NULL,
4018 NULL,
4019 (next_time >= 0) ? &delta : NULL);
willy tarreau0f7af912005-12-17 12:21:26 +01004020
willy tarreau5cbea6f2005-12-17 12:48:26 +01004021 /* this is an experiment on the separation of the select work */
4022 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4023 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4024
willy tarreau0f7af912005-12-17 12:21:26 +01004025 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004026
willy tarreau0f7af912005-12-17 12:21:26 +01004027 if (status > 0) { /* must proceed with events */
4028
4029 int fds;
4030 char count;
4031
4032 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
4033 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
4034 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
4035
willy tarreau5cbea6f2005-12-17 12:48:26 +01004036 /* if we specify read first, the accepts and zero reads will be
4037 * seen first. Moreover, system buffers will be flushed faster.
4038 */
willy tarreau0f7af912005-12-17 12:21:26 +01004039 if (fdtab[fd].state == FD_STCLOSE)
4040 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01004041
4042 if (FD_ISSET(fd, ReadEvent))
4043 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004044
willy tarreau5cbea6f2005-12-17 12:48:26 +01004045 if (FD_ISSET(fd, WriteEvent))
4046 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004047 }
4048 }
4049 else {
4050 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
4051 }
willy tarreau0f7af912005-12-17 12:21:26 +01004052 }
4053}
4054
4055
4056#if STATTIME > 0
4057/*
4058 * Display proxy statistics regularly. It is designed to be called from the
4059 * select_loop().
4060 */
4061int stats(void) {
4062 static int lines;
4063 static struct timeval nextevt;
4064 static struct timeval lastevt;
4065 static struct timeval starttime = {0,0};
4066 unsigned long totaltime, deltatime;
4067 int ret;
4068
willy tarreau750a4722005-12-17 13:21:24 +01004069 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01004070 deltatime = (tv_diff(&lastevt, &now)?:1);
4071 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01004072
willy tarreau9fe663a2005-12-17 13:02:59 +01004073 if (global.mode & MODE_STATS) {
4074 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004075 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004076 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
4077 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004078 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004079 actconn, totalconn,
4080 stats_tsk_new, stats_tsk_good,
4081 stats_tsk_left, stats_tsk_right,
4082 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
4083 }
4084 }
4085
4086 tv_delayfrom(&nextevt, &now, STATTIME);
4087
4088 lastevt=now;
4089 }
4090 ret = tv_remain(&now, &nextevt);
4091 return ret;
4092}
4093#endif
4094
4095
4096/*
4097 * this function enables proxies when there are enough free sessions,
4098 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01004099 * select_loop(). It returns the time left before next expiration event
4100 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01004101 */
4102static int maintain_proxies(void) {
4103 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01004104 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004105 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01004106
4107 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004108 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01004109
4110 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01004111 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01004112 while (p) {
4113 if (p->nbconn < p->maxconn) {
4114 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004115 for (l = p->listen; l != NULL; l = l->next) {
4116 FD_SET(l->fd, StaticReadEvent);
4117 }
willy tarreau0f7af912005-12-17 12:21:26 +01004118 p->state = PR_STRUN;
4119 }
4120 }
4121 else {
4122 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004123 for (l = p->listen; l != NULL; l = l->next) {
4124 FD_CLR(l->fd, StaticReadEvent);
4125 }
willy tarreau0f7af912005-12-17 12:21:26 +01004126 p->state = PR_STIDLE;
4127 }
4128 }
4129 p = p->next;
4130 }
4131 }
4132 else { /* block all proxies */
4133 while (p) {
4134 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004135 for (l = p->listen; l != NULL; l = l->next) {
4136 FD_CLR(l->fd, StaticReadEvent);
4137 }
willy tarreau0f7af912005-12-17 12:21:26 +01004138 p->state = PR_STIDLE;
4139 }
4140 p = p->next;
4141 }
4142 }
4143
willy tarreau5cbea6f2005-12-17 12:48:26 +01004144 if (stopping) {
4145 p = proxy;
4146 while (p) {
4147 if (p->state != PR_STDISABLED) {
4148 int t;
4149 t = tv_remain(&now, &p->stop_time);
4150 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004151 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004152 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004153
willy tarreaua41a8b42005-12-17 14:02:24 +01004154 for (l = p->listen; l != NULL; l = l->next) {
4155 fd_delete(l->fd);
4156 listeners--;
4157 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004158 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004159 }
4160 else {
4161 tleft = MINTIME(t, tleft);
4162 }
4163 }
4164 p = p->next;
4165 }
4166 }
4167 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004168}
4169
4170/*
4171 * this function disables health-check servers so that the process will quickly be ignored
4172 * by load balancers.
4173 */
4174static void soft_stop(void) {
4175 struct proxy *p;
4176
4177 stopping = 1;
4178 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004179 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004180 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004181 if (p->state != PR_STDISABLED) {
4182 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004183 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004184 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004185 }
willy tarreau0f7af912005-12-17 12:21:26 +01004186 p = p->next;
4187 }
4188}
4189
4190/*
4191 * upon SIGUSR1, let's have a soft stop.
4192 */
4193void sig_soft_stop(int sig) {
4194 soft_stop();
4195 signal(sig, SIG_IGN);
4196}
4197
4198
willy tarreau8337c6b2005-12-17 13:41:01 +01004199/*
4200 * this function dumps every server's state when the process receives SIGHUP.
4201 */
4202void sig_dump_state(int sig) {
4203 struct proxy *p = proxy;
4204
4205 Warning("SIGHUP received, dumping servers states.\n");
4206 while (p) {
4207 struct server *s = p->srv;
4208
4209 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4210 while (s) {
4211 if (s->state & SRV_RUNNING) {
4212 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4213 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4214 }
4215 else {
4216 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4217 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4218 }
4219 s = s->next;
4220 }
4221 p = p->next;
4222 }
4223 signal(sig, sig_dump_state);
4224}
4225
willy tarreau0f7af912005-12-17 12:21:26 +01004226void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004227 struct task *t, *tnext;
4228 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004229
willy tarreau5cbea6f2005-12-17 12:48:26 +01004230 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4231 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4232 tnext = t->next;
4233 s = t->context;
4234 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4235 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4236 "req=%d, rep=%d, clifd=%d\n",
4237 s, tv_remain(&now, &t->expire),
4238 s->cli_state,
4239 s->srv_state,
4240 FD_ISSET(s->cli_fd, StaticReadEvent),
4241 FD_ISSET(s->cli_fd, StaticWriteEvent),
4242 FD_ISSET(s->srv_fd, StaticReadEvent),
4243 FD_ISSET(s->srv_fd, StaticWriteEvent),
4244 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4245 );
willy tarreau0f7af912005-12-17 12:21:26 +01004246 }
4247}
4248
willy tarreaue39cd132005-12-17 13:00:18 +01004249void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4250 struct hdr_exp *exp;
4251
4252 while (*head != NULL)
4253 head = &(*head)->next;
4254
4255 exp = calloc(1, sizeof(struct hdr_exp));
4256
4257 exp->preg = preg;
4258 exp->replace = replace;
4259 exp->action = action;
4260 *head = exp;
4261}
4262
willy tarreau9fe663a2005-12-17 13:02:59 +01004263
willy tarreau0f7af912005-12-17 12:21:26 +01004264/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004265 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004266 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004267int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004268
willy tarreau9fe663a2005-12-17 13:02:59 +01004269 if (!strcmp(args[0], "global")) { /* new section */
4270 /* no option, nothing special to do */
4271 return 0;
4272 }
4273 else if (!strcmp(args[0], "daemon")) {
4274 global.mode |= MODE_DAEMON;
4275 }
4276 else if (!strcmp(args[0], "debug")) {
4277 global.mode |= MODE_DEBUG;
4278 }
4279 else if (!strcmp(args[0], "quiet")) {
4280 global.mode |= MODE_QUIET;
4281 }
4282 else if (!strcmp(args[0], "stats")) {
4283 global.mode |= MODE_STATS;
4284 }
4285 else if (!strcmp(args[0], "uid")) {
4286 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004287 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004288 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004289 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004290 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004291 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004292 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004293 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004294 global.uid = atol(args[1]);
4295 }
4296 else if (!strcmp(args[0], "gid")) {
4297 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004298 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004299 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004300 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004301 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004302 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004303 return -1;
4304 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004305 global.gid = atol(args[1]);
4306 }
4307 else if (!strcmp(args[0], "nbproc")) {
4308 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004309 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004310 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004311 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004312 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004313 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004314 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004315 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004316 global.nbproc = atol(args[1]);
4317 }
4318 else if (!strcmp(args[0], "maxconn")) {
4319 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004320 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004321 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004322 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004323 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004324 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004325 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004326 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004327 global.maxconn = atol(args[1]);
4328 }
4329 else if (!strcmp(args[0], "chroot")) {
4330 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004331 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004332 return 0;
4333 }
4334 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004335 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004336 return -1;
4337 }
4338 global.chroot = strdup(args[1]);
4339 }
4340 else if (!strcmp(args[0], "log")) { /* syslog server address */
4341 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004342 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004343
4344 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004345 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004346 return -1;
4347 }
4348
4349 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4350 if (!strcmp(log_facilities[facility], args[2]))
4351 break;
4352
4353 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004354 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004355 exit(1);
4356 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004357
4358 level = 7; /* max syslog level = debug */
4359 if (*(args[3])) {
4360 while (level >= 0 && strcmp(log_levels[level], args[3]))
4361 level--;
4362 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004363 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004364 exit(1);
4365 }
4366 }
4367
willy tarreau9fe663a2005-12-17 13:02:59 +01004368 sa = str2sa(args[1]);
4369 if (!sa->sin_port)
4370 sa->sin_port = htons(SYSLOG_PORT);
4371
4372 if (global.logfac1 == -1) {
4373 global.logsrv1 = *sa;
4374 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004375 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004376 }
4377 else if (global.logfac2 == -1) {
4378 global.logsrv2 = *sa;
4379 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004380 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004381 }
4382 else {
4383 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4384 return -1;
4385 }
4386
4387 }
4388 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004389 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004390 return -1;
4391 }
4392 return 0;
4393}
4394
4395
willy tarreaua41a8b42005-12-17 14:02:24 +01004396void init_default_instance() {
4397 memset(&defproxy, 0, sizeof(defproxy));
4398 defproxy.mode = PR_MODE_TCP;
4399 defproxy.state = PR_STNEW;
4400 defproxy.maxconn = cfg_maxpconn;
4401 defproxy.conn_retries = CONN_RETRIES;
4402 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
4403}
4404
willy tarreau9fe663a2005-12-17 13:02:59 +01004405/*
4406 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4407 */
4408int cfg_parse_listen(char *file, int linenum, char **args) {
4409 static struct proxy *curproxy = NULL;
4410 struct server *newsrv = NULL;
4411
4412 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01004413 if (!*args[1]) {
4414 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
4415 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004416 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004417 return -1;
4418 }
4419
4420 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004421 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004422 return -1;
4423 }
4424 curproxy->next = proxy;
4425 proxy = curproxy;
4426 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01004427 if (strchr(args[2], ':') != NULL)
4428 curproxy->listen = str2listener(args[2], curproxy->listen);
4429
willy tarreau9fe663a2005-12-17 13:02:59 +01004430 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01004431 curproxy->state = defproxy.state;
4432 curproxy->maxconn = defproxy.maxconn;
4433 curproxy->conn_retries = defproxy.conn_retries;
4434 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004435
4436 if (defproxy.check_req)
4437 curproxy->check_req = strdup(defproxy.check_req);
4438 curproxy->check_len = defproxy.check_len;
4439
4440 if (defproxy.cookie_name)
4441 curproxy->cookie_name = strdup(defproxy.cookie_name);
4442 curproxy->cookie_len = defproxy.cookie_len;
4443
4444 if (defproxy.capture_name)
4445 curproxy->capture_name = strdup(defproxy.capture_name);
4446 curproxy->capture_namelen = defproxy.capture_namelen;
4447 curproxy->capture_len = defproxy.capture_len;
4448
4449 if (defproxy.errmsg.msg400)
4450 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
4451 curproxy->errmsg.len400 = defproxy.errmsg.len400;
4452
4453 if (defproxy.errmsg.msg403)
4454 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
4455 curproxy->errmsg.len403 = defproxy.errmsg.len403;
4456
4457 if (defproxy.errmsg.msg408)
4458 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
4459 curproxy->errmsg.len408 = defproxy.errmsg.len408;
4460
4461 if (defproxy.errmsg.msg500)
4462 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
4463 curproxy->errmsg.len500 = defproxy.errmsg.len500;
4464
4465 if (defproxy.errmsg.msg502)
4466 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
4467 curproxy->errmsg.len502 = defproxy.errmsg.len502;
4468
4469 if (defproxy.errmsg.msg503)
4470 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
4471 curproxy->errmsg.len503 = defproxy.errmsg.len503;
4472
4473 if (defproxy.errmsg.msg504)
4474 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
4475 curproxy->errmsg.len504 = defproxy.errmsg.len504;
4476
willy tarreaua41a8b42005-12-17 14:02:24 +01004477 curproxy->clitimeout = defproxy.clitimeout;
4478 curproxy->contimeout = defproxy.contimeout;
4479 curproxy->srvtimeout = defproxy.srvtimeout;
4480 curproxy->mode = defproxy.mode;
4481 curproxy->logfac1 = defproxy.logfac1;
4482 curproxy->logsrv1 = defproxy.logsrv1;
4483 curproxy->loglev1 = defproxy.loglev1;
4484 curproxy->logfac2 = defproxy.logfac2;
4485 curproxy->logsrv2 = defproxy.logsrv2;
4486 curproxy->loglev2 = defproxy.loglev2;
4487 curproxy->to_log = defproxy.to_log;
4488 curproxy->grace = defproxy.grace;
4489 curproxy->source_addr = defproxy.source_addr;
4490 return 0;
4491 }
4492 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004493 /* some variables may have already been initialized earlier */
4494 if (defproxy.check_req) free(defproxy.check_req);
4495 if (defproxy.cookie_name) free(defproxy.cookie_name);
4496 if (defproxy.capture_name) free(defproxy.capture_name);
4497 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
4498 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
4499 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
4500 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
4501 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
4502 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
4503 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
4504
4505 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01004506 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01004507 return 0;
4508 }
4509 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004510 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004511 return -1;
4512 }
4513
willy tarreaua41a8b42005-12-17 14:02:24 +01004514 if (!strcmp(args[0], "bind")) { /* new listen addresses */
4515 if (curproxy == &defproxy) {
4516 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4517 return -1;
4518 }
4519
4520 if (strchr(args[1], ':') == NULL) {
4521 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
4522 file, linenum, args[0]);
4523 return -1;
4524 }
4525 curproxy->listen = str2listener(args[1], curproxy->listen);
4526 return 0;
4527 }
4528 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01004529 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
4530 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
4531 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
4532 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004533 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004534 return -1;
4535 }
4536 }
4537 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
4538 curproxy->state = PR_STDISABLED;
4539 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004540 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
4541 curproxy->state = PR_STNEW;
4542 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004543 else if (!strcmp(args[0], "cookie")) { /* cookie name */
4544 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004545// if (curproxy == &defproxy) {
4546// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4547// return -1;
4548// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004549
willy tarreau9fe663a2005-12-17 13:02:59 +01004550 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004551// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
4552// file, linenum);
4553// return 0;
4554 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004555 }
4556
4557 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004558 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
4559 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004560 return -1;
4561 }
4562 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004563 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004564
4565 cur_arg = 2;
4566 while (*(args[cur_arg])) {
4567 if (!strcmp(args[cur_arg], "rewrite")) {
4568 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01004569 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004570 else if (!strcmp(args[cur_arg], "indirect")) {
4571 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01004572 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004573 else if (!strcmp(args[cur_arg], "insert")) {
4574 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01004575 }
willy tarreau240afa62005-12-17 13:14:35 +01004576 else if (!strcmp(args[cur_arg], "nocache")) {
4577 curproxy->options |= PR_O_COOK_NOC;
4578 }
willy tarreaucd878942005-12-17 13:27:43 +01004579 else if (!strcmp(args[cur_arg], "postonly")) {
4580 curproxy->options |= PR_O_COOK_POST;
4581 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004582 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004583 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
4584 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004585 return -1;
4586 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004587 cur_arg++;
4588 }
4589 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 +01004590 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004591 file, linenum);
4592 return -1;
4593 }
4594 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004595 else if (!strcmp(args[0], "capture")) { /* name of a cookie to capture */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004596// if (curproxy == &defproxy) {
4597// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4598// return -1;
4599// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004600
willy tarreau8337c6b2005-12-17 13:41:01 +01004601 if (curproxy->capture_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004602// Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4603// file, linenum, args[0]);
4604// return 0;
4605 free(curproxy->capture_name);
willy tarreau8337c6b2005-12-17 13:41:01 +01004606 }
4607
4608 if (*(args[4]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004609 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
4610 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004611 return -1;
4612 }
4613 curproxy->capture_name = strdup(args[2]);
4614 curproxy->capture_namelen = strlen(curproxy->capture_name);
4615 curproxy->capture_len = atol(args[4]);
4616 if (curproxy->capture_len >= CAPTURE_LEN) {
4617 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
4618 file, linenum, CAPTURE_LEN - 1);
4619 curproxy->capture_len = CAPTURE_LEN - 1;
4620 }
4621 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004622 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004623 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004624 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004625 return 0;
4626 }
4627 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004628 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4629 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004630 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004631 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004632 curproxy->contimeout = atol(args[1]);
4633 }
4634 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004635 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004636 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4637 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004638 return 0;
4639 }
4640 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004641 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4642 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004643 return -1;
4644 }
4645 curproxy->clitimeout = atol(args[1]);
4646 }
4647 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004648 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004649 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004650 return 0;
4651 }
4652 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004653 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4654 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004655 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004656 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004657 curproxy->srvtimeout = atol(args[1]);
4658 }
4659 else if (!strcmp(args[0], "retries")) { /* connection retries */
4660 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004661 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
4662 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004663 return -1;
4664 }
4665 curproxy->conn_retries = atol(args[1]);
4666 }
4667 else if (!strcmp(args[0], "option")) {
4668 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004669 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004670 return -1;
4671 }
4672 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004673 /* enable reconnections to dispatch */
4674 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004675#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004676 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004677 /* enable transparent proxy connections */
4678 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004679#endif
4680 else if (!strcmp(args[1], "keepalive"))
4681 /* enable keep-alive */
4682 curproxy->options |= PR_O_KEEPALIVE;
4683 else if (!strcmp(args[1], "forwardfor"))
4684 /* insert x-forwarded-for field */
4685 curproxy->options |= PR_O_FWDFOR;
willy tarreauc1cae632005-12-17 14:12:23 +01004686 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01004687 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01004688 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
willy tarreauc1cae632005-12-17 14:12:23 +01004689 else if (!strcmp(args[1], "tcplog"))
4690 /* generate a detailed TCP log */
4691 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID;
willy tarreaua1598082005-12-17 13:08:06 +01004692 else if (!strcmp(args[1], "dontlognull")) {
4693 /* don't log empty requests */
4694 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004695 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004696 else if (!strcmp(args[1], "httpchk")) {
4697 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004698 if (curproxy->check_req != NULL) {
4699 free(curproxy->check_req);
4700 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004701 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004702 if (!*args[2]) { /* no argument */
4703 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
4704 curproxy->check_len = strlen(DEF_CHECK_REQ);
4705 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01004706 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
4707 curproxy->check_req = (char *)malloc(reqlen);
4708 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4709 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004710 } else { /* more arguments : METHOD URI [HTTP_VER] */
4711 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
4712 if (*args[4])
4713 reqlen += strlen(args[4]);
4714 else
4715 reqlen += strlen("HTTP/1.0");
4716
4717 curproxy->check_req = (char *)malloc(reqlen);
4718 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4719 "%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 +01004720 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004721 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004722 else if (!strcmp(args[1], "persist")) {
4723 /* persist on using the server specified by the cookie, even when it's down */
4724 curproxy->options |= PR_O_PERSIST;
4725 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004726 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004727 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004728 return -1;
4729 }
4730 return 0;
4731 }
4732 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4733 /* enable reconnections to dispatch */
4734 curproxy->options |= PR_O_REDISP;
4735 }
willy tarreaua1598082005-12-17 13:08:06 +01004736#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004737 else if (!strcmp(args[0], "transparent")) {
4738 /* enable transparent proxy connections */
4739 curproxy->options |= PR_O_TRANSP;
4740 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004741#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004742 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4743 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004744 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004745 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004746 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004747 curproxy->maxconn = atol(args[1]);
4748 }
4749 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4750 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004751 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004752 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004753 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004754 curproxy->grace = atol(args[1]);
4755 }
4756 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01004757 if (curproxy == &defproxy) {
4758 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4759 return -1;
4760 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004761 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004762 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004763 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004764 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004765 curproxy->dispatch_addr = *str2sa(args[1]);
4766 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004767 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01004768 if (*(args[1])) {
4769 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004770 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004771 }
4772 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004773 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004774 return -1;
4775 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004776 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004777 else /* if no option is set, use round-robin by default */
4778 curproxy->options |= PR_O_BALANCE_RR;
4779 }
4780 else if (!strcmp(args[0], "server")) { /* server address */
4781 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004782 char *rport;
4783 char *raddr;
4784 short realport;
4785 int do_check;
4786
4787 if (curproxy == &defproxy) {
4788 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4789 return -1;
4790 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004791
willy tarreaua41a8b42005-12-17 14:02:24 +01004792 if (!*args[2]) {
4793 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004794 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004795 return -1;
4796 }
4797 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4798 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4799 return -1;
4800 }
4801 newsrv->next = curproxy->srv;
4802 curproxy->srv = newsrv;
4803 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01004804
4805 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004806 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01004807 newsrv->id = strdup(args[1]);
4808
4809 /* several ways to check the port component :
4810 * - IP => port=+0, relative
4811 * - IP: => port=+0, relative
4812 * - IP:N => port=N, absolute
4813 * - IP:+N => port=+N, relative
4814 * - IP:-N => port=-N, relative
4815 */
4816 raddr = strdup(args[2]);
4817 rport = strchr(raddr, ':');
4818 if (rport) {
4819 *rport++ = 0;
4820 realport = atol(rport);
4821 if (!isdigit((int)*rport))
4822 newsrv->state |= SRV_MAPPORTS;
4823 } else {
4824 realport = 0;
4825 newsrv->state |= SRV_MAPPORTS;
4826 }
4827
4828 newsrv->addr = *str2sa(raddr);
4829 newsrv->addr.sin_port = htons(realport);
4830 free(raddr);
4831
willy tarreau9fe663a2005-12-17 13:02:59 +01004832 newsrv->curfd = -1; /* no health-check in progress */
4833 newsrv->inter = DEF_CHKINTR;
4834 newsrv->rise = DEF_RISETIME;
4835 newsrv->fall = DEF_FALLTIME;
4836 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4837 cur_arg = 3;
4838 while (*args[cur_arg]) {
4839 if (!strcmp(args[cur_arg], "cookie")) {
4840 newsrv->cookie = strdup(args[cur_arg + 1]);
4841 newsrv->cklen = strlen(args[cur_arg + 1]);
4842 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004843 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004844 else if (!strcmp(args[cur_arg], "rise")) {
4845 newsrv->rise = atol(args[cur_arg + 1]);
4846 newsrv->health = newsrv->rise;
4847 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004848 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004849 else if (!strcmp(args[cur_arg], "fall")) {
4850 newsrv->fall = atol(args[cur_arg + 1]);
4851 cur_arg += 2;
4852 }
4853 else if (!strcmp(args[cur_arg], "inter")) {
4854 newsrv->inter = atol(args[cur_arg + 1]);
4855 cur_arg += 2;
4856 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004857 else if (!strcmp(args[cur_arg], "port")) {
4858 newsrv->check_port = atol(args[cur_arg + 1]);
4859 cur_arg += 2;
4860 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004861 else if (!strcmp(args[cur_arg], "backup")) {
4862 newsrv->state |= SRV_BACKUP;
4863 cur_arg ++;
4864 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004865 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004866 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004867 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004868 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004869 else {
willy tarreaua41a8b42005-12-17 14:02:24 +01004870 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
4871 file, linenum, newsrv->id);
4872 return -1;
4873 }
4874 }
4875
4876 if (do_check) {
4877 struct task *t;
4878
4879 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
4880 newsrv->check_port = realport; /* by default */
4881 if (!newsrv->check_port) {
4882 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 +01004883 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004884 return -1;
4885 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004886
4887 if ((t = pool_alloc(task)) == NULL) {
4888 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4889 return -1;
4890 }
4891
4892 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4893 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4894 t->state = TASK_IDLE;
4895 t->process = process_chk;
4896 t->context = newsrv;
4897
4898 if (curproxy->state != PR_STDISABLED) {
4899 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4900 task_queue(t);
4901 task_wakeup(&rq, t);
4902 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004903 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004904
willy tarreau9fe663a2005-12-17 13:02:59 +01004905 curproxy->nbservers++;
4906 }
4907 else if (!strcmp(args[0], "log")) { /* syslog server address */
4908 struct sockaddr_in *sa;
4909 int facility;
4910
4911 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4912 curproxy->logfac1 = global.logfac1;
4913 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004914 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004915 curproxy->logfac2 = global.logfac2;
4916 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01004917 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01004918 }
4919 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01004920 int level;
4921
willy tarreau0f7af912005-12-17 12:21:26 +01004922 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4923 if (!strcmp(log_facilities[facility], args[2]))
4924 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004925
willy tarreau0f7af912005-12-17 12:21:26 +01004926 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004927 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01004928 exit(1);
4929 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004930
willy tarreau8337c6b2005-12-17 13:41:01 +01004931 level = 7; /* max syslog level = debug */
4932 if (*(args[3])) {
4933 while (level >= 0 && strcmp(log_levels[level], args[3]))
4934 level--;
4935 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004936 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004937 exit(1);
4938 }
4939 }
4940
willy tarreau0f7af912005-12-17 12:21:26 +01004941 sa = str2sa(args[1]);
4942 if (!sa->sin_port)
4943 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004944
willy tarreau0f7af912005-12-17 12:21:26 +01004945 if (curproxy->logfac1 == -1) {
4946 curproxy->logsrv1 = *sa;
4947 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004948 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004949 }
4950 else if (curproxy->logfac2 == -1) {
4951 curproxy->logsrv2 = *sa;
4952 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004953 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004954 }
4955 else {
4956 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004957 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004958 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004959 }
4960 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004961 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004962 file, linenum);
4963 return -1;
4964 }
4965 }
willy tarreaua1598082005-12-17 13:08:06 +01004966 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01004967 if (!*args[1]) {
4968 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004969 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01004970 return -1;
4971 }
4972
4973 curproxy->source_addr = *str2sa(args[1]);
4974 curproxy->options |= PR_O_BIND_SRC;
4975 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004976 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4977 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004978 if (curproxy == &defproxy) {
4979 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4980 return -1;
4981 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004982
4983 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004984 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4985 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004986 return -1;
4987 }
4988
4989 preg = calloc(1, sizeof(regex_t));
4990 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004991 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004992 return -1;
4993 }
4994
4995 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4996 }
4997 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4998 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004999 if (curproxy == &defproxy) {
5000 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5001 return -1;
5002 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005003
5004 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005005 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005006 return -1;
5007 }
5008
5009 preg = calloc(1, sizeof(regex_t));
5010 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005011 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005012 return -1;
5013 }
5014
5015 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5016 }
5017 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
5018 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005019 if (curproxy == &defproxy) {
5020 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5021 return -1;
5022 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005023
5024 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005025 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005026 return -1;
5027 }
5028
5029 preg = calloc(1, sizeof(regex_t));
5030 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005031 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005032 return -1;
5033 }
5034
5035 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5036 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005037 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
5038 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005039 if (curproxy == &defproxy) {
5040 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5041 return -1;
5042 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005043
5044 if (*(args[1]) == 0) {
5045 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5046 return -1;
5047 }
5048
5049 preg = calloc(1, sizeof(regex_t));
5050 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5051 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5052 return -1;
5053 }
5054
5055 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5056 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005057 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
5058 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005059 if (curproxy == &defproxy) {
5060 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5061 return -1;
5062 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005063
5064 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005065 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005066 return -1;
5067 }
5068
5069 preg = calloc(1, sizeof(regex_t));
5070 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005071 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005072 return -1;
5073 }
5074
5075 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5076 }
5077 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
5078 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005079 if (curproxy == &defproxy) {
5080 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5081 return -1;
5082 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005083
5084 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005085 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5086 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005087 return -1;
5088 }
5089
5090 preg = calloc(1, sizeof(regex_t));
5091 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005092 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005093 return -1;
5094 }
5095
5096 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5097 }
5098 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
5099 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005100 if (curproxy == &defproxy) {
5101 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5102 return -1;
5103 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005104
5105 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005106 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005107 return -1;
5108 }
5109
5110 preg = calloc(1, sizeof(regex_t));
5111 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005112 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005113 return -1;
5114 }
5115
5116 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5117 }
5118 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
5119 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005120 if (curproxy == &defproxy) {
5121 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5122 return -1;
5123 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005124
5125 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005126 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005127 return -1;
5128 }
5129
5130 preg = calloc(1, sizeof(regex_t));
5131 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005132 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005133 return -1;
5134 }
5135
5136 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5137 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005138 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
5139 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005140 if (curproxy == &defproxy) {
5141 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5142 return -1;
5143 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005144
5145 if (*(args[1]) == 0) {
5146 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5147 return -1;
5148 }
5149
5150 preg = calloc(1, sizeof(regex_t));
5151 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5152 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5153 return -1;
5154 }
5155
5156 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5157 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005158 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
5159 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005160 if (curproxy == &defproxy) {
5161 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5162 return -1;
5163 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005164
5165 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005166 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005167 return -1;
5168 }
5169
5170 preg = calloc(1, sizeof(regex_t));
5171 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005172 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005173 return -1;
5174 }
5175
5176 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5177 }
5178 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005179 if (curproxy == &defproxy) {
5180 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5181 return -1;
5182 }
5183
willy tarreau9fe663a2005-12-17 13:02:59 +01005184 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005185 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005186 return 0;
5187 }
5188
5189 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005190 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005191 return -1;
5192 }
5193
5194 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005195 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005196 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01005197 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01005198
5199 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005200 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5201 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005202 return -1;
5203 }
5204
5205 preg = calloc(1, sizeof(regex_t));
5206 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005207 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005208 return -1;
5209 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005210
5211 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5212 }
5213 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
5214 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005215 if (curproxy == &defproxy) {
5216 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5217 return -1;
5218 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005219
5220 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005221 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005222 return -1;
5223 }
willy tarreaue39cd132005-12-17 13:00:18 +01005224
willy tarreau9fe663a2005-12-17 13:02:59 +01005225 preg = calloc(1, sizeof(regex_t));
5226 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005227 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005228 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005229 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005230
5231 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5232 }
5233 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01005234 regex_t *preg;
5235 if (curproxy == &defproxy) {
5236 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5237 return -1;
5238 }
willy tarreaue39cd132005-12-17 13:00:18 +01005239
willy tarreaua41a8b42005-12-17 14:02:24 +01005240 if (*(args[1]) == 0 || *(args[2]) == 0) {
5241 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5242 file, linenum, args[0]);
5243 return -1;
5244 }
willy tarreaue39cd132005-12-17 13:00:18 +01005245
willy tarreaua41a8b42005-12-17 14:02:24 +01005246 preg = calloc(1, sizeof(regex_t));
5247 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5248 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5249 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005250 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005251
5252 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5253 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005254 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
5255 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005256 if (curproxy == &defproxy) {
5257 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5258 return -1;
5259 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005260
5261 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005262 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005263 return -1;
5264 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005265
willy tarreau9fe663a2005-12-17 13:02:59 +01005266 preg = calloc(1, sizeof(regex_t));
5267 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005268 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005269 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005270 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005271
5272 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5273 }
5274 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005275 if (curproxy == &defproxy) {
5276 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5277 return -1;
5278 }
5279
willy tarreau9fe663a2005-12-17 13:02:59 +01005280 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005281 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005282 return 0;
5283 }
5284
5285 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005286 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005287 return -1;
5288 }
5289
5290 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
5291 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005292 else if (!strcmp(args[0], "errorloc")) { /* error location */
5293 int errnum;
5294 char *err;
5295
willy tarreaueedaa9f2005-12-17 14:08:03 +01005296 // if (curproxy == &defproxy) {
5297 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5298 // return -1;
5299 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005300
willy tarreau8337c6b2005-12-17 13:41:01 +01005301 if (*(args[2]) == 0) {
5302 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
5303 return -1;
5304 }
5305
5306 errnum = atol(args[1]);
5307 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
5308 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
5309
5310 if (errnum == 400) {
5311 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005312 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005313 free(curproxy->errmsg.msg400);
5314 }
5315 curproxy->errmsg.msg400 = err;
5316 curproxy->errmsg.len400 = strlen(err);
5317 }
5318 else if (errnum == 403) {
5319 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005320 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005321 free(curproxy->errmsg.msg403);
5322 }
5323 curproxy->errmsg.msg403 = err;
5324 curproxy->errmsg.len403 = strlen(err);
5325 }
5326 else if (errnum == 408) {
5327 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005328 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005329 free(curproxy->errmsg.msg408);
5330 }
5331 curproxy->errmsg.msg408 = err;
5332 curproxy->errmsg.len408 = strlen(err);
5333 }
5334 else if (errnum == 500) {
5335 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005336 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005337 free(curproxy->errmsg.msg500);
5338 }
5339 curproxy->errmsg.msg500 = err;
5340 curproxy->errmsg.len500 = strlen(err);
5341 }
5342 else if (errnum == 502) {
5343 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005344 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005345 free(curproxy->errmsg.msg502);
5346 }
5347 curproxy->errmsg.msg502 = err;
5348 curproxy->errmsg.len502 = strlen(err);
5349 }
5350 else if (errnum == 503) {
5351 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005352 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005353 free(curproxy->errmsg.msg503);
5354 }
5355 curproxy->errmsg.msg503 = err;
5356 curproxy->errmsg.len503 = strlen(err);
5357 }
5358 else if (errnum == 504) {
5359 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005360 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005361 free(curproxy->errmsg.msg504);
5362 }
5363 curproxy->errmsg.msg504 = err;
5364 curproxy->errmsg.len504 = strlen(err);
5365 }
5366 else {
5367 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
5368 free(err);
5369 }
5370 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005371 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005372 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01005373 return -1;
5374 }
5375 return 0;
5376}
willy tarreaue39cd132005-12-17 13:00:18 +01005377
willy tarreau5cbea6f2005-12-17 12:48:26 +01005378
willy tarreau9fe663a2005-12-17 13:02:59 +01005379/*
5380 * This function reads and parses the configuration file given in the argument.
5381 * returns 0 if OK, -1 if error.
5382 */
5383int readcfgfile(char *file) {
5384 char thisline[256];
5385 char *line;
5386 FILE *f;
5387 int linenum = 0;
5388 char *end;
5389 char *args[MAX_LINE_ARGS];
5390 int arg;
5391 int cfgerr = 0;
5392 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01005393
willy tarreau9fe663a2005-12-17 13:02:59 +01005394 struct proxy *curproxy = NULL;
5395 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005396
willy tarreau9fe663a2005-12-17 13:02:59 +01005397 if ((f=fopen(file,"r")) == NULL)
5398 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005399
willy tarreaueedaa9f2005-12-17 14:08:03 +01005400 init_default_instance();
5401
willy tarreau9fe663a2005-12-17 13:02:59 +01005402 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
5403 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005404
willy tarreau9fe663a2005-12-17 13:02:59 +01005405 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005406
willy tarreau9fe663a2005-12-17 13:02:59 +01005407 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01005408 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01005409 line++;
5410
5411 arg = 0;
5412 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01005413
willy tarreau9fe663a2005-12-17 13:02:59 +01005414 while (*line && arg < MAX_LINE_ARGS) {
5415 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
5416 * C equivalent value. Other combinations left unchanged (eg: \1).
5417 */
5418 if (*line == '\\') {
5419 int skip = 0;
5420 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
5421 *line = line[1];
5422 skip = 1;
5423 }
5424 else if (line[1] == 'r') {
5425 *line = '\r';
5426 skip = 1;
5427 }
5428 else if (line[1] == 'n') {
5429 *line = '\n';
5430 skip = 1;
5431 }
5432 else if (line[1] == 't') {
5433 *line = '\t';
5434 skip = 1;
5435 }
5436 else if (line[1] == 'x' && (line + 3 < end )) {
5437 unsigned char hex1, hex2;
5438 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
5439 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
5440 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
5441 *line = (hex1<<4) + hex2;
5442 skip = 3;
5443 }
5444 if (skip) {
5445 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
5446 end -= skip;
5447 }
5448 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005449 }
willy tarreaua1598082005-12-17 13:08:06 +01005450 else if (*line == '#' || *line == '\n' || *line == '\r') {
5451 /* end of string, end of loop */
5452 *line = 0;
5453 break;
5454 }
willy tarreauc29948c2005-12-17 13:10:27 +01005455 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005456 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01005457 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01005458 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01005459 line++;
5460 args[++arg] = line;
5461 }
5462 else {
5463 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005464 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005465 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005466
willy tarreau9fe663a2005-12-17 13:02:59 +01005467 /* empty line */
5468 if (!**args)
5469 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01005470
willy tarreau9fe663a2005-12-17 13:02:59 +01005471 /* zero out remaining args */
5472 while (++arg < MAX_LINE_ARGS) {
5473 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005474 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005475
willy tarreaua41a8b42005-12-17 14:02:24 +01005476 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01005477 confsect = CFG_LISTEN;
5478 else if (!strcmp(args[0], "global")) /* global config */
5479 confsect = CFG_GLOBAL;
5480 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005481
willy tarreau9fe663a2005-12-17 13:02:59 +01005482 switch (confsect) {
5483 case CFG_LISTEN:
5484 if (cfg_parse_listen(file, linenum, args) < 0)
5485 return -1;
5486 break;
5487 case CFG_GLOBAL:
5488 if (cfg_parse_global(file, linenum, args) < 0)
5489 return -1;
5490 break;
5491 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01005492 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005493 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005494 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005495
5496
willy tarreau0f7af912005-12-17 12:21:26 +01005497 }
5498 fclose(f);
5499
5500 /*
5501 * Now, check for the integrity of all that we have collected.
5502 */
5503
5504 if ((curproxy = proxy) == NULL) {
5505 Alert("parsing %s : no <listen> line. Nothing to do !\n",
5506 file);
5507 return -1;
5508 }
5509
5510 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01005511 if (curproxy->state == PR_STDISABLED) {
5512 curproxy = curproxy->next;
5513 continue;
5514 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005515 if ((curproxy->mode != PR_MODE_HEALTH) &&
5516 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01005517 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005518 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
5519 file, curproxy->id);
5520 cfgerr++;
5521 }
5522 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
5523 if (curproxy->options & PR_O_TRANSP) {
5524 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
5525 file, curproxy->id);
5526 cfgerr++;
5527 }
5528 else if (curproxy->srv == NULL) {
5529 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
5530 file, curproxy->id);
5531 cfgerr++;
5532 }
willy tarreaua1598082005-12-17 13:08:06 +01005533 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005534 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
5535 file, curproxy->id);
5536 }
5537 }
5538 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01005539 if (curproxy->cookie_name != NULL) {
5540 Warning("parsing %s : cookie will be ignored for listener %s.\n",
5541 file, curproxy->id);
5542 }
5543 if ((newsrv = curproxy->srv) != NULL) {
5544 Warning("parsing %s : servers will be ignored for listener %s.\n",
5545 file, curproxy->id);
5546 }
willy tarreaue39cd132005-12-17 13:00:18 +01005547 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005548 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
5549 file, curproxy->id);
5550 }
willy tarreaue39cd132005-12-17 13:00:18 +01005551 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005552 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
5553 file, curproxy->id);
5554 }
5555 }
5556 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
5557 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
5558 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
5559 file, curproxy->id);
5560 cfgerr++;
5561 }
5562 else {
5563 while (newsrv != NULL) {
5564 /* nothing to check for now */
5565 newsrv = newsrv->next;
5566 }
5567 }
5568 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005569 if (curproxy->errmsg.msg400 == NULL) {
5570 curproxy->errmsg.msg400 = (char *)HTTP_400;
5571 curproxy->errmsg.len400 = strlen(HTTP_400);
5572 }
5573 if (curproxy->errmsg.msg403 == NULL) {
5574 curproxy->errmsg.msg403 = (char *)HTTP_403;
5575 curproxy->errmsg.len403 = strlen(HTTP_403);
5576 }
5577 if (curproxy->errmsg.msg408 == NULL) {
5578 curproxy->errmsg.msg408 = (char *)HTTP_408;
5579 curproxy->errmsg.len408 = strlen(HTTP_408);
5580 }
5581 if (curproxy->errmsg.msg500 == NULL) {
5582 curproxy->errmsg.msg500 = (char *)HTTP_500;
5583 curproxy->errmsg.len500 = strlen(HTTP_500);
5584 }
5585 if (curproxy->errmsg.msg502 == NULL) {
5586 curproxy->errmsg.msg502 = (char *)HTTP_502;
5587 curproxy->errmsg.len502 = strlen(HTTP_502);
5588 }
5589 if (curproxy->errmsg.msg503 == NULL) {
5590 curproxy->errmsg.msg503 = (char *)HTTP_503;
5591 curproxy->errmsg.len503 = strlen(HTTP_503);
5592 }
5593 if (curproxy->errmsg.msg504 == NULL) {
5594 curproxy->errmsg.msg504 = (char *)HTTP_504;
5595 curproxy->errmsg.len504 = strlen(HTTP_504);
5596 }
willy tarreau0f7af912005-12-17 12:21:26 +01005597 curproxy = curproxy->next;
5598 }
5599 if (cfgerr > 0) {
5600 Alert("Errors found in configuration file, aborting.\n");
5601 return -1;
5602 }
5603 else
5604 return 0;
5605}
5606
5607
5608/*
5609 * This function initializes all the necessary variables. It only returns
5610 * if everything is OK. If something fails, it exits.
5611 */
5612void init(int argc, char **argv) {
5613 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01005614 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01005615 char *old_argv = *argv;
5616 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01005617 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01005618
5619 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005620 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005621 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
5622 sizeof(int)*8);
5623 exit(1);
5624 }
5625
5626 pid = getpid();
5627 progname = *argv;
5628 while ((tmp = strchr(progname, '/')) != NULL)
5629 progname = tmp + 1;
5630
5631 argc--; argv++;
5632 while (argc > 0) {
5633 char *flag;
5634
5635 if (**argv == '-') {
5636 flag = *argv+1;
5637
5638 /* 1 arg */
5639 if (*flag == 'v') {
5640 display_version();
5641 exit(0);
5642 }
5643 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01005644 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01005645 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01005646 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005647 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01005648 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01005649#if STATTIME > 0
5650 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01005651 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01005652 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01005653 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01005654#endif
5655 else { /* >=2 args */
5656 argv++; argc--;
5657 if (argc == 0)
5658 usage(old_argv);
5659
5660 switch (*flag) {
5661 case 'n' : cfg_maxconn = atol(*argv); break;
5662 case 'N' : cfg_maxpconn = atol(*argv); break;
5663 case 'f' : cfg_cfgfile = *argv; break;
5664 default: usage(old_argv);
5665 }
5666 }
5667 }
5668 else
5669 usage(old_argv);
5670 argv++; argc--;
5671 }
5672
willy tarreau0f7af912005-12-17 12:21:26 +01005673 if (!cfg_cfgfile)
5674 usage(old_argv);
5675
5676 gethostname(hostname, MAX_HOSTNAME_LEN);
5677
5678 if (readcfgfile(cfg_cfgfile) < 0) {
5679 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
5680 exit(1);
5681 }
5682
willy tarreau9fe663a2005-12-17 13:02:59 +01005683 if (cfg_maxconn > 0)
5684 global.maxconn = cfg_maxconn;
5685
5686 if (global.maxconn == 0)
5687 global.maxconn = DEFAULT_MAXCONN;
5688
5689 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
5690
5691 if (arg_mode & MODE_DEBUG) {
5692 /* command line debug mode inhibits configuration mode */
5693 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5694 }
willy tarreau750a4722005-12-17 13:21:24 +01005695 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01005696
5697 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
5698 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
5699 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5700 }
5701
5702 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
5703 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
5704 global.nbproc = 1;
5705 }
5706
5707 if (global.nbproc < 1)
5708 global.nbproc = 1;
5709
willy tarreau0f7af912005-12-17 12:21:26 +01005710 ReadEvent = (fd_set *)calloc(1,
5711 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005712 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005713 WriteEvent = (fd_set *)calloc(1,
5714 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005715 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005716 StaticReadEvent = (fd_set *)calloc(1,
5717 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005718 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005719 StaticWriteEvent = (fd_set *)calloc(1,
5720 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005721 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005722
5723 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01005724 sizeof(struct fdtab) * (global.maxsock));
5725 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01005726 fdtab[i].state = FD_STCLOSE;
5727 }
5728}
5729
5730/*
5731 * this function starts all the proxies. It returns 0 if OK, -1 if not.
5732 */
5733int start_proxies() {
5734 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01005735 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01005736 int one = 1;
5737 int fd;
5738
5739 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01005740 if (curproxy->state == PR_STDISABLED)
5741 continue;
5742
willy tarreaua41a8b42005-12-17 14:02:24 +01005743 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
5744 if ((fd = listener->fd =
5745 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
5746 Alert("cannot create listening socket for proxy %s. Aborting.\n",
5747 curproxy->id);
5748 return -1;
5749 }
willy tarreau0f7af912005-12-17 12:21:26 +01005750
willy tarreaua41a8b42005-12-17 14:02:24 +01005751 if (fd >= global.maxsock) {
5752 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
5753 curproxy->id);
5754 close(fd);
5755 return -1;
5756 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005757
willy tarreaua41a8b42005-12-17 14:02:24 +01005758 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
5759 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
5760 (char *) &one, sizeof(one)) == -1)) {
5761 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
5762 curproxy->id);
5763 close(fd);
5764 return -1;
5765 }
willy tarreau0f7af912005-12-17 12:21:26 +01005766
willy tarreaua41a8b42005-12-17 14:02:24 +01005767 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
5768 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
5769 curproxy->id);
5770 }
willy tarreau0f7af912005-12-17 12:21:26 +01005771
willy tarreaua41a8b42005-12-17 14:02:24 +01005772 if (bind(fd,
5773 (struct sockaddr *)&listener->addr,
5774 sizeof(listener->addr)) == -1) {
5775 Alert("cannot bind socket for proxy %s. Aborting.\n",
5776 curproxy->id);
5777 close(fd);
5778 return -1;
5779 }
willy tarreau0f7af912005-12-17 12:21:26 +01005780
willy tarreaua41a8b42005-12-17 14:02:24 +01005781 if (listen(fd, curproxy->maxconn) == -1) {
5782 Alert("cannot listen to socket for proxy %s. Aborting.\n",
5783 curproxy->id);
5784 close(fd);
5785 return -1;
5786 }
willy tarreau0f7af912005-12-17 12:21:26 +01005787
willy tarreaua41a8b42005-12-17 14:02:24 +01005788 /* the function for the accept() event */
5789 fdtab[fd].read = &event_accept;
5790 fdtab[fd].write = NULL; /* never called */
5791 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
5792 curproxy->state = PR_STRUN;
5793 fdtab[fd].state = FD_STLISTEN;
5794 FD_SET(fd, StaticReadEvent);
5795 fd_insert(fd);
5796 listeners++;
5797 }
willy tarreaua1598082005-12-17 13:08:06 +01005798 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005799 }
5800 return 0;
5801}
5802
5803
5804int main(int argc, char **argv) {
5805 init(argc, argv);
5806
willy tarreau9fe663a2005-12-17 13:02:59 +01005807 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01005808 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005809 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01005810 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01005811 }
5812
5813 signal(SIGQUIT, dump);
5814 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01005815 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005816
5817 /* on very high loads, a sigpipe sometimes happen just between the
5818 * getsockopt() which tells "it's OK to write", and the following write :-(
5819 */
willy tarreau3242e862005-12-17 12:27:53 +01005820#ifndef MSG_NOSIGNAL
5821 signal(SIGPIPE, SIG_IGN);
5822#endif
willy tarreau0f7af912005-12-17 12:21:26 +01005823
5824 if (start_proxies() < 0)
5825 exit(1);
5826
willy tarreau9fe663a2005-12-17 13:02:59 +01005827 /* open log files */
5828
5829 /* chroot if needed */
5830 if (global.chroot != NULL) {
5831 if (chroot(global.chroot) == -1) {
5832 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
5833 exit(1);
5834 }
5835 chdir("/");
5836 }
5837
5838 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01005839 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005840 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
5841 exit(1);
5842 }
5843
willy tarreau036e1ce2005-12-17 13:46:33 +01005844 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005845 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
5846 exit(1);
5847 }
5848
5849 if (global.mode & MODE_DAEMON) {
5850 int ret = 0;
5851 int proc;
5852
5853 /* the father launches the required number of processes */
5854 for (proc = 0; proc < global.nbproc; proc++) {
5855 ret = fork();
5856 if (ret < 0) {
5857 Alert("[%s.main()] Cannot fork.\n", argv[0]);
5858 exit(1); /* there has been an error */
5859 }
5860 else if (ret == 0) /* child breaks here */
5861 break;
5862 }
5863 if (proc == global.nbproc)
5864 exit(0); /* parent must leave */
5865
willy tarreau750a4722005-12-17 13:21:24 +01005866 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
5867 * that we can detach from the TTY. We MUST NOT do it in other cases since
5868 * it would have already be done, and 0-2 would have been affected to listening
5869 * sockets
5870 */
5871 if (!(global.mode & MODE_QUIET)) {
5872 /* detach from the tty */
5873 fclose(stdin); fclose(stdout); fclose(stderr);
5874 close(0); close(1); close(2); /* close all fd's */
5875 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
5876 }
willy tarreaua1598082005-12-17 13:08:06 +01005877 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01005878 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01005879 }
5880
willy tarreau0f7af912005-12-17 12:21:26 +01005881 select_loop();
5882
5883 exit(0);
5884}