blob: ff880a6ed566dddd8c413c31dbac792d7ff266be [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 tarreau2f6ba652005-12-17 13:57:42 +010056#define HAPROXY_VERSION "1.1.21"
57#define HAPROXY_DATE "2003/05/06"
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 */
298#define SRV_RUNNING 1
willy tarreau8337c6b2005-12-17 13:41:01 +0100299#define SRV_BACKUP 2
willy tarreau0f7af912005-12-17 12:21:26 +0100300
willy tarreaue39cd132005-12-17 13:00:18 +0100301/* what to do when a header matches a regex */
302#define ACT_ALLOW 0 /* allow the request */
303#define ACT_REPLACE 1 /* replace the matching header */
304#define ACT_REMOVE 2 /* remove the matching header */
305#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100306#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100307
willy tarreau9fe663a2005-12-17 13:02:59 +0100308/* configuration sections */
309#define CFG_NONE 0
310#define CFG_GLOBAL 1
311#define CFG_LISTEN 2
312
willy tarreaua1598082005-12-17 13:08:06 +0100313/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100314#define LW_DATE 1 /* date */
315#define LW_CLIP 2 /* CLient IP */
316#define LW_SVIP 4 /* SerVer IP */
317#define LW_SVID 8 /* server ID */
318#define LW_REQ 16 /* http REQuest */
319#define LW_RESP 32 /* http RESPonse */
320#define LW_PXIP 64 /* proxy IP */
321#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100322#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100323
willy tarreau0f7af912005-12-17 12:21:26 +0100324/*********************************************************************/
325
326#define LIST_HEAD(a) ((void *)(&(a)))
327
328/*********************************************************************/
329
330struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100331 struct hdr_exp *next;
332 regex_t *preg; /* expression to look for */
333 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
334 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100335};
336
337struct buffer {
338 unsigned int l; /* data length */
339 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100340 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100341 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100342 char data[BUFSIZE];
343};
344
345struct server {
346 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100347 int state; /* server state (SRV_*) */
348 int cklen; /* the len of the cookie, to speed up checks */
349 char *cookie; /* the id set in the cookie */
350 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100351 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100352 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100353 int rise, fall; /* time in iterations */
354 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100355 int result; /* 0 = connect OK, -1 = connect KO */
356 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100357 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100358};
359
willy tarreau5cbea6f2005-12-17 12:48:26 +0100360/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100361struct task {
362 struct task *next, *prev; /* chaining ... */
363 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100364 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100365 int state; /* task state : IDLE or RUNNING */
366 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100367 int (*process)(struct task *t); /* the function which processes the task */
368 void *context; /* the task's context */
369};
370
371/* WARNING: if new fields are added, they must be initialized in event_accept() */
372struct session {
373 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100374 /* application specific below */
375 struct timeval crexpire; /* expiration date for a client read */
376 struct timeval cwexpire; /* expiration date for a client write */
377 struct timeval srexpire; /* expiration date for a server read */
378 struct timeval swexpire; /* expiration date for a server write */
379 struct timeval cnexpire; /* expiration date for a connect */
380 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
381 struct proxy *proxy; /* the proxy this socket belongs to */
382 int cli_fd; /* the client side fd */
383 int srv_fd; /* the server side fd */
384 int cli_state; /* state of the client side */
385 int srv_state; /* state of the server side */
386 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100387 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100388 struct buffer *req; /* request buffer */
389 struct buffer *rep; /* response buffer */
390 struct sockaddr_in cli_addr; /* the client address */
391 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100392 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100393 struct {
394 int logwait; /* log fields waiting to be collected : LW_* */
395 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
396 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
397 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
398 long t_data; /* delay before the first data byte from the server ... */
399 unsigned long t_close; /* total session duration */
400 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100401 char *cli_cookie; /* cookie presented by the client, in capture mode */
402 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100403 int status; /* HTTP status from the server, negative if from proxy */
404 long long bytes; /* number of bytes transferred from the server */
405 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100406 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100407};
408
409struct proxy {
410 int listen_fd; /* the listen socket */
411 int state; /* proxy state */
412 struct sockaddr_in listen_addr; /* the address we listen to */
413 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100414 struct server *srv, *cursrv; /* known servers, current server */
415 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100416 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100417 int cookie_len; /* strlen(cookie_len), computed only once */
418 char *capture_name; /* beginning of the name of the cookie to capture */
419 int capture_namelen; /* length of the cookie name to match */
420 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100421 int clitimeout; /* client I/O timeout (in milliseconds) */
422 int srvtimeout; /* server I/O timeout (in milliseconds) */
423 int contimeout; /* connect timeout (in milliseconds) */
424 char *id; /* proxy id */
425 int nbconn; /* # of active sessions */
426 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100427 int conn_retries; /* maximum number of connect retries */
428 int options; /* PR_O_REDISP, PR_O_TRANSP */
429 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100430 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100431 struct proxy *next;
432 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
433 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100434 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100435 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100436 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100437 int nb_reqadd, nb_rspadd;
438 struct hdr_exp *req_exp; /* regular expressions for request headers */
439 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
440 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100441 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100442 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
443 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100444 struct {
445 char *msg400; /* message for error 400 */
446 int len400; /* message length for error 400 */
447 char *msg403; /* message for error 403 */
448 int len403; /* message length for error 403 */
449 char *msg408; /* message for error 408 */
450 int len408; /* message length for error 408 */
451 char *msg500; /* message for error 500 */
452 int len500; /* message length for error 500 */
453 char *msg502; /* message for error 502 */
454 int len502; /* message length for error 502 */
455 char *msg503; /* message for error 503 */
456 int len503; /* message length for error 503 */
457 char *msg504; /* message for error 504 */
458 int len504; /* message length for error 504 */
459 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100460};
461
462/* info about one given fd */
463struct fdtab {
464 int (*read)(int fd); /* read function */
465 int (*write)(int fd); /* write function */
466 struct task *owner; /* the session (or proxy) associated with this fd */
467 int state; /* the state of this fd */
468};
469
470/*********************************************************************/
471
willy tarreau0f7af912005-12-17 12:21:26 +0100472int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100473char *cfg_cfgfile = NULL; /* configuration file */
474char *progname = NULL; /* program name */
475int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100476
477/* global options */
478static struct {
479 int uid;
480 int gid;
481 int nbproc;
482 int maxconn;
483 int maxsock; /* max # of sockets */
484 int mode;
485 char *chroot;
486 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100487 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100488 struct sockaddr_in logsrv1, logsrv2;
489} global = {
490 logfac1 : -1,
491 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100492 loglev1 : 7, /* max syslog level : debug */
493 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100494 /* others NULL OK */
495};
496
willy tarreau0f7af912005-12-17 12:21:26 +0100497/*********************************************************************/
498
499fd_set *ReadEvent,
500 *WriteEvent,
501 *StaticReadEvent,
502 *StaticWriteEvent;
503
504void **pool_session = NULL,
505 **pool_buffer = NULL,
506 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100507 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100508 **pool_task = NULL,
509 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100510
511struct proxy *proxy = NULL; /* list of all existing proxies */
512struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100513struct task *rq = NULL; /* global run queue */
514struct task wait_queue = { /* global wait queue */
515 prev:LIST_HEAD(wait_queue),
516 next:LIST_HEAD(wait_queue)
517};
willy tarreau0f7af912005-12-17 12:21:26 +0100518
willy tarreau0f7af912005-12-17 12:21:26 +0100519static int totalconn = 0; /* total # of terminated sessions */
520static int actconn = 0; /* # of active sessions */
521static int maxfd = 0; /* # of the highest fd + 1 */
522static int listeners = 0; /* # of listeners */
523static int stopping = 0; /* non zero means stopping in progress */
524static struct timeval now = {0,0}; /* the current date at any moment */
525
526static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100527/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100528static char trash[BUFSIZE];
529
530/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100531 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100532 */
533
534#define MAX_SYSLOG_LEN 1024
535#define NB_LOG_FACILITIES 24
536const char *log_facilities[NB_LOG_FACILITIES] = {
537 "kern", "user", "mail", "daemon",
538 "auth", "syslog", "lpr", "news",
539 "uucp", "cron", "auth2", "ftp",
540 "ntp", "audit", "alert", "cron2",
541 "local0", "local1", "local2", "local3",
542 "local4", "local5", "local6", "local7"
543};
544
545
546#define NB_LOG_LEVELS 8
547const char *log_levels[NB_LOG_LEVELS] = {
548 "emerg", "alert", "crit", "err",
549 "warning", "notice", "info", "debug"
550};
551
552#define SYSLOG_PORT 514
553
554const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
555 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100556
557const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
558const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
559const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
560const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
561 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
562 unknown, Set-cookie Rewritten */
563
willy tarreau0f7af912005-12-17 12:21:26 +0100564#define MAX_HOSTNAME_LEN 32
565static char hostname[MAX_HOSTNAME_LEN] = "";
566
willy tarreau8337c6b2005-12-17 13:41:01 +0100567const char *HTTP_302 =
568 "HTTP/1.0 302 Found\r\n"
569 "Cache-Control: no-cache\r\n"
570 "Connection: close\r\n"
571 "Location: "; /* not terminated since it will be concatenated with the URL */
572
willy tarreaua1598082005-12-17 13:08:06 +0100573const char *HTTP_400 =
574 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100575 "Cache-Control: no-cache\r\n"
576 "Connection: close\r\n"
577 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100578 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100579
willy tarreaua1598082005-12-17 13:08:06 +0100580const char *HTTP_403 =
581 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100582 "Cache-Control: no-cache\r\n"
583 "Connection: close\r\n"
584 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100585 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
586
willy tarreau8337c6b2005-12-17 13:41:01 +0100587const char *HTTP_408 =
588 "HTTP/1.0 408 Request Time-out\r\n"
589 "Cache-Control: no-cache\r\n"
590 "Connection: close\r\n"
591 "\r\n"
592 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
593
willy tarreau750a4722005-12-17 13:21:24 +0100594const char *HTTP_500 =
595 "HTTP/1.0 500 Server Error\r\n"
596 "Cache-Control: no-cache\r\n"
597 "Connection: close\r\n"
598 "\r\n"
599 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100600
601const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100602 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100603 "Cache-Control: no-cache\r\n"
604 "Connection: close\r\n"
605 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100606 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
607
608const char *HTTP_503 =
609 "HTTP/1.0 503 Service Unavailable\r\n"
610 "Cache-Control: no-cache\r\n"
611 "Connection: close\r\n"
612 "\r\n"
613 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
614
615const char *HTTP_504 =
616 "HTTP/1.0 504 Gateway Time-out\r\n"
617 "Cache-Control: no-cache\r\n"
618 "Connection: close\r\n"
619 "\r\n"
620 "<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 +0100621
willy tarreau0f7af912005-12-17 12:21:26 +0100622/*********************************************************************/
623/* statistics ******************************************************/
624/*********************************************************************/
625
willy tarreau750a4722005-12-17 13:21:24 +0100626#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100627static int stats_tsk_lsrch, stats_tsk_rsrch,
628 stats_tsk_good, stats_tsk_right, stats_tsk_left,
629 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100630#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100631
632
633/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100634/* debugging *******************************************************/
635/*********************************************************************/
636#ifdef DEBUG_FULL
637static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
638static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
639#endif
640
641/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100642/* function prototypes *********************************************/
643/*********************************************************************/
644
645int event_accept(int fd);
646int event_cli_read(int fd);
647int event_cli_write(int fd);
648int event_srv_read(int fd);
649int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100650int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100651
652/*********************************************************************/
653/* general purpose functions ***************************************/
654/*********************************************************************/
655
656void display_version() {
657 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100658 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100659}
660
661/*
662 * This function prints the command line usage and exits
663 */
664void usage(char *name) {
665 display_version();
666 fprintf(stderr,
667 "Usage : %s -f <cfgfile> [ -vd"
668#if STATTIME > 0
669 "sl"
670#endif
671 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
672 " -v displays version\n"
673 " -d enters debug mode\n"
674#if STATTIME > 0
675 " -s enables statistics output\n"
676 " -l enables long statistics format\n"
677#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100678 " -D goes daemon ; implies -q\n"
679 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100680 " -n sets the maximum total # of connections (%d)\n"
681 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100682 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100683 exit(1);
684}
685
686
687/*
688 * Displays the message on stderr with the date and pid.
689 */
690void Alert(char *fmt, ...) {
691 va_list argp;
692 struct timeval tv;
693 struct tm *tm;
694
willy tarreau9fe663a2005-12-17 13:02:59 +0100695 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100696 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100697
willy tarreau5cbea6f2005-12-17 12:48:26 +0100698 gettimeofday(&tv, NULL);
699 tm=localtime(&tv.tv_sec);
700 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100701 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100702 vfprintf(stderr, fmt, argp);
703 fflush(stderr);
704 va_end(argp);
705 }
willy tarreau0f7af912005-12-17 12:21:26 +0100706}
707
708
709/*
710 * Displays the message on stderr with the date and pid.
711 */
712void Warning(char *fmt, ...) {
713 va_list argp;
714 struct timeval tv;
715 struct tm *tm;
716
willy tarreau9fe663a2005-12-17 13:02:59 +0100717 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100718 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100719
willy tarreau5cbea6f2005-12-17 12:48:26 +0100720 gettimeofday(&tv, NULL);
721 tm=localtime(&tv.tv_sec);
722 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100723 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100724 vfprintf(stderr, fmt, argp);
725 fflush(stderr);
726 va_end(argp);
727 }
728}
729
730/*
731 * Displays the message on <out> only if quiet mode is not set.
732 */
733void qfprintf(FILE *out, char *fmt, ...) {
734 va_list argp;
735
willy tarreau9fe663a2005-12-17 13:02:59 +0100736 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100737 va_start(argp, fmt);
738 vfprintf(out, fmt, argp);
739 fflush(out);
740 va_end(argp);
741 }
willy tarreau0f7af912005-12-17 12:21:26 +0100742}
743
744
745/*
746 * converts <str> to a struct sockaddr_in* which is locally allocated.
747 * The format is "addr:port", where "addr" can be empty or "*" to indicate
748 * INADDR_ANY.
749 */
750struct sockaddr_in *str2sa(char *str) {
751 static struct sockaddr_in sa;
752 char *c;
753 int port;
754
willy tarreaua1598082005-12-17 13:08:06 +0100755 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100756 str=strdup(str);
757
758 if ((c=strrchr(str,':')) != NULL) {
759 *c++=0;
760 port=atol(c);
761 }
762 else
763 port=0;
764
765 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
766 sa.sin_addr.s_addr = INADDR_ANY;
767 }
768 else if (
769#ifndef SOLARIS
770 !inet_aton(str, &sa.sin_addr)
771#else
772 !inet_pton(AF_INET, str, &sa.sin_addr)
773#endif
774 ) {
775 struct hostent *he;
776
777 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100778 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100779 }
780 else
781 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
782 }
783 sa.sin_port=htons(port);
784 sa.sin_family=AF_INET;
785
786 free(str);
787 return &sa;
788}
789
willy tarreau9fe663a2005-12-17 13:02:59 +0100790
791/*
792 * This function sends a syslog message to both log servers of a proxy,
793 * or to global log servers if the proxy is NULL.
794 * It also tries not to waste too much time computing the message header.
795 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100796 */
797void send_log(struct proxy *p, int level, char *message, ...) {
798 static int logfd = -1; /* syslog UDP socket */
799 static long tvsec = -1; /* to force the string to be initialized */
800 struct timeval tv;
801 va_list argp;
802 static char logmsg[MAX_SYSLOG_LEN];
803 static char *dataptr = NULL;
804 int fac_level;
805 int hdr_len, data_len;
806 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +0100807 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +0100808 int nbloggers = 0;
809 char *log_ptr;
810
811 if (logfd < 0) {
812 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
813 return;
814 }
815
816 if (level < 0 || progname == NULL || message == NULL)
817 return;
818
819 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100820 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100821 /* this string is rebuild only once a second */
822 struct tm *tm = localtime(&tv.tv_sec);
823 tvsec = tv.tv_sec;
824
willy tarreauc29948c2005-12-17 13:10:27 +0100825 hdr_len = snprintf(logmsg, sizeof(logmsg),
826 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
827 monthname[tm->tm_mon],
828 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
829 progname, pid);
830 /* WARNING: depending upon implementations, snprintf may return
831 * either -1 or the number of bytes that would be needed to store
832 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100833 */
willy tarreauc29948c2005-12-17 13:10:27 +0100834 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
835 hdr_len = sizeof(logmsg);
836
837 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100838 }
839
840 va_start(argp, message);
841 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100842 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
843 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100844 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100845 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100846
847 if (p == NULL) {
848 if (global.logfac1 >= 0) {
849 sa[nbloggers] = &global.logsrv1;
850 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100851 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100852 nbloggers++;
853 }
854 if (global.logfac2 >= 0) {
855 sa[nbloggers] = &global.logsrv2;
856 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100857 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100858 nbloggers++;
859 }
860 } else {
861 if (p->logfac1 >= 0) {
862 sa[nbloggers] = &p->logsrv1;
863 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100864 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100865 nbloggers++;
866 }
867 if (p->logfac2 >= 0) {
868 sa[nbloggers] = &p->logsrv2;
869 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100870 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100871 nbloggers++;
872 }
873 }
874
875 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +0100876 /* we can filter the level of the messages that are sent to each logger */
877 if (level > loglevel[nbloggers])
878 continue;
879
willy tarreauc29948c2005-12-17 13:10:27 +0100880 /* For each target, we may have a different facility.
881 * We can also have a different log level for each message.
882 * This induces variations in the message header length.
883 * Since we don't want to recompute it each time, nor copy it every
884 * time, we only change the facility in the pre-computed header,
885 * and we change the pointer to the header accordingly.
886 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100887 fac_level = (facilities[nbloggers] << 3) + level;
888 log_ptr = logmsg + 3; /* last digit of the log level */
889 do {
890 *log_ptr = '0' + fac_level % 10;
891 fac_level /= 10;
892 log_ptr--;
893 } while (fac_level && log_ptr > logmsg);
894 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100895
willy tarreauc29948c2005-12-17 13:10:27 +0100896 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100897
898#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100899 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100900 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
901#else
willy tarreauc29948c2005-12-17 13:10:27 +0100902 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100903 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
904#endif
905 }
willy tarreau0f7af912005-12-17 12:21:26 +0100906}
907
908
909/* sets <tv> to the current time */
910static inline struct timeval *tv_now(struct timeval *tv) {
911 if (tv)
912 gettimeofday(tv, NULL);
913 return tv;
914}
915
916/*
917 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
918 */
919static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
920 if (!tv || !from)
921 return NULL;
922 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
923 tv->tv_sec = from->tv_sec + (ms/1000);
924 while (tv->tv_usec >= 1000000) {
925 tv->tv_usec -= 1000000;
926 tv->tv_sec++;
927 }
928 return tv;
929}
930
931/*
932 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
933 */
934static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +0100935 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100936 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100937 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100938 return 1;
939 else if (tv1->tv_usec < tv2->tv_usec)
940 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100941 else if (tv1->tv_usec > tv2->tv_usec)
942 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +0100943 else
944 return 0;
945}
946
947/*
948 * returns the absolute difference, in ms, between tv1 and tv2
949 */
950unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
951 int cmp;
952 unsigned long ret;
953
954
willy tarreauef900ab2005-12-17 12:52:52 +0100955 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100956 if (!cmp)
957 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +0100958 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100959 struct timeval *tmp = tv1;
960 tv1 = tv2;
961 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100962 }
willy tarreauef900ab2005-12-17 12:52:52 +0100963 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100964 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100965 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100966 else
willy tarreauef900ab2005-12-17 12:52:52 +0100967 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100968 return (unsigned long) ret;
969}
970
971/*
willy tarreau750a4722005-12-17 13:21:24 +0100972 * returns the difference, in ms, between tv1 and tv2
973 */
974static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
975 unsigned long ret;
976
willy tarreau6e682ce2005-12-17 13:26:49 +0100977 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
978 if (tv2->tv_usec > tv1->tv_usec)
979 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100980 else
willy tarreau6e682ce2005-12-17 13:26:49 +0100981 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100982 return (unsigned long) ret;
983}
984
985/*
willy tarreau0f7af912005-12-17 12:21:26 +0100986 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
987 */
988static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100989 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +0100990 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100991 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100992 else if (tv1->tv_usec > tv2->tv_usec + 1000)
993 return 1;
willy tarreauefae1842005-12-17 12:51:03 +0100994 else
995 return 0;
996 }
willy tarreau0f7af912005-12-17 12:21:26 +0100997 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100998 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100999 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001000 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1001 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1002 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001003 else
1004 return 0;
1005}
1006
1007/*
1008 * returns the remaining time between tv1=now and event=tv2
1009 * if tv2 is passed, 0 is returned.
1010 */
1011static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1012 unsigned long ret;
1013
willy tarreau0f7af912005-12-17 12:21:26 +01001014 if (tv_cmp_ms(tv1, tv2) >= 0)
1015 return 0; /* event elapsed */
1016
willy tarreauef900ab2005-12-17 12:52:52 +01001017 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001018 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001019 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001020 else
willy tarreauef900ab2005-12-17 12:52:52 +01001021 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001022 return (unsigned long) ret;
1023}
1024
1025
1026/*
1027 * zeroes a struct timeval
1028 */
1029
1030static inline struct timeval *tv_eternity(struct timeval *tv) {
1031 tv->tv_sec = tv->tv_usec = 0;
1032 return tv;
1033}
1034
1035/*
1036 * returns 1 if tv is null, else 0
1037 */
1038static inline int tv_iseternity(struct timeval *tv) {
1039 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1040 return 1;
1041 else
1042 return 0;
1043}
1044
1045/*
1046 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1047 * considering that 0 is the eternity.
1048 */
1049static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1050 if (tv_iseternity(tv1))
1051 if (tv_iseternity(tv2))
1052 return 0; /* same */
1053 else
1054 return 1; /* tv1 later than tv2 */
1055 else if (tv_iseternity(tv2))
1056 return -1; /* tv2 later than tv1 */
1057
1058 if (tv1->tv_sec > tv2->tv_sec)
1059 return 1;
1060 else if (tv1->tv_sec < tv2->tv_sec)
1061 return -1;
1062 else if (tv1->tv_usec > tv2->tv_usec)
1063 return 1;
1064 else if (tv1->tv_usec < tv2->tv_usec)
1065 return -1;
1066 else
1067 return 0;
1068}
1069
1070/*
1071 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1072 * considering that 0 is the eternity.
1073 */
1074static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1075 if (tv_iseternity(tv1))
1076 if (tv_iseternity(tv2))
1077 return 0; /* same */
1078 else
1079 return 1; /* tv1 later than tv2 */
1080 else if (tv_iseternity(tv2))
1081 return -1; /* tv2 later than tv1 */
1082
willy tarreauefae1842005-12-17 12:51:03 +01001083 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001084 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001085 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001086 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001087 return -1;
1088 else
1089 return 0;
1090 }
1091 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001092 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001093 return 1;
1094 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001095 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001096 return -1;
1097 else
1098 return 0;
1099}
1100
1101/*
1102 * returns the first event between tv1 and tv2 into tvmin.
1103 * a zero tv is ignored. tvmin is returned.
1104 */
1105static inline struct timeval *tv_min(struct timeval *tvmin,
1106 struct timeval *tv1, struct timeval *tv2) {
1107
1108 if (tv_cmp2(tv1, tv2) <= 0)
1109 *tvmin = *tv1;
1110 else
1111 *tvmin = *tv2;
1112
1113 return tvmin;
1114}
1115
1116
1117
1118/***********************************************************/
1119/* fd management ***************************************/
1120/***********************************************************/
1121
1122
1123
willy tarreau5cbea6f2005-12-17 12:48:26 +01001124/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1125 * The file descriptor is also closed.
1126 */
willy tarreau0f7af912005-12-17 12:21:26 +01001127static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001128 FD_CLR(fd, StaticReadEvent);
1129 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001130 close(fd);
1131 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001132
1133 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1134 maxfd--;
1135}
1136
1137/* recomputes the maxfd limit from the fd */
1138static inline void fd_insert(int fd) {
1139 if (fd+1 > maxfd)
1140 maxfd = fd+1;
1141}
1142
1143/*************************************************************/
1144/* task management ***************************************/
1145/*************************************************************/
1146
willy tarreau5cbea6f2005-12-17 12:48:26 +01001147/* puts the task <t> in run queue <q>, and returns <t> */
1148static inline struct task *task_wakeup(struct task **q, struct task *t) {
1149 if (t->state == TASK_RUNNING)
1150 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001151 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001152 t->rqnext = *q;
1153 t->state = TASK_RUNNING;
1154 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001155 }
1156}
1157
willy tarreau5cbea6f2005-12-17 12:48:26 +01001158/* removes the task <t> from the queue <q>
1159 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001160 * set the run queue to point to the next one, and return it
1161 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001162static inline struct task *task_sleep(struct task **q, struct task *t) {
1163 if (t->state == TASK_RUNNING) {
1164 *q = t->rqnext;
1165 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001166 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001167 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001168}
1169
1170/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001171 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001172 * from the run queue. A pointer to the task itself is returned.
1173 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001174static inline struct task *task_delete(struct task *t) {
1175 t->prev->next = t->next;
1176 t->next->prev = t->prev;
1177 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001178}
1179
1180/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001181 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001182 */
1183static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001184 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001185}
1186
willy tarreau5cbea6f2005-12-17 12:48:26 +01001187/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001188 * may be only moved or left where it was, depending on its timing requirements.
1189 * <task> is returned.
1190 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001191struct task *task_queue(struct task *task) {
1192 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001193 struct task *start_from;
1194
1195 /* first, test if the task was already in a list */
1196 if (task->prev == NULL) {
1197 // start_from = list;
1198 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001199#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001200 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001201#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001202 /* insert the unlinked <task> into the list, searching back from the last entry */
1203 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1204 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001205#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001206 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001207#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001208 }
1209
1210 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1211 // start_from = start_from->next;
1212 // stats_tsk_nsrch++;
1213 // }
1214 }
1215 else if (task->prev == list ||
1216 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1217 start_from = task->next;
1218 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001219#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001220 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001221#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001222 return task; /* it's already in the right place */
1223 }
1224
willy tarreau750a4722005-12-17 13:21:24 +01001225#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001226 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001227#endif
1228
1229 /* if the task is not at the right place, there's little chance that
1230 * it has only shifted a bit, and it will nearly always be queued
1231 * at the end of the list because of constant timeouts
1232 * (observed in real case).
1233 */
1234#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1235 start_from = list->prev; /* assume we'll queue to the end of the list */
1236 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1237 start_from = start_from->prev;
1238#if STATTIME > 0
1239 stats_tsk_lsrch++;
1240#endif
1241 }
1242#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001243 /* insert the unlinked <task> into the list, searching after position <start_from> */
1244 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1245 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001246#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001247 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001248#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001249 }
willy tarreau750a4722005-12-17 13:21:24 +01001250#endif /* WE_REALLY_... */
1251
willy tarreau0f7af912005-12-17 12:21:26 +01001252 /* we need to unlink it now */
1253 task_delete(task);
1254 }
1255 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001256#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001257 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001258#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001259#ifdef LEFT_TO_TOP /* not very good */
1260 start_from = list;
1261 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1262 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001263#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001264 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001265#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001266 }
1267#else
1268 start_from = task->prev->prev; /* valid because of the previous test above */
1269 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1270 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001271#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001272 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001273#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001274 }
1275#endif
1276 /* we need to unlink it now */
1277 task_delete(task);
1278 }
1279 task->prev = start_from;
1280 task->next = start_from->next;
1281 task->next->prev = task;
1282 start_from->next = task;
1283 return task;
1284}
1285
1286
1287/*********************************************************************/
1288/* more specific functions ***************************************/
1289/*********************************************************************/
1290
1291/* some prototypes */
1292static int maintain_proxies(void);
1293
willy tarreau5cbea6f2005-12-17 12:48:26 +01001294/* this either returns the sockname or the original destination address. Code
1295 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1296 */
1297static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001298#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001299 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1300#else
willy tarreaua1598082005-12-17 13:08:06 +01001301#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001302 return getsockname(fd, (struct sockaddr *)sa, salen);
1303#else
1304 return -1;
1305#endif
1306#endif
1307}
1308
1309/*
1310 * frees the context associated to a session. It must have been removed first.
1311 */
1312static inline void session_free(struct session *s) {
1313 if (s->req)
1314 pool_free(buffer, s->req);
1315 if (s->rep)
1316 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001317 if (s->logs.uri)
1318 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001319 if (s->logs.cli_cookie)
1320 pool_free(capture, s->logs.cli_cookie);
1321 if (s->logs.srv_cookie)
1322 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001323
willy tarreau5cbea6f2005-12-17 12:48:26 +01001324 pool_free(session, s);
1325}
1326
willy tarreau0f7af912005-12-17 12:21:26 +01001327
1328/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001329 * This function tries to find a running server for the proxy <px>. A first
1330 * pass looks for active servers, and if none is found, a second pass also
1331 * looks for backup servers.
1332 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1333 */
1334static inline struct server *find_server(struct proxy *px) {
1335 struct server *srv = px->cursrv;
1336 int ignore_backup = 1;
1337
1338 do {
1339 do {
1340 if (srv == NULL)
1341 srv = px->srv;
1342 if (srv->state & SRV_RUNNING
1343 && !((srv->state & SRV_BACKUP) && ignore_backup))
1344 return srv;
1345 srv = srv->next;
1346 } while (srv != px->cursrv);
1347 } while (ignore_backup--);
1348 return NULL;
1349}
1350
1351/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001352 * This function initiates a connection to the current server (s->srv) if (s->direct)
1353 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001354 * it's OK, -1 if it's impossible.
1355 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001356int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001357 int one = 1;
1358 int fd;
1359
1360 // fprintf(stderr,"connect_server : s=%p\n",s);
1361
willy tarreaue39cd132005-12-17 13:00:18 +01001362 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001363 s->srv_addr = s->srv->addr;
1364 }
1365 else if (s->proxy->options & PR_O_BALANCE) {
1366 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001367 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001368
willy tarreau8337c6b2005-12-17 13:41:01 +01001369 srv = find_server(s->proxy);
1370
1371 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001372 return -1;
1373
willy tarreau8337c6b2005-12-17 13:41:01 +01001374 s->srv_addr = srv->addr;
1375 s->srv = srv;
1376 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001377 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001378 else /* unknown balancing algorithm */
1379 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001380 }
willy tarreaua1598082005-12-17 13:08:06 +01001381 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001382 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001383 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001384 }
1385 else if (s->proxy->options & PR_O_TRANSP) {
1386 /* in transparent mode, use the original dest addr if no dispatch specified */
1387 int salen = sizeof(struct sockaddr_in);
1388 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1389 qfprintf(stderr, "Cannot get original server address.\n");
1390 return -1;
1391 }
1392 }
willy tarreau0f7af912005-12-17 12:21:26 +01001393
1394 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001395 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001396 return -1;
1397 }
1398
willy tarreau9fe663a2005-12-17 13:02:59 +01001399 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001400 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1401 close(fd);
1402 return -1;
1403 }
1404
willy tarreau0f7af912005-12-17 12:21:26 +01001405 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1406 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001407 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001408 close(fd);
1409 return -1;
1410 }
1411
willy tarreaua1598082005-12-17 13:08:06 +01001412 /* allow specific binding */
1413 if (s->proxy->options & PR_O_BIND_SRC &&
1414 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1415 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1416 close(fd);
1417 return -1;
1418 }
1419
willy tarreau0f7af912005-12-17 12:21:26 +01001420 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1421 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001422 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001423 close(fd);
1424 return -1;
1425 }
1426 else if (errno != EALREADY && errno != EISCONN) {
1427 close(fd);
1428 return -1;
1429 }
1430 }
1431
willy tarreau5cbea6f2005-12-17 12:48:26 +01001432 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001433 fdtab[fd].read = &event_srv_read;
1434 fdtab[fd].write = &event_srv_write;
1435 fdtab[fd].state = FD_STCONN; /* connection in progress */
1436
1437 FD_SET(fd, StaticWriteEvent); /* for connect status */
1438
1439 fd_insert(fd);
1440
1441 if (s->proxy->contimeout)
1442 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1443 else
1444 tv_eternity(&s->cnexpire);
1445 return 0;
1446}
1447
1448/*
1449 * this function is called on a read event from a client socket.
1450 * It returns 0.
1451 */
1452int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001453 struct task *t = fdtab[fd].owner;
1454 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001455 struct buffer *b = s->req;
1456 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001457
1458 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1459
willy tarreau0f7af912005-12-17 12:21:26 +01001460 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001461 while (1) {
1462 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1463 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001464 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001465 }
1466 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001467 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001468 }
1469 else {
1470 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001471 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1472 * since it means that the rewrite protection has been removed. This
1473 * implies that the if statement can be removed.
1474 */
1475 if (max > b->rlim - b->data)
1476 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001477 }
1478
1479 if (max == 0) { /* not anymore room to store data */
1480 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001481 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001482 }
1483
willy tarreau3242e862005-12-17 12:27:53 +01001484#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001485 {
1486 int skerr, lskerr;
1487
1488 lskerr = sizeof(skerr);
1489 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1490 if (skerr)
1491 ret = -1;
1492 else
1493 ret = recv(fd, b->r, max, 0);
1494 }
willy tarreau3242e862005-12-17 12:27:53 +01001495#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001496 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001497#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001498 if (ret > 0) {
1499 b->r += ret;
1500 b->l += ret;
1501 s->res_cr = RES_DATA;
1502
1503 if (b->r == b->data + BUFSIZE) {
1504 b->r = b->data; /* wrap around the buffer */
1505 }
willy tarreaua1598082005-12-17 13:08:06 +01001506
1507 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001508 /* we hope to read more data or to get a close on next round */
1509 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001510 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001511 else if (ret == 0) {
1512 s->res_cr = RES_NULL;
1513 break;
1514 }
1515 else if (errno == EAGAIN) {/* ignore EAGAIN */
1516 break;
1517 }
1518 else {
1519 s->res_cr = RES_ERROR;
1520 fdtab[fd].state = FD_STERROR;
1521 break;
1522 }
1523 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001524 }
1525 else {
1526 s->res_cr = RES_ERROR;
1527 fdtab[fd].state = FD_STERROR;
1528 }
1529
willy tarreau5cbea6f2005-12-17 12:48:26 +01001530 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001531 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001532 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1533 else
1534 tv_eternity(&s->crexpire);
1535
1536 task_wakeup(&rq, t);
1537 }
willy tarreau0f7af912005-12-17 12:21:26 +01001538
willy tarreau0f7af912005-12-17 12:21:26 +01001539 return 0;
1540}
1541
1542
1543/*
1544 * this function is called on a read event from a server socket.
1545 * It returns 0.
1546 */
1547int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001548 struct task *t = fdtab[fd].owner;
1549 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001550 struct buffer *b = s->rep;
1551 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001552
1553 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1554
willy tarreau0f7af912005-12-17 12:21:26 +01001555 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001556 while (1) {
1557 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1558 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001559 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001560 }
1561 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001562 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001563 }
1564 else {
1565 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001566 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1567 * since it means that the rewrite protection has been removed. This
1568 * implies that the if statement can be removed.
1569 */
1570 if (max > b->rlim - b->data)
1571 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001572 }
1573
1574 if (max == 0) { /* not anymore room to store data */
1575 FD_CLR(fd, StaticReadEvent);
1576 break;
1577 }
1578
willy tarreau3242e862005-12-17 12:27:53 +01001579#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001580 {
1581 int skerr, lskerr;
1582
1583 lskerr = sizeof(skerr);
1584 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1585 if (skerr)
1586 ret = -1;
1587 else
1588 ret = recv(fd, b->r, max, 0);
1589 }
willy tarreau3242e862005-12-17 12:27:53 +01001590#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001591 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001592#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001593 if (ret > 0) {
1594 b->r += ret;
1595 b->l += ret;
1596 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001597
willy tarreau5cbea6f2005-12-17 12:48:26 +01001598 if (b->r == b->data + BUFSIZE) {
1599 b->r = b->data; /* wrap around the buffer */
1600 }
willy tarreaua1598082005-12-17 13:08:06 +01001601
1602 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001603 /* we hope to read more data or to get a close on next round */
1604 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001605 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001606 else if (ret == 0) {
1607 s->res_sr = RES_NULL;
1608 break;
1609 }
1610 else if (errno == EAGAIN) {/* ignore EAGAIN */
1611 break;
1612 }
1613 else {
1614 s->res_sr = RES_ERROR;
1615 fdtab[fd].state = FD_STERROR;
1616 break;
1617 }
1618 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001619 }
1620 else {
1621 s->res_sr = RES_ERROR;
1622 fdtab[fd].state = FD_STERROR;
1623 }
1624
willy tarreau5cbea6f2005-12-17 12:48:26 +01001625 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001626 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001627 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1628 else
1629 tv_eternity(&s->srexpire);
1630
1631 task_wakeup(&rq, t);
1632 }
willy tarreau0f7af912005-12-17 12:21:26 +01001633
willy tarreau0f7af912005-12-17 12:21:26 +01001634 return 0;
1635}
1636
1637/*
1638 * this function is called on a write event from a client socket.
1639 * It returns 0.
1640 */
1641int event_cli_write(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_cli_write : fd=%d, s=%p\n", fd, s);
1648
1649 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001650 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001651 // max = BUFSIZE; BUG !!!!
1652 max = 0;
1653 }
1654 else if (b->r > b->w) {
1655 max = b->r - b->w;
1656 }
1657 else
1658 max = b->data + BUFSIZE - b->w;
1659
willy tarreau0f7af912005-12-17 12:21:26 +01001660 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001661#ifndef MSG_NOSIGNAL
1662 int skerr, lskerr;
1663#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001664
1665 if (max == 0) {
1666 s->res_cw = RES_NULL;
1667 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001668 tv_eternity(&s->cwexpire);
1669 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001670 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001671 }
1672
willy tarreau3242e862005-12-17 12:27:53 +01001673#ifndef MSG_NOSIGNAL
1674 lskerr=sizeof(skerr);
1675 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1676 if (skerr)
1677 ret = -1;
1678 else
1679 ret = send(fd, b->w, max, MSG_DONTWAIT);
1680#else
willy tarreau0f7af912005-12-17 12:21:26 +01001681 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001682#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001683
1684 if (ret > 0) {
1685 b->l -= ret;
1686 b->w += ret;
1687
1688 s->res_cw = RES_DATA;
1689
1690 if (b->w == b->data + BUFSIZE) {
1691 b->w = b->data; /* wrap around the buffer */
1692 }
1693 }
1694 else if (ret == 0) {
1695 /* nothing written, just make as if we were never called */
1696// s->res_cw = RES_NULL;
1697 return 0;
1698 }
1699 else if (errno == EAGAIN) /* ignore EAGAIN */
1700 return 0;
1701 else {
1702 s->res_cw = RES_ERROR;
1703 fdtab[fd].state = FD_STERROR;
1704 }
1705 }
1706 else {
1707 s->res_cw = RES_ERROR;
1708 fdtab[fd].state = FD_STERROR;
1709 }
1710
willy tarreaub1ff9db2005-12-17 13:51:03 +01001711 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001712 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001713 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
1714 s->crexpire = s->cwexpire;
1715 }
willy tarreau0f7af912005-12-17 12:21:26 +01001716 else
1717 tv_eternity(&s->cwexpire);
1718
willy tarreau5cbea6f2005-12-17 12:48:26 +01001719 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001720 return 0;
1721}
1722
1723
1724/*
1725 * this function is called on a write event from a server socket.
1726 * It returns 0.
1727 */
1728int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001729 struct task *t = fdtab[fd].owner;
1730 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001731 struct buffer *b = s->req;
1732 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001733
1734 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1735
1736 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001737 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001738 // max = BUFSIZE; BUG !!!!
1739 max = 0;
1740 }
1741 else if (b->r > b->w) {
1742 max = b->r - b->w;
1743 }
1744 else
1745 max = b->data + BUFSIZE - b->w;
1746
willy tarreau0f7af912005-12-17 12:21:26 +01001747 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001748#ifndef MSG_NOSIGNAL
1749 int skerr, lskerr;
1750#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001751 if (max == 0) {
1752 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001753 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001754 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001755 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01001756 tv_eternity(&s->swexpire);
1757 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01001758 return 0;
1759 }
1760
willy tarreauef900ab2005-12-17 12:52:52 +01001761
willy tarreau3242e862005-12-17 12:27:53 +01001762#ifndef MSG_NOSIGNAL
1763 lskerr=sizeof(skerr);
1764 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1765 if (skerr)
1766 ret = -1;
1767 else
1768 ret = send(fd, b->w, max, MSG_DONTWAIT);
1769#else
willy tarreau0f7af912005-12-17 12:21:26 +01001770 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001771#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001772 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001773 if (ret > 0) {
1774 b->l -= ret;
1775 b->w += ret;
1776
1777 s->res_sw = RES_DATA;
1778
1779 if (b->w == b->data + BUFSIZE) {
1780 b->w = b->data; /* wrap around the buffer */
1781 }
1782 }
1783 else if (ret == 0) {
1784 /* nothing written, just make as if we were never called */
1785 // s->res_sw = RES_NULL;
1786 return 0;
1787 }
1788 else if (errno == EAGAIN) /* ignore EAGAIN */
1789 return 0;
1790 else {
1791 s->res_sw = RES_ERROR;
1792 fdtab[fd].state = FD_STERROR;
1793 }
1794 }
1795 else {
1796 s->res_sw = RES_ERROR;
1797 fdtab[fd].state = FD_STERROR;
1798 }
1799
willy tarreaub1ff9db2005-12-17 13:51:03 +01001800 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001801 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001802 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
1803 s->srexpire = s->swexpire;
1804 }
willy tarreau0f7af912005-12-17 12:21:26 +01001805 else
1806 tv_eternity(&s->swexpire);
1807
willy tarreau5cbea6f2005-12-17 12:48:26 +01001808 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001809 return 0;
1810}
1811
1812
1813/*
willy tarreaue39cd132005-12-17 13:00:18 +01001814 * returns a message to the client ; the connection is shut down for read,
1815 * and the request is cleared so that no server connection can be initiated.
1816 * The client must be in a valid state for this (HEADER, DATA ...).
1817 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01001818 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001819 */
1820void client_retnclose(struct session *s, int len, const char *msg) {
1821 FD_CLR(s->cli_fd, StaticReadEvent);
1822 FD_SET(s->cli_fd, StaticWriteEvent);
1823 tv_eternity(&s->crexpire);
1824 shutdown(s->cli_fd, SHUT_RD);
1825 s->cli_state = CL_STSHUTR;
1826 strcpy(s->rep->data, msg);
1827 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001828 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001829 s->rep->r += len;
1830 s->req->l = 0;
1831}
1832
1833
1834/*
1835 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01001836 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001837 */
1838void client_return(struct session *s, int len, const char *msg) {
1839 strcpy(s->rep->data, msg);
1840 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001841 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001842 s->rep->r += len;
1843 s->req->l = 0;
1844}
1845
willy tarreau9fe663a2005-12-17 13:02:59 +01001846/*
1847 * send a log for the session when we have enough info about it
1848 */
1849void sess_log(struct session *s) {
1850 unsigned char *pn;
1851 struct proxy *p = s->proxy;
1852 int log;
1853 char *uri;
1854 char *pxid;
1855 char *srv;
1856
1857 /* This is a first attempt at a better logging system.
1858 * For now, we rely on send_log() to provide the date, although it obviously
1859 * is the date of the log and not of the request, and most fields are not
1860 * computed.
1861 */
1862
willy tarreaua1598082005-12-17 13:08:06 +01001863 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001864
1865 pn = (log & LW_CLIP) ?
1866 (unsigned char *)&s->cli_addr.sin_addr :
1867 (unsigned char *)"\0\0\0\0";
1868
willy tarreaua1598082005-12-17 13:08:06 +01001869 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001870 pxid = p->id;
1871 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001872 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1873
1874 if (p->to_log & LW_DATE) {
1875 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1876
willy tarreau036e1ce2005-12-17 13:46:33 +01001877 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 +01001878 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1879 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1880 tm->tm_hour, tm->tm_min, tm->tm_sec,
1881 pxid, srv,
1882 s->logs.t_request,
1883 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1884 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1885 s->logs.t_close,
1886 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001887 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1888 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01001889 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
1890 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
1891 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
1892 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01001893 uri);
1894 }
1895 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01001896 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
willy tarreaua1598082005-12-17 13:08:06 +01001897 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1898 pxid, srv,
1899 s->logs.t_request,
1900 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1901 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1902 s->logs.t_close,
1903 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001904 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1905 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01001906 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
1907 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
1908 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
1909 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01001910 uri);
1911 }
1912
1913 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001914}
1915
willy tarreaue39cd132005-12-17 13:00:18 +01001916
1917/*
willy tarreau0f7af912005-12-17 12:21:26 +01001918 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001919 * to an accept. It tries to accept as many connections as possible.
1920 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001921 */
1922int event_accept(int fd) {
1923 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001924 struct session *s;
1925 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001926 int cfd;
1927 int one = 1;
1928
willy tarreau5cbea6f2005-12-17 12:48:26 +01001929 while (p->nbconn < p->maxconn) {
1930 struct sockaddr_in addr;
1931 int laddr = sizeof(addr);
1932 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1933 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001934
willy tarreau5cbea6f2005-12-17 12:48:26 +01001935 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1936 Alert("out of memory in event_accept().\n");
1937 FD_CLR(fd, StaticReadEvent);
1938 p->state = PR_STIDLE;
1939 close(cfd);
1940 return 0;
1941 }
willy tarreau0f7af912005-12-17 12:21:26 +01001942
willy tarreau5cbea6f2005-12-17 12:48:26 +01001943 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1944 Alert("out of memory in event_accept().\n");
1945 FD_CLR(fd, StaticReadEvent);
1946 p->state = PR_STIDLE;
1947 close(cfd);
1948 pool_free(session, s);
1949 return 0;
1950 }
willy tarreau0f7af912005-12-17 12:21:26 +01001951
willy tarreau5cbea6f2005-12-17 12:48:26 +01001952 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001953 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001954 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1955 close(cfd);
1956 pool_free(task, t);
1957 pool_free(session, s);
1958 return 0;
1959 }
willy tarreau0f7af912005-12-17 12:21:26 +01001960
willy tarreau5cbea6f2005-12-17 12:48:26 +01001961 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1962 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1963 (char *) &one, sizeof(one)) == -1)) {
1964 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1965 close(cfd);
1966 pool_free(task, t);
1967 pool_free(session, s);
1968 return 0;
1969 }
willy tarreau0f7af912005-12-17 12:21:26 +01001970
willy tarreau9fe663a2005-12-17 13:02:59 +01001971 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1972 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1973 t->state = TASK_IDLE;
1974 t->process = process_session;
1975 t->context = s;
1976
1977 s->task = t;
1978 s->proxy = p;
1979 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1980 s->srv_state = SV_STIDLE;
1981 s->req = s->rep = NULL; /* will be allocated later */
1982 s->flags = 0;
1983 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1984 s->cli_fd = cfd;
1985 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01001986 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01001987 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01001988
1989 s->logs.logwait = p->to_log;
1990 s->logs.tv_accept = now;
1991 s->logs.t_request = -1;
1992 s->logs.t_connect = -1;
1993 s->logs.t_data = -1;
1994 s->logs.t_close = 0;
1995 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01001996 s->logs.cli_cookie = NULL;
1997 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01001998 s->logs.status = -1;
1999 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002000
willy tarreau2f6ba652005-12-17 13:57:42 +01002001 s->uniq_id = totalconn;
2002
willy tarreau5cbea6f2005-12-17 12:48:26 +01002003 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2004 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01002005 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002006 unsigned char *pn, *sn;
2007 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002008
willy tarreau5cbea6f2005-12-17 12:48:26 +01002009 namelen = sizeof(sockname);
2010 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2011 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
2012 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01002013 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01002014
willy tarreau9fe663a2005-12-17 13:02:59 +01002015 if (p->to_log) {
2016 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002017 if (s->logs.logwait & LW_CLIP)
2018 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002019 sess_log(s);
2020 }
2021 else
2022 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
2023 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
2024 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
2025 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01002026 }
willy tarreau0f7af912005-12-17 12:21:26 +01002027
willy tarreau9fe663a2005-12-17 13:02:59 +01002028 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002029 struct sockaddr_in sockname;
2030 unsigned char *pn, *sn;
2031 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002032 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002033
2034 namelen = sizeof(sockname);
2035 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2036 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
2037 sn = (unsigned char *)&sockname.sin_addr;
2038 pn = (unsigned char *)&s->cli_addr.sin_addr;
2039
2040 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%d.%d.%d.%d:%d]\n",
2041 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2042 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port));
willy tarreauef900ab2005-12-17 12:52:52 +01002043 write(1, trash, len);
2044 }
willy tarreau0f7af912005-12-17 12:21:26 +01002045
willy tarreau5cbea6f2005-12-17 12:48:26 +01002046 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2047 close(cfd); /* nothing can be done for this fd without memory */
2048 pool_free(task, t);
2049 pool_free(session, s);
2050 return 0;
2051 }
2052 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002053 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002054 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2055 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002056 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002057 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002058
willy tarreau5cbea6f2005-12-17 12:48:26 +01002059 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2060 pool_free(buffer, s->req);
2061 close(cfd); /* nothing can be done for this fd without memory */
2062 pool_free(task, t);
2063 pool_free(session, s);
2064 return 0;
2065 }
2066 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002067 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002068 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 +01002069
willy tarreau5cbea6f2005-12-17 12:48:26 +01002070 fdtab[cfd].read = &event_cli_read;
2071 fdtab[cfd].write = &event_cli_write;
2072 fdtab[cfd].owner = t;
2073 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002074
willy tarreau5cbea6f2005-12-17 12:48:26 +01002075 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01002076 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002077 }
2078 else {
2079 FD_SET(cfd, StaticReadEvent);
2080 }
2081
2082 fd_insert(cfd);
2083
2084 tv_eternity(&s->cnexpire);
2085 tv_eternity(&s->srexpire);
2086 tv_eternity(&s->swexpire);
2087 tv_eternity(&s->cwexpire);
2088
2089 if (s->proxy->clitimeout)
2090 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2091 else
2092 tv_eternity(&s->crexpire);
2093
2094 t->expire = s->crexpire;
2095
2096 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002097
2098 if (p->mode != PR_MODE_HEALTH)
2099 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002100
2101 p->nbconn++;
2102 actconn++;
2103 totalconn++;
2104
2105 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2106 } /* end of while (p->nbconn < p->maxconn) */
2107 return 0;
2108}
willy tarreau0f7af912005-12-17 12:21:26 +01002109
willy tarreau0f7af912005-12-17 12:21:26 +01002110
willy tarreau5cbea6f2005-12-17 12:48:26 +01002111/*
2112 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002113 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2114 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002115 * or -1 if an error occured.
2116 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002117int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002118 struct task *t = fdtab[fd].owner;
2119 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002120
willy tarreau5cbea6f2005-12-17 12:48:26 +01002121 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002122 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002123 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2124 if (skerr)
2125 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002126 else {
2127 if (s->proxy->options & PR_O_HTTP_CHK) {
2128 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002129 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002130 * so we'll send the request, and won't wake the checker up now.
2131 */
2132#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002133 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002134#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002135 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002136#endif
2137 if (ret == 22) {
2138 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2139 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2140 return 0;
2141 }
2142 else
2143 s->result = -1;
2144 }
2145 else {
2146 /* good TCP connection is enough */
2147 s->result = 1;
2148 }
2149 }
2150
2151 task_wakeup(&rq, t);
2152 return 0;
2153}
2154
willy tarreau0f7af912005-12-17 12:21:26 +01002155
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002156/*
2157 * This function is used only for server health-checks. It handles
2158 * the server's reply to an HTTP request. It returns 1 if the server replies
2159 * 2xx or 3xx (valid responses), or -1 in other cases.
2160 */
2161int event_srv_chk_r(int fd) {
2162 char reply[64];
2163 int len;
2164 struct task *t = fdtab[fd].owner;
2165 struct server *s = t->context;
2166
2167 int skerr, lskerr;
2168 lskerr = sizeof(skerr);
2169 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2170 s->result = -1;
2171 if (!skerr) {
2172#ifndef MSG_NOSIGNAL
2173 len = recv(fd, reply, sizeof(reply), 0);
2174#else
2175 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
2176#endif
2177 if ((len >= sizeof("HTTP/1.0 000")) &&
2178 !memcmp(reply, "HTTP/1.", 7) &&
2179 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2180 s->result = 1;
2181 }
2182
2183 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002184 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002185 return 0;
2186}
2187
2188
2189/*
2190 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2191 * and moves <end> just after the end of <str>.
2192 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2193 * the shift value (positive or negative) is returned.
2194 * If there's no space left, the move is not done.
2195 *
2196 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002197int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002198 int delta;
2199 int len;
2200
2201 len = strlen(str);
2202 delta = len - (end - pos);
2203
2204 if (delta + b->r >= b->data + BUFSIZE)
2205 return 0; /* no space left */
2206
2207 /* first, protect the end of the buffer */
2208 memmove(end + delta, end, b->data + b->l - end);
2209
2210 /* now, copy str over pos */
2211 memcpy(pos, str,len);
2212
willy tarreau5cbea6f2005-12-17 12:48:26 +01002213 /* we only move data after the displaced zone */
2214 if (b->r > pos) b->r += delta;
2215 if (b->w > pos) b->w += delta;
2216 if (b->h > pos) b->h += delta;
2217 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002218 b->l += delta;
2219
2220 return delta;
2221}
2222
willy tarreau8337c6b2005-12-17 13:41:01 +01002223/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002224 * len is 0.
2225 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002226int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002227 int delta;
2228
2229 delta = len - (end - pos);
2230
2231 if (delta + b->r >= b->data + BUFSIZE)
2232 return 0; /* no space left */
2233
2234 /* first, protect the end of the buffer */
2235 memmove(end + delta, end, b->data + b->l - end);
2236
2237 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002238 if (len)
2239 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002240
willy tarreau5cbea6f2005-12-17 12:48:26 +01002241 /* we only move data after the displaced zone */
2242 if (b->r > pos) b->r += delta;
2243 if (b->w > pos) b->w += delta;
2244 if (b->h > pos) b->h += delta;
2245 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002246 b->l += delta;
2247
2248 return delta;
2249}
2250
2251
2252int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2253 char *old_dst = dst;
2254
2255 while (*str) {
2256 if (*str == '\\') {
2257 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002258 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002259 int len, num;
2260
2261 num = *str - '0';
2262 str++;
2263
2264 if (matches[num].rm_so > -1) {
2265 len = matches[num].rm_eo - matches[num].rm_so;
2266 memcpy(dst, src + matches[num].rm_so, len);
2267 dst += len;
2268 }
2269
2270 }
2271 else if (*str == 'x') {
2272 unsigned char hex1, hex2;
2273 str++;
2274
2275 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2276
2277 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2278 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2279 *dst++ = (hex1<<4) + hex2;
2280 }
2281 else
2282 *dst++ = *str++;
2283 }
2284 else
2285 *dst++ = *str++;
2286 }
2287 *dst = 0;
2288 return dst - old_dst;
2289}
2290
willy tarreau9fe663a2005-12-17 13:02:59 +01002291
willy tarreau0f7af912005-12-17 12:21:26 +01002292/*
2293 * manages the client FSM and its socket. BTW, it also tries to handle the
2294 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2295 * 0 else.
2296 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002297int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002298 int s = t->srv_state;
2299 int c = t->cli_state;
2300 struct buffer *req = t->req;
2301 struct buffer *rep = t->rep;
2302
willy tarreau750a4722005-12-17 13:21:24 +01002303#ifdef DEBUG_FULL
2304 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2305#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002306 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2307 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2308 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2309 //);
2310 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002311 /* now parse the partial (or complete) headers */
2312 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2313 char *ptr;
2314 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002315
willy tarreau5cbea6f2005-12-17 12:48:26 +01002316 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002317
willy tarreau0f7af912005-12-17 12:21:26 +01002318 /* look for the end of the current header */
2319 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2320 ptr++;
2321
willy tarreau5cbea6f2005-12-17 12:48:26 +01002322 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002323 int line, len;
2324 /* we can only get here after an end of headers */
2325 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002326
willy tarreaue39cd132005-12-17 13:00:18 +01002327 if (t->flags & SN_CLDENY) {
2328 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002329 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002330 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002331 if (!(t->flags & SN_ERR_MASK))
2332 t->flags |= SN_ERR_PRXCOND;
2333 if (!(t->flags & SN_FINST_MASK))
2334 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002335 return 1;
2336 }
2337
willy tarreau5cbea6f2005-12-17 12:48:26 +01002338 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002339 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2340 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002341 }
willy tarreau0f7af912005-12-17 12:21:26 +01002342
willy tarreau9fe663a2005-12-17 13:02:59 +01002343 if (t->proxy->options & PR_O_FWDFOR) {
2344 /* insert an X-Forwarded-For header */
2345 unsigned char *pn;
2346 pn = (unsigned char *)&t->cli_addr.sin_addr;
willy tarreau750a4722005-12-17 13:21:24 +01002347 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01002348 pn[0], pn[1], pn[2], pn[3]);
willy tarreau750a4722005-12-17 13:21:24 +01002349 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau9fe663a2005-12-17 13:02:59 +01002350 }
2351
willy tarreaucd878942005-12-17 13:27:43 +01002352 if (!memcmp(req->data, "POST ", 5))
2353 t->flags |= SN_POST; /* this is a POST request */
2354
willy tarreau5cbea6f2005-12-17 12:48:26 +01002355 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002356 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002357
willy tarreau750a4722005-12-17 13:21:24 +01002358 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002359 /* FIXME: we'll set the client in a wait state while we try to
2360 * connect to the server. Is this really needed ? wouldn't it be
2361 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002362 //FD_CLR(t->cli_fd, StaticReadEvent);
2363 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002364 break;
2365 }
willy tarreau0f7af912005-12-17 12:21:26 +01002366
willy tarreau5cbea6f2005-12-17 12:48:26 +01002367 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2368 if (ptr > req->r - 2) {
2369 /* this is a partial header, let's wait for more to come */
2370 req->lr = ptr;
2371 break;
2372 }
willy tarreau0f7af912005-12-17 12:21:26 +01002373
willy tarreau5cbea6f2005-12-17 12:48:26 +01002374 /* now we know that *ptr is either \r or \n,
2375 * and that there are at least 1 char after it.
2376 */
2377 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2378 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2379 else
2380 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002381
willy tarreau5cbea6f2005-12-17 12:48:26 +01002382 /*
2383 * now we know that we have a full header ; we can do whatever
2384 * we want with these pointers :
2385 * req->h = beginning of header
2386 * ptr = end of header (first \r or \n)
2387 * req->lr = beginning of next line (next rep->h)
2388 * req->r = end of data (not used at this stage)
2389 */
willy tarreau0f7af912005-12-17 12:21:26 +01002390
willy tarreau8337c6b2005-12-17 13:41:01 +01002391 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002392 /* we have a complete HTTP request that we must log */
2393 int urilen;
2394
willy tarreaua1598082005-12-17 13:08:06 +01002395 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002396 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002397 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002398 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002399 if (!(t->flags & SN_ERR_MASK))
2400 t->flags |= SN_ERR_PRXCOND;
2401 if (!(t->flags & SN_FINST_MASK))
2402 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002403 return 1;
2404 }
2405
2406 urilen = ptr - req->h;
2407 if (urilen >= REQURI_LEN)
2408 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002409 memcpy(t->logs.uri, req->h, urilen);
2410 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002411
willy tarreaua1598082005-12-17 13:08:06 +01002412 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002413 sess_log(t);
2414 }
2415
willy tarreau5cbea6f2005-12-17 12:48:26 +01002416 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002417
willy tarreau9fe663a2005-12-17 13:02:59 +01002418 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002419 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002420 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 +01002421 max = ptr - req->h;
2422 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002423 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002424 trash[len++] = '\n';
2425 write(1, trash, len);
2426 }
willy tarreau0f7af912005-12-17 12:21:26 +01002427
willy tarreau5cbea6f2005-12-17 12:48:26 +01002428 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002429 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2430 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002431 char term;
2432
2433 term = *ptr;
2434 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002435 exp = t->proxy->req_exp;
2436 do {
2437 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2438 switch (exp->action) {
2439 case ACT_ALLOW:
2440 if (!(t->flags & SN_CLDENY))
2441 t->flags |= SN_CLALLOW;
2442 break;
2443 case ACT_REPLACE:
2444 if (!(t->flags & SN_CLDENY)) {
2445 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2446 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2447 }
2448 break;
2449 case ACT_REMOVE:
2450 if (!(t->flags & SN_CLDENY))
2451 delete_header = 1;
2452 break;
2453 case ACT_DENY:
2454 if (!(t->flags & SN_CLALLOW))
2455 t->flags |= SN_CLDENY;
2456 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002457 case ACT_PASS: /* we simply don't deny this one */
2458 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002459 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002460 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002461 }
willy tarreaue39cd132005-12-17 13:00:18 +01002462 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002463 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002464 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002465
willy tarreau240afa62005-12-17 13:14:35 +01002466 /* Now look for cookies. Conforming to RFC2109, we have to support
2467 * attributes whose name begin with a '$', and associate them with
2468 * the right cookie, if we want to delete this cookie.
2469 * So there are 3 cases for each cookie read :
2470 * 1) it's a special attribute, beginning with a '$' : ignore it.
2471 * 2) it's a server id cookie that we *MAY* want to delete : save
2472 * some pointers on it (last semi-colon, beginning of cookie...)
2473 * 3) it's an application cookie : we *MAY* have to delete a previous
2474 * "special" cookie.
2475 * At the end of loop, if a "special" cookie remains, we may have to
2476 * remove it. If no application cookie persists in the header, we
2477 * *MUST* delete it
2478 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002479 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002480 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01002481 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002482 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002483 char *del_colon, *del_cookie, *colon;
2484 int app_cookies;
2485
willy tarreau5cbea6f2005-12-17 12:48:26 +01002486 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002487 colon = p1;
2488 /* del_cookie == NULL => nothing to be deleted */
2489 del_colon = del_cookie = NULL;
2490 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002491
2492 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002493 /* skip spaces and colons, but keep an eye on these ones */
2494 while (p1 < ptr) {
2495 if (*p1 == ';' || *p1 == ',')
2496 colon = p1;
2497 else if (!isspace((int)*p1))
2498 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002499 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002500 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002501
2502 if (p1 == ptr)
2503 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002504
2505 /* p1 is at the beginning of the cookie name */
2506 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002507 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002508 p2++;
2509
2510 if (p2 == ptr)
2511 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002512
2513 p3 = p2 + 1; /* skips the '=' sign */
2514 if (p3 == ptr)
2515 break;
2516
willy tarreau240afa62005-12-17 13:14:35 +01002517 p4 = p3;
2518 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002519 p4++;
2520
2521 /* here, we have the cookie name between p1 and p2,
2522 * and its value between p3 and p4.
2523 * we can process it.
2524 */
2525
willy tarreau240afa62005-12-17 13:14:35 +01002526 if (*p1 == '$') {
2527 /* skip this one */
2528 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002529 else {
2530 /* first, let's see if we want to capture it */
2531 if (t->proxy->capture_name != NULL &&
2532 t->logs.cli_cookie == NULL &&
2533 (p4 - p1 >= t->proxy->capture_namelen) &&
2534 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2535 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002536
willy tarreau8337c6b2005-12-17 13:41:01 +01002537 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2538 Alert("HTTP logging : out of memory.\n");
2539 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002540
willy tarreau8337c6b2005-12-17 13:41:01 +01002541 if (log_len > t->proxy->capture_len)
2542 log_len = t->proxy->capture_len;
2543 memcpy(t->logs.cli_cookie, p1, log_len);
2544 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002545 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002546
2547 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2548 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2549 /* Cool... it's the right one */
2550 struct server *srv = t->proxy->srv;
2551
2552 while (srv &&
2553 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2554 srv = srv->next;
2555 }
2556
willy tarreau036e1ce2005-12-17 13:46:33 +01002557 if (!srv) {
2558 t->flags &= ~SN_CK_MASK;
2559 t->flags |= SN_CK_INVALID;
2560 }
2561 else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002562 /* we found the server and it's usable */
willy tarreau036e1ce2005-12-17 13:46:33 +01002563 t->flags &= ~SN_CK_MASK;
2564 t->flags |= SN_CK_VALID | SN_DIRECT;
willy tarreau8337c6b2005-12-17 13:41:01 +01002565 t->srv = srv;
2566 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002567 else {
2568 t->flags &= ~SN_CK_MASK;
2569 t->flags |= SN_CK_DOWN;
2570 }
2571
willy tarreau8337c6b2005-12-17 13:41:01 +01002572 /* if this cookie was set in insert+indirect mode, then it's better that the
2573 * server never sees it.
2574 */
2575 if (del_cookie == NULL &&
2576 (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 +01002577 del_cookie = p1;
2578 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002579 }
willy tarreau240afa62005-12-17 13:14:35 +01002580 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002581 else {
2582 /* now we know that we must keep this cookie since it's
2583 * not ours. But if we wanted to delete our cookie
2584 * earlier, we cannot remove the complete header, but we
2585 * can remove the previous block itself.
2586 */
2587 app_cookies++;
2588
2589 if (del_cookie != NULL) {
2590 buffer_replace2(req, del_cookie, p1, NULL, 0);
2591 p4 -= (p1 - del_cookie);
2592 ptr -= (p1 - del_cookie);
2593 del_cookie = del_colon = NULL;
2594 }
willy tarreau240afa62005-12-17 13:14:35 +01002595 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002596 }
willy tarreau240afa62005-12-17 13:14:35 +01002597
willy tarreau5cbea6f2005-12-17 12:48:26 +01002598 /* we'll have to look for another cookie ... */
2599 p1 = p4;
2600 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002601
2602 /* There's no more cookie on this line.
2603 * We may have marked the last one(s) for deletion.
2604 * We must do this now in two ways :
2605 * - if there is no app cookie, we simply delete the header ;
2606 * - if there are app cookies, we must delete the end of the
2607 * string properly, including the colon/semi-colon before
2608 * the cookie name.
2609 */
2610 if (del_cookie != NULL) {
2611 if (app_cookies) {
2612 buffer_replace2(req, del_colon, ptr, NULL, 0);
2613 /* WARNING! <ptr> becomes invalid for now. If some code
2614 * below needs to rely on it before the end of the global
2615 * header loop, we need to correct it with this code :
2616 * ptr = del_colon;
2617 */
2618 }
2619 else
2620 delete_header = 1;
2621 }
2622 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002623
2624 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002625 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002626 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002627 }
willy tarreau240afa62005-12-17 13:14:35 +01002628 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2629
willy tarreau5cbea6f2005-12-17 12:48:26 +01002630 req->h = req->lr;
2631 } /* while (req->lr < req->r) */
2632
2633 /* end of header processing (even if incomplete) */
2634
willy tarreauef900ab2005-12-17 12:52:52 +01002635 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2636 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2637 * full. We cannot loop here since event_cli_read will disable it only if
2638 * req->l == rlim-data
2639 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640 FD_SET(t->cli_fd, StaticReadEvent);
2641 if (t->proxy->clitimeout)
2642 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2643 else
2644 tv_eternity(&t->crexpire);
2645 }
2646
willy tarreaue39cd132005-12-17 13:00:18 +01002647 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002648 * won't be able to free more later, so the session will never terminate.
2649 */
willy tarreaue39cd132005-12-17 13:00:18 +01002650 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002651 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01002652 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01002653 if (!(t->flags & SN_ERR_MASK))
2654 t->flags |= SN_ERR_PRXCOND;
2655 if (!(t->flags & SN_FINST_MASK))
2656 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002657 return 1;
2658 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002659 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002660 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002661 tv_eternity(&t->crexpire);
2662 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002663 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002664 if (!(t->flags & SN_ERR_MASK))
2665 t->flags |= SN_ERR_CLICL;
2666 if (!(t->flags & SN_FINST_MASK))
2667 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002668 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002669 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002670 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2671
2672 /* read timeout : give up with an error message.
2673 */
2674 t->logs.status = 408;
2675 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01002676 if (!(t->flags & SN_ERR_MASK))
2677 t->flags |= SN_ERR_CLITO;
2678 if (!(t->flags & SN_FINST_MASK))
2679 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01002680 return 1;
2681 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002682
2683 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002684 }
2685 else if (c == CL_STDATA) {
2686 /* read or write error */
2687 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002688 tv_eternity(&t->crexpire);
2689 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002690 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002691 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002692 if (!(t->flags & SN_ERR_MASK))
2693 t->flags |= SN_ERR_CLICL;
2694 if (!(t->flags & SN_FINST_MASK))
2695 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002696 return 1;
2697 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002698 /* last read, or end of server write */
2699 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002700 FD_CLR(t->cli_fd, StaticReadEvent);
2701 // if (req->l == 0) /* nothing to write on the server side */
2702 // FD_CLR(t->srv_fd, StaticWriteEvent);
2703 tv_eternity(&t->crexpire);
2704 shutdown(t->cli_fd, SHUT_RD);
2705 t->cli_state = CL_STSHUTR;
2706 return 1;
2707 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002708 /* last server read and buffer empty */
2709 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002710 FD_CLR(t->cli_fd, StaticWriteEvent);
2711 tv_eternity(&t->cwexpire);
2712 shutdown(t->cli_fd, SHUT_WR);
2713 t->cli_state = CL_STSHUTW;
2714 return 1;
2715 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002716 /* read timeout */
2717 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2718 FD_CLR(t->cli_fd, StaticReadEvent);
2719 // if (req->l == 0) /* nothing to write on the server side */
2720 // FD_CLR(t->srv_fd, StaticWriteEvent);
2721 tv_eternity(&t->crexpire);
2722 shutdown(t->cli_fd, SHUT_RD);
2723 t->cli_state = CL_STSHUTR;
2724 if (!(t->flags & SN_ERR_MASK))
2725 t->flags |= SN_ERR_CLITO;
2726 if (!(t->flags & SN_FINST_MASK))
2727 t->flags |= SN_FINST_D;
2728 return 1;
2729 }
2730 /* write timeout */
2731 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2732 FD_CLR(t->cli_fd, StaticWriteEvent);
2733 tv_eternity(&t->cwexpire);
2734 shutdown(t->cli_fd, SHUT_WR);
2735 t->cli_state = CL_STSHUTW;
2736 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01002737 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01002738 if (!(t->flags & SN_FINST_MASK))
2739 t->flags |= SN_FINST_D;
2740 return 1;
2741 }
willy tarreau0f7af912005-12-17 12:21:26 +01002742
willy tarreauef900ab2005-12-17 12:52:52 +01002743 if (req->l >= req->rlim - req->data) {
2744 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002745 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002746 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002747 FD_CLR(t->cli_fd, StaticReadEvent);
2748 tv_eternity(&t->crexpire);
2749 }
2750 }
2751 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002752 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002753 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2754 FD_SET(t->cli_fd, StaticReadEvent);
2755 if (t->proxy->clitimeout)
2756 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2757 else
2758 tv_eternity(&t->crexpire);
2759 }
2760 }
2761
2762 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002763 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002764 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2765 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2766 tv_eternity(&t->cwexpire);
2767 }
2768 }
2769 else { /* buffer not empty */
2770 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2771 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002772 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002773 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002774 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2775 t->crexpire = t->cwexpire;
2776 }
willy tarreau0f7af912005-12-17 12:21:26 +01002777 else
2778 tv_eternity(&t->cwexpire);
2779 }
2780 }
2781 return 0; /* other cases change nothing */
2782 }
2783 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002784 if (t->res_cw == RES_ERROR) {
2785 tv_eternity(&t->cwexpire);
2786 fd_delete(t->cli_fd);
2787 t->cli_state = CL_STCLOSE;
2788 if (!(t->flags & SN_ERR_MASK))
2789 t->flags |= SN_ERR_CLICL;
2790 if (!(t->flags & SN_FINST_MASK))
2791 t->flags |= SN_FINST_D;
2792 return 1;
2793 }
2794 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002795 tv_eternity(&t->cwexpire);
2796 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002797 t->cli_state = CL_STCLOSE;
2798 return 1;
2799 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002800 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2801 tv_eternity(&t->cwexpire);
2802 fd_delete(t->cli_fd);
2803 t->cli_state = CL_STCLOSE;
2804 if (!(t->flags & SN_ERR_MASK))
2805 t->flags |= SN_ERR_CLITO;
2806 if (!(t->flags & SN_FINST_MASK))
2807 t->flags |= SN_FINST_D;
2808 return 1;
2809 }
willy tarreau0f7af912005-12-17 12:21:26 +01002810 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002811 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002812 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2813 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2814 tv_eternity(&t->cwexpire);
2815 }
2816 }
2817 else { /* buffer not empty */
2818 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2819 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002820 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002821 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002822 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2823 t->crexpire = t->cwexpire;
2824 }
willy tarreau0f7af912005-12-17 12:21:26 +01002825 else
2826 tv_eternity(&t->cwexpire);
2827 }
2828 }
2829 return 0;
2830 }
2831 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002832 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002833 tv_eternity(&t->crexpire);
2834 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002835 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002836 if (!(t->flags & SN_ERR_MASK))
2837 t->flags |= SN_ERR_CLICL;
2838 if (!(t->flags & SN_FINST_MASK))
2839 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002840 return 1;
2841 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002842 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
2843 tv_eternity(&t->crexpire);
2844 fd_delete(t->cli_fd);
2845 t->cli_state = CL_STCLOSE;
2846 return 1;
2847 }
2848 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2849 tv_eternity(&t->crexpire);
2850 fd_delete(t->cli_fd);
2851 t->cli_state = CL_STCLOSE;
2852 if (!(t->flags & SN_ERR_MASK))
2853 t->flags |= SN_ERR_CLITO;
2854 if (!(t->flags & SN_FINST_MASK))
2855 t->flags |= SN_FINST_D;
2856 return 1;
2857 }
willy tarreauef900ab2005-12-17 12:52:52 +01002858 else 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);
2870 if (t->proxy->clitimeout)
2871 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2872 else
2873 tv_eternity(&t->crexpire);
2874 }
2875 }
2876 return 0;
2877 }
2878 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002879 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002880 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002881 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 +01002882 write(1, trash, len);
2883 }
2884 return 0;
2885 }
2886 return 0;
2887}
2888
2889
2890/*
2891 * manages the server FSM and its socket. It returns 1 if a state has changed
2892 * (and a resync may be needed), 0 else.
2893 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002894int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002895 int s = t->srv_state;
2896 int c = t->cli_state;
2897 struct buffer *req = t->req;
2898 struct buffer *rep = t->rep;
2899
willy tarreau750a4722005-12-17 13:21:24 +01002900#ifdef DEBUG_FULL
2901 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2902#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002903 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2904 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2905 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2906 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002907 if (s == SV_STIDLE) {
2908 if (c == CL_STHEADERS)
2909 return 0; /* stay in idle, waiting for data to reach the client side */
2910 else if (c == CL_STCLOSE ||
2911 c == CL_STSHUTW ||
2912 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2913 tv_eternity(&t->cnexpire);
2914 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002915 if (!(t->flags & SN_ERR_MASK))
2916 t->flags |= SN_ERR_CLICL;
2917 if (!(t->flags & SN_FINST_MASK))
2918 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01002919 return 1;
2920 }
2921 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002922 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002923 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2924 t->srv_state = SV_STCONN;
2925 }
2926 else { /* try again */
2927 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002928 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002929 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002930 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01002931 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
2932 t->flags &= ~SN_CK_MASK;
2933 t->flags |= SN_CK_DOWN;
2934 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002935 }
2936
2937 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002938 t->srv_state = SV_STCONN;
2939 break;
2940 }
2941 }
2942 if (t->conn_retries < 0) {
2943 /* if conn_retries < 0 or other error, let's abort */
2944 tv_eternity(&t->cnexpire);
2945 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01002946 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01002947 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01002948 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01002949 if (!(t->flags & SN_ERR_MASK))
2950 t->flags |= SN_ERR_SRVCL;
2951 if (!(t->flags & SN_FINST_MASK))
2952 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01002953 }
2954 }
2955 return 1;
2956 }
2957 }
2958 else if (s == SV_STCONN) { /* connection in progress */
2959 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2960 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2961 return 0; /* nothing changed */
2962 }
2963 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2964 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2965 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002966 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002967 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002968 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002969 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002970 if (t->conn_retries >= 0) {
2971 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002972 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002973 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01002974 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
2975 t->flags &= ~SN_CK_MASK;
2976 t->flags |= SN_CK_DOWN;
2977 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002978 }
2979 if (connect_server(t) == 0)
2980 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002981 }
2982 /* if conn_retries < 0 or other error, let's abort */
2983 tv_eternity(&t->cnexpire);
2984 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01002985 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01002986 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01002987 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01002988 if (!(t->flags & SN_ERR_MASK))
2989 t->flags |= SN_ERR_SRVCL;
2990 if (!(t->flags & SN_FINST_MASK))
2991 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01002992 return 1;
2993 }
2994 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01002995 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01002996
willy tarreau0f7af912005-12-17 12:21:26 +01002997 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002998 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01002999 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003000 tv_eternity(&t->swexpire);
3001 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003002 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003003 if (t->proxy->srvtimeout) {
3004 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3005 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3006 t->srexpire = t->swexpire;
3007 }
3008 else
3009 tv_eternity(&t->swexpire);
3010 }
willy tarreau0f7af912005-12-17 12:21:26 +01003011
3012 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3013 FD_SET(t->srv_fd, StaticReadEvent);
3014 if (t->proxy->srvtimeout)
3015 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3016 else
3017 tv_eternity(&t->srexpire);
3018
3019 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003020 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003021 }
willy tarreauef900ab2005-12-17 12:52:52 +01003022 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003023 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003024 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3025 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003026 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003027 return 1;
3028 }
3029 }
3030 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003031 /* now parse the partial (or complete) headers */
3032 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3033 char *ptr;
3034 int delete_header;
3035
3036 ptr = rep->lr;
3037
3038 /* look for the end of the current header */
3039 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3040 ptr++;
3041
3042 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003043 int line, len;
3044
3045 /* we can only get here after an end of headers */
3046 /* we'll have something else to do here : add new headers ... */
3047
willy tarreaucd878942005-12-17 13:27:43 +01003048 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3049 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003050 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003051 * insert a set-cookie here, except if we want to insert only on POST
3052 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003053 */
willy tarreau750a4722005-12-17 13:21:24 +01003054 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003055 t->proxy->cookie_name,
3056 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003057
willy tarreau036e1ce2005-12-17 13:46:33 +01003058 t->flags |= SN_SCK_INSERTED;
3059
willy tarreau750a4722005-12-17 13:21:24 +01003060 /* Here, we will tell an eventual cache on the client side that we don't
3061 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3062 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3063 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3064 */
willy tarreau240afa62005-12-17 13:14:35 +01003065 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003066 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3067 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003068
willy tarreau750a4722005-12-17 13:21:24 +01003069 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003070 }
3071
3072 /* headers to be added */
3073 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003074 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3075 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003076 }
3077
3078 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003079 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003080 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003081 break;
3082 }
3083
3084 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3085 if (ptr > rep->r - 2) {
3086 /* this is a partial header, let's wait for more to come */
3087 rep->lr = ptr;
3088 break;
3089 }
3090
3091 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3092 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3093
3094 /* now we know that *ptr is either \r or \n,
3095 * and that there are at least 1 char after it.
3096 */
3097 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3098 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3099 else
3100 rep->lr = ptr + 2; /* \r\n or \n\r */
3101
3102 /*
3103 * now we know that we have a full header ; we can do whatever
3104 * we want with these pointers :
3105 * rep->h = beginning of header
3106 * ptr = end of header (first \r or \n)
3107 * rep->lr = beginning of next line (next rep->h)
3108 * rep->r = end of data (not used at this stage)
3109 */
3110
willy tarreaua1598082005-12-17 13:08:06 +01003111
3112 if (t->logs.logwait & LW_RESP) {
3113 t->logs.logwait &= ~LW_RESP;
3114 t->logs.status = atoi(rep->h + 9);
3115 }
3116
willy tarreau5cbea6f2005-12-17 12:48:26 +01003117 delete_header = 0;
3118
willy tarreau9fe663a2005-12-17 13:02:59 +01003119 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003120 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003121 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 +01003122 max = ptr - rep->h;
3123 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003124 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003125 trash[len++] = '\n';
3126 write(1, trash, len);
3127 }
3128
3129 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01003130 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
3131 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003132 char term;
3133
3134 term = *ptr;
3135 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003136 exp = t->proxy->rsp_exp;
3137 do {
3138 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3139 switch (exp->action) {
3140 case ACT_ALLOW:
3141 if (!(t->flags & SN_SVDENY))
3142 t->flags |= SN_SVALLOW;
3143 break;
3144 case ACT_REPLACE:
3145 if (!(t->flags & SN_SVDENY)) {
3146 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3147 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3148 }
3149 break;
3150 case ACT_REMOVE:
3151 if (!(t->flags & SN_SVDENY))
3152 delete_header = 1;
3153 break;
3154 case ACT_DENY:
3155 if (!(t->flags & SN_SVALLOW))
3156 t->flags |= SN_SVDENY;
3157 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003158 case ACT_PASS: /* we simply don't deny this one */
3159 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003160 }
3161 break;
3162 }
willy tarreaue39cd132005-12-17 13:00:18 +01003163 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003164 *ptr = term; /* restore the string terminator */
3165 }
3166
3167 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003168 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3169 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
3170 && (ptr >= rep->h + 12)
willy tarreau906b2682005-12-17 13:49:52 +01003171 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003172 char *p1, *p2, *p3, *p4;
3173
3174 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3175
3176 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003177 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003178 p1++;
3179
3180 if (p1 == ptr || *p1 == ';') /* end of cookie */
3181 break;
3182
3183 /* p1 is at the beginning of the cookie name */
3184 p2 = p1;
3185
3186 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3187 p2++;
3188
3189 if (p2 == ptr || *p2 == ';') /* next cookie */
3190 break;
3191
3192 p3 = p2 + 1; /* skips the '=' sign */
3193 if (p3 == ptr)
3194 break;
3195
3196 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003197 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003198 p4++;
3199
3200 /* here, we have the cookie name between p1 and p2,
3201 * and its value between p3 and p4.
3202 * we can process it.
3203 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003204
3205 /* first, let's see if we want to capture it */
3206 if (t->proxy->capture_name != NULL &&
3207 t->logs.srv_cookie == NULL &&
3208 (p4 - p1 >= t->proxy->capture_namelen) &&
3209 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3210 int log_len = p4 - p1;
3211
3212 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3213 Alert("HTTP logging : out of memory.\n");
3214 }
3215
3216 if (log_len > t->proxy->capture_len)
3217 log_len = t->proxy->capture_len;
3218 memcpy(t->logs.srv_cookie, p1, log_len);
3219 t->logs.srv_cookie[log_len] = 0;
3220 }
3221
3222 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3223 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003224 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003225 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003226
3227 /* If the cookie is in insert mode on a known server, we'll delete
3228 * this occurrence because we'll insert another one later.
3229 * We'll delete it too if the "indirect" option is set and we're in
3230 * a direct access. */
3231 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003232 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003233 /* this header must be deleted */
3234 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003235 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003236 }
3237 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3238 /* replace bytes p3->p4 with the cookie name associated
3239 * with this server since we know it.
3240 */
3241 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003242 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003243 }
3244 break;
3245 }
3246 else {
3247 // fprintf(stderr,"Ignoring unknown cookie : ");
3248 // write(2, p1, p2-p1);
3249 // fprintf(stderr," = ");
3250 // write(2, p3, p4-p3);
3251 // fprintf(stderr,"\n");
3252 }
3253 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3254 } /* we're now at the end of the cookie value */
3255 } /* end of cookie processing */
3256
3257 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003258 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003259 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003260
willy tarreau5cbea6f2005-12-17 12:48:26 +01003261 rep->h = rep->lr;
3262 } /* while (rep->lr < rep->r) */
3263
3264 /* end of header processing (even if incomplete) */
3265
willy tarreauef900ab2005-12-17 12:52:52 +01003266 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3267 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3268 * full. We cannot loop here since event_srv_read will disable it only if
3269 * rep->l == rlim-data
3270 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003271 FD_SET(t->srv_fd, StaticReadEvent);
3272 if (t->proxy->srvtimeout)
3273 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3274 else
3275 tv_eternity(&t->srexpire);
3276 }
willy tarreau0f7af912005-12-17 12:21:26 +01003277
willy tarreau8337c6b2005-12-17 13:41:01 +01003278 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003279 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003280 tv_eternity(&t->srexpire);
3281 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003282 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003283 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003284 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003285 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003286 if (!(t->flags & SN_ERR_MASK))
3287 t->flags |= SN_ERR_SRVCL;
3288 if (!(t->flags & SN_FINST_MASK))
3289 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003290 return 1;
3291 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003292 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003293 * since we are in header mode, if there's no space left for headers, we
3294 * won't be able to free more later, so the session will never terminate.
3295 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003296 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 +01003297 FD_CLR(t->srv_fd, StaticReadEvent);
3298 tv_eternity(&t->srexpire);
3299 shutdown(t->srv_fd, SHUT_RD);
3300 t->srv_state = SV_STSHUTR;
3301 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003302 }
3303 /* read timeout : return a 504 to the client.
3304 */
3305 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3306 tv_eternity(&t->srexpire);
3307 tv_eternity(&t->swexpire);
3308 fd_delete(t->srv_fd);
3309 t->srv_state = SV_STCLOSE;
3310 t->logs.status = 504;
3311 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003312 if (!(t->flags & SN_ERR_MASK))
3313 t->flags |= SN_ERR_SRVTO;
3314 if (!(t->flags & SN_FINST_MASK))
3315 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003316 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003317
3318 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003319 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003320 /* FIXME!!! here, we don't want to switch to SHUTW if the
3321 * client shuts read too early, because we may still have
3322 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01003323 * The side-effect is that if the client completely closes its
3324 * connection during SV_STHEADER, the connection to the server
3325 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01003326 */
willy tarreau036e1ce2005-12-17 13:46:33 +01003327 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003328 FD_CLR(t->srv_fd, StaticWriteEvent);
3329 tv_eternity(&t->swexpire);
3330 shutdown(t->srv_fd, SHUT_WR);
3331 t->srv_state = SV_STSHUTW;
3332 return 1;
3333 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003334 /* write timeout */
3335 /* FIXME!!! here, we don't want to switch to SHUTW if the
3336 * client shuts read too early, because we may still have
3337 * some work to do on the headers.
3338 */
3339 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3340 FD_CLR(t->srv_fd, StaticWriteEvent);
3341 tv_eternity(&t->swexpire);
3342 shutdown(t->srv_fd, SHUT_WR);
3343 t->srv_state = SV_STSHUTW;
3344 if (!(t->flags & SN_ERR_MASK))
3345 t->flags |= SN_ERR_SRVTO;
3346 if (!(t->flags & SN_FINST_MASK))
3347 t->flags |= SN_FINST_H;
3348 return 1;
3349 }
willy tarreau0f7af912005-12-17 12:21:26 +01003350
3351 if (req->l == 0) {
3352 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3353 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3354 tv_eternity(&t->swexpire);
3355 }
3356 }
3357 else { /* client buffer not empty */
3358 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3359 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003360 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003361 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003362 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3363 t->srexpire = t->swexpire;
3364 }
willy tarreau0f7af912005-12-17 12:21:26 +01003365 else
3366 tv_eternity(&t->swexpire);
3367 }
3368 }
3369
willy tarreau5cbea6f2005-12-17 12:48:26 +01003370 /* be nice with the client side which would like to send a complete header
3371 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3372 * would read all remaining data at once ! The client should not write past rep->lr
3373 * when the server is in header state.
3374 */
3375 //return header_processed;
3376 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003377 }
3378 else if (s == SV_STDATA) {
3379 /* read or write error */
3380 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003381 tv_eternity(&t->srexpire);
3382 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003383 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003384 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003385 if (!(t->flags & SN_ERR_MASK))
3386 t->flags |= SN_ERR_SRVCL;
3387 if (!(t->flags & SN_FINST_MASK))
3388 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003389 return 1;
3390 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003391 /* last read, or end of client write */
3392 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003393 FD_CLR(t->srv_fd, StaticReadEvent);
3394 tv_eternity(&t->srexpire);
3395 shutdown(t->srv_fd, SHUT_RD);
3396 t->srv_state = SV_STSHUTR;
3397 return 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003398 }
3399 /* read timeout */
3400 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3401 FD_CLR(t->srv_fd, StaticReadEvent);
3402 tv_eternity(&t->srexpire);
3403 shutdown(t->srv_fd, SHUT_RD);
3404 t->srv_state = SV_STSHUTR;
3405 if (!(t->flags & SN_ERR_MASK))
3406 t->flags |= SN_ERR_SRVTO;
3407 if (!(t->flags & SN_FINST_MASK))
3408 t->flags |= SN_FINST_D;
3409 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003410 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003411 /* write timeout */
3412 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003413 FD_CLR(t->srv_fd, StaticWriteEvent);
3414 tv_eternity(&t->swexpire);
3415 shutdown(t->srv_fd, SHUT_WR);
3416 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01003417 if (!(t->flags & SN_ERR_MASK))
3418 t->flags |= SN_ERR_SRVTO;
3419 if (!(t->flags & SN_FINST_MASK))
3420 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003421 return 1;
3422 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003423
3424 /* recompute request time-outs */
3425 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003426 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3427 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3428 tv_eternity(&t->swexpire);
3429 }
3430 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003431 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01003432 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3433 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003434 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003435 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003436 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3437 t->srexpire = t->swexpire;
3438 }
willy tarreau0f7af912005-12-17 12:21:26 +01003439 else
3440 tv_eternity(&t->swexpire);
3441 }
3442 }
3443
willy tarreaub1ff9db2005-12-17 13:51:03 +01003444 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01003445 if (rep->l == BUFSIZE) { /* no room to read more data */
3446 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3447 FD_CLR(t->srv_fd, StaticReadEvent);
3448 tv_eternity(&t->srexpire);
3449 }
3450 }
3451 else {
3452 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3453 FD_SET(t->srv_fd, StaticReadEvent);
3454 if (t->proxy->srvtimeout)
3455 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3456 else
3457 tv_eternity(&t->srexpire);
3458 }
3459 }
3460
3461 return 0; /* other cases change nothing */
3462 }
3463 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003464 if (t->res_sw == RES_ERROR) {
3465 //FD_CLR(t->srv_fd, StaticWriteEvent);
3466 tv_eternity(&t->swexpire);
3467 fd_delete(t->srv_fd);
3468 //close(t->srv_fd);
3469 t->srv_state = SV_STCLOSE;
3470 if (!(t->flags & SN_ERR_MASK))
3471 t->flags |= SN_ERR_SRVCL;
3472 if (!(t->flags & SN_FINST_MASK))
3473 t->flags |= SN_FINST_D;
3474 return 1;
3475 }
3476 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003477 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003478 tv_eternity(&t->swexpire);
3479 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003480 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003481 t->srv_state = SV_STCLOSE;
3482 return 1;
3483 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003484 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3485 //FD_CLR(t->srv_fd, StaticWriteEvent);
3486 tv_eternity(&t->swexpire);
3487 fd_delete(t->srv_fd);
3488 //close(t->srv_fd);
3489 t->srv_state = SV_STCLOSE;
3490 if (!(t->flags & SN_ERR_MASK))
3491 t->flags |= SN_ERR_SRVTO;
3492 if (!(t->flags & SN_FINST_MASK))
3493 t->flags |= SN_FINST_D;
3494 return 1;
3495 }
willy tarreau0f7af912005-12-17 12:21:26 +01003496 else if (req->l == 0) {
3497 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3498 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3499 tv_eternity(&t->swexpire);
3500 }
3501 }
3502 else { /* buffer not empty */
3503 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3504 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003505 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003506 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003507 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3508 t->srexpire = t->swexpire;
3509 }
willy tarreau0f7af912005-12-17 12:21:26 +01003510 else
3511 tv_eternity(&t->swexpire);
3512 }
3513 }
3514 return 0;
3515 }
3516 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003517 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003518 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003519 tv_eternity(&t->srexpire);
3520 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003521 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003522 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003523 if (!(t->flags & SN_ERR_MASK))
3524 t->flags |= SN_ERR_SRVCL;
3525 if (!(t->flags & SN_FINST_MASK))
3526 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003527 return 1;
3528 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003529 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
3530 //FD_CLR(t->srv_fd, StaticReadEvent);
3531 tv_eternity(&t->srexpire);
3532 fd_delete(t->srv_fd);
3533 //close(t->srv_fd);
3534 t->srv_state = SV_STCLOSE;
3535 return 1;
3536 }
3537 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3538 //FD_CLR(t->srv_fd, StaticReadEvent);
3539 tv_eternity(&t->srexpire);
3540 fd_delete(t->srv_fd);
3541 //close(t->srv_fd);
3542 t->srv_state = SV_STCLOSE;
3543 if (!(t->flags & SN_ERR_MASK))
3544 t->flags |= SN_ERR_SRVTO;
3545 if (!(t->flags & SN_FINST_MASK))
3546 t->flags |= SN_FINST_D;
3547 return 1;
3548 }
willy tarreau0f7af912005-12-17 12:21:26 +01003549 else if (rep->l == BUFSIZE) { /* no room to read more data */
3550 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3551 FD_CLR(t->srv_fd, StaticReadEvent);
3552 tv_eternity(&t->srexpire);
3553 }
3554 }
3555 else {
3556 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3557 FD_SET(t->srv_fd, StaticReadEvent);
3558 if (t->proxy->srvtimeout)
3559 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3560 else
3561 tv_eternity(&t->srexpire);
3562 }
3563 }
3564 return 0;
3565 }
3566 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003567 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003568 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003569 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 +01003570 write(1, trash, len);
3571 }
3572 return 0;
3573 }
3574 return 0;
3575}
3576
3577
willy tarreau5cbea6f2005-12-17 12:48:26 +01003578/* Processes the client and server jobs of a session task, then
3579 * puts it back to the wait queue in a clean state, or
3580 * cleans up its resources if it must be deleted. Returns
3581 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003582 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003583int process_session(struct task *t) {
3584 struct session *s = t->context;
3585 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003586
willy tarreau5cbea6f2005-12-17 12:48:26 +01003587 do {
3588 fsm_resync = 0;
3589 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3590 fsm_resync |= process_cli(s);
3591 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3592 fsm_resync |= process_srv(s);
3593 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3594 } while (fsm_resync);
3595
3596 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003597 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003598 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003599
willy tarreau5cbea6f2005-12-17 12:48:26 +01003600 tv_min(&min1, &s->crexpire, &s->cwexpire);
3601 tv_min(&min2, &s->srexpire, &s->swexpire);
3602 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003603 tv_min(&t->expire, &min1, &min2);
3604
3605 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003606 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003607
willy tarreau5cbea6f2005-12-17 12:48:26 +01003608 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003609 }
3610
willy tarreau5cbea6f2005-12-17 12:48:26 +01003611 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003612 actconn--;
3613
willy tarreau9fe663a2005-12-17 13:02:59 +01003614 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003615 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003616 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 +01003617 write(1, trash, len);
3618 }
3619
willy tarreau750a4722005-12-17 13:21:24 +01003620 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003621 if (s->rep != NULL)
3622 s->logs.bytes = s->rep->total;
3623
willy tarreau9fe663a2005-12-17 13:02:59 +01003624 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003625 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003626 sess_log(s);
3627
willy tarreau0f7af912005-12-17 12:21:26 +01003628 /* the task MUST not be in the run queue anymore */
3629 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003630 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003631 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003632 return -1; /* rest in peace for eternity */
3633}
3634
3635
3636
3637/*
3638 * manages a server health-check. Returns
3639 * the time the task accepts to wait, or -1 for infinity.
3640 */
3641int process_chk(struct task *t) {
3642 struct server *s = t->context;
3643 int fd = s->curfd;
3644 int one = 1;
3645
willy tarreauef900ab2005-12-17 12:52:52 +01003646 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003647
3648 if (fd < 0) { /* no check currently running */
3649 //fprintf(stderr, "process_chk: 2\n");
3650 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3651 task_queue(t); /* restore t to its place in the task list */
3652 return tv_remain(&now, &t->expire);
3653 }
3654
3655 /* we'll initiate a new check */
3656 s->result = 0; /* no result yet */
3657 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003658 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003659 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3660 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3661 //fprintf(stderr, "process_chk: 3\n");
3662
willy tarreau036e1ce2005-12-17 13:46:33 +01003663 /* allow specific binding */
3664 if (s->proxy->options & PR_O_BIND_SRC &&
3665 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
3666 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
3667 close(fd);
3668 s->result = -1;
3669 }
3670 else if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003671 /* OK, connection in progress or established */
3672
3673 //fprintf(stderr, "process_chk: 4\n");
3674
3675 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3676 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003677 fdtab[fd].read = &event_srv_chk_r;
3678 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003679 fdtab[fd].state = FD_STCONN; /* connection in progress */
3680 FD_SET(fd, StaticWriteEvent); /* for connect status */
3681 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003682 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3683 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003684 task_queue(t); /* restore t to its place in the task list */
3685 return tv_remain(&now, &t->expire);
3686 }
3687 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3688 s->result = -1; /* a real error */
3689 }
3690 }
3691 //fprintf(stderr, "process_chk: 5\n");
3692 close(fd);
3693 }
3694
3695 if (!s->result) { /* nothing done */
3696 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003697 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003698 task_queue(t); /* restore t to its place in the task list */
3699 return tv_remain(&now, &t->expire);
3700 }
3701
3702 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003703 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003704 s->health--; /* still good */
3705 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003706 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003707 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003708 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003709
willy tarreau9fe663a2005-12-17 13:02:59 +01003710 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003711 }
willy tarreauef900ab2005-12-17 12:52:52 +01003712
willy tarreau5cbea6f2005-12-17 12:48:26 +01003713 s->health = 0; /* failure */
3714 s->state &= ~SRV_RUNNING;
3715 }
3716
3717 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003718 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3719 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003720 }
3721 else {
3722 //fprintf(stderr, "process_chk: 8\n");
3723 /* there was a test running */
3724 if (s->result > 0) { /* good server detected */
3725 //fprintf(stderr, "process_chk: 9\n");
3726 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003727 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003728 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003729 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003730 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003731 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003732 }
willy tarreauef900ab2005-12-17 12:52:52 +01003733
willy tarreaue47c8d72005-12-17 12:55:52 +01003734 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003735 s->state |= SRV_RUNNING;
3736 }
willy tarreauef900ab2005-12-17 12:52:52 +01003737 s->curfd = -1; /* no check running anymore */
3738 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003739 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003740 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003741 }
3742 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3743 //fprintf(stderr, "process_chk: 10\n");
3744 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003745 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003746 s->health--; /* still good */
3747 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003748 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003749 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003750 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003751
3752 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003753 }
willy tarreauef900ab2005-12-17 12:52:52 +01003754
willy tarreau5cbea6f2005-12-17 12:48:26 +01003755 s->health = 0; /* failure */
3756 s->state &= ~SRV_RUNNING;
3757 }
3758 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003759 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003760 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003761 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003762 }
3763 /* if result is 0 and there's no timeout, we have to wait again */
3764 }
3765 //fprintf(stderr, "process_chk: 11\n");
3766 s->result = 0;
3767 task_queue(t); /* restore t to its place in the task list */
3768 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003769}
3770
3771
willy tarreau5cbea6f2005-12-17 12:48:26 +01003772
willy tarreau0f7af912005-12-17 12:21:26 +01003773#if STATTIME > 0
3774int stats(void);
3775#endif
3776
3777/*
3778 * Main select() loop.
3779 */
3780
3781void select_loop() {
3782 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003783 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003784 int status;
3785 int fd,i;
3786 struct timeval delta;
3787 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003788 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003789
willy tarreau5cbea6f2005-12-17 12:48:26 +01003790 tv_now(&now);
3791
3792 while (1) {
3793 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003794
willy tarreau5cbea6f2005-12-17 12:48:26 +01003795 /* look for expired tasks and add them to the run queue.
3796 */
3797 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3798 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3799 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003800 if (t->state & TASK_RUNNING)
3801 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003802
3803 /* wakeup expired entries. It doesn't matter if they are
3804 * already running because of a previous event
3805 */
3806 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003807 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003808 task_wakeup(&rq, t);
3809 }
3810 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003811 /* first non-runnable task. Use its expiration date as an upper bound */
3812 int temp_time = tv_remain(&now, &t->expire);
3813 if (temp_time)
3814 next_time = temp_time;
3815 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003816 break;
3817 }
3818 }
3819
3820 /* process each task in the run queue now. Each task may be deleted
3821 * since we only use tnext.
3822 */
3823 tnext = rq;
3824 while ((t = tnext) != NULL) {
3825 int temp_time;
3826
3827 tnext = t->rqnext;
3828 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003829 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003830 temp_time = t->process(t);
3831 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003832 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003833 }
3834
willy tarreauef900ab2005-12-17 12:52:52 +01003835 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003836
3837 /* maintain all proxies in a consistent state. This should quickly become a task */
3838 time2 = maintain_proxies();
3839 next_time = MINTIME(time2, next_time);
3840
3841 /* stop when there's no connection left and we don't allow them anymore */
3842 if (!actconn && listeners == 0)
3843 break;
3844
willy tarreau0f7af912005-12-17 12:21:26 +01003845
3846#if STATTIME > 0
3847 time2 = stats();
3848 // fprintf(stderr," stats = %d\n", time2);
3849 next_time = MINTIME(time2, next_time);
3850#endif
3851
willy tarreau5cbea6f2005-12-17 12:48:26 +01003852 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003853 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003854 /* to avoid eventual select loops due to timer precision */
3855 next_time += SCHEDULER_RESOLUTION;
3856 delta.tv_sec = next_time / 1000;
3857 delta.tv_usec = (next_time % 1000) * 1000;
3858 }
3859 else if (next_time == 0) { /* allow select to return immediately when needed */
3860 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003861 }
3862
3863
3864 /* let's restore fdset state */
3865
3866 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003867 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003868 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3869 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3870 }
3871
3872// /* just a verification code, needs to be removed for performance */
3873// for (i=0; i<maxfd; i++) {
3874// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3875// abort();
3876// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3877// abort();
3878//
3879// }
3880
3881 status=select(maxfd,
3882 readnotnull ? ReadEvent : NULL,
3883 writenotnull ? WriteEvent : NULL,
3884 NULL,
3885 (next_time >= 0) ? &delta : NULL);
3886
willy tarreau5cbea6f2005-12-17 12:48:26 +01003887 /* this is an experiment on the separation of the select work */
3888 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3889 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3890
willy tarreau0f7af912005-12-17 12:21:26 +01003891 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003892
willy tarreau0f7af912005-12-17 12:21:26 +01003893 if (status > 0) { /* must proceed with events */
3894
3895 int fds;
3896 char count;
3897
3898 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3899 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3900 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3901
willy tarreau5cbea6f2005-12-17 12:48:26 +01003902 /* if we specify read first, the accepts and zero reads will be
3903 * seen first. Moreover, system buffers will be flushed faster.
3904 */
willy tarreau0f7af912005-12-17 12:21:26 +01003905 if (fdtab[fd].state == FD_STCLOSE)
3906 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003907
3908 if (FD_ISSET(fd, ReadEvent))
3909 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003910
willy tarreau5cbea6f2005-12-17 12:48:26 +01003911 if (FD_ISSET(fd, WriteEvent))
3912 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003913 }
3914 }
3915 else {
3916 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3917 }
willy tarreau0f7af912005-12-17 12:21:26 +01003918 }
3919}
3920
3921
3922#if STATTIME > 0
3923/*
3924 * Display proxy statistics regularly. It is designed to be called from the
3925 * select_loop().
3926 */
3927int stats(void) {
3928 static int lines;
3929 static struct timeval nextevt;
3930 static struct timeval lastevt;
3931 static struct timeval starttime = {0,0};
3932 unsigned long totaltime, deltatime;
3933 int ret;
3934
willy tarreau750a4722005-12-17 13:21:24 +01003935 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01003936 deltatime = (tv_diff(&lastevt, &now)?:1);
3937 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01003938
willy tarreau9fe663a2005-12-17 13:02:59 +01003939 if (global.mode & MODE_STATS) {
3940 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003941 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003942 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3943 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003944 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003945 actconn, totalconn,
3946 stats_tsk_new, stats_tsk_good,
3947 stats_tsk_left, stats_tsk_right,
3948 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3949 }
3950 }
3951
3952 tv_delayfrom(&nextevt, &now, STATTIME);
3953
3954 lastevt=now;
3955 }
3956 ret = tv_remain(&now, &nextevt);
3957 return ret;
3958}
3959#endif
3960
3961
3962/*
3963 * this function enables proxies when there are enough free sessions,
3964 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003965 * select_loop(). It returns the time left before next expiration event
3966 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003967 */
3968static int maintain_proxies(void) {
3969 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003970 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003971
3972 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003973 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003974
3975 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003976 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003977 while (p) {
3978 if (p->nbconn < p->maxconn) {
3979 if (p->state == PR_STIDLE) {
3980 FD_SET(p->listen_fd, StaticReadEvent);
3981 p->state = PR_STRUN;
3982 }
3983 }
3984 else {
3985 if (p->state == PR_STRUN) {
3986 FD_CLR(p->listen_fd, StaticReadEvent);
3987 p->state = PR_STIDLE;
3988 }
3989 }
3990 p = p->next;
3991 }
3992 }
3993 else { /* block all proxies */
3994 while (p) {
3995 if (p->state == PR_STRUN) {
3996 FD_CLR(p->listen_fd, StaticReadEvent);
3997 p->state = PR_STIDLE;
3998 }
3999 p = p->next;
4000 }
4001 }
4002
willy tarreau5cbea6f2005-12-17 12:48:26 +01004003 if (stopping) {
4004 p = proxy;
4005 while (p) {
4006 if (p->state != PR_STDISABLED) {
4007 int t;
4008 t = tv_remain(&now, &p->stop_time);
4009 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004010 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004011 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004012
willy tarreau5cbea6f2005-12-17 12:48:26 +01004013 fd_delete(p->listen_fd);
4014 p->state = PR_STDISABLED;
4015 listeners--;
4016 }
4017 else {
4018 tleft = MINTIME(t, tleft);
4019 }
4020 }
4021 p = p->next;
4022 }
4023 }
4024 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004025}
4026
4027/*
4028 * this function disables health-check servers so that the process will quickly be ignored
4029 * by load balancers.
4030 */
4031static void soft_stop(void) {
4032 struct proxy *p;
4033
4034 stopping = 1;
4035 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004036 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004037 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004038 if (p->state != PR_STDISABLED) {
4039 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004040 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004041 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004042 }
willy tarreau0f7af912005-12-17 12:21:26 +01004043 p = p->next;
4044 }
4045}
4046
4047/*
4048 * upon SIGUSR1, let's have a soft stop.
4049 */
4050void sig_soft_stop(int sig) {
4051 soft_stop();
4052 signal(sig, SIG_IGN);
4053}
4054
4055
willy tarreau8337c6b2005-12-17 13:41:01 +01004056/*
4057 * this function dumps every server's state when the process receives SIGHUP.
4058 */
4059void sig_dump_state(int sig) {
4060 struct proxy *p = proxy;
4061
4062 Warning("SIGHUP received, dumping servers states.\n");
4063 while (p) {
4064 struct server *s = p->srv;
4065
4066 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4067 while (s) {
4068 if (s->state & SRV_RUNNING) {
4069 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4070 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4071 }
4072 else {
4073 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4074 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4075 }
4076 s = s->next;
4077 }
4078 p = p->next;
4079 }
4080 signal(sig, sig_dump_state);
4081}
4082
willy tarreau0f7af912005-12-17 12:21:26 +01004083void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004084 struct task *t, *tnext;
4085 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004086
willy tarreau5cbea6f2005-12-17 12:48:26 +01004087 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4088 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4089 tnext = t->next;
4090 s = t->context;
4091 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4092 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4093 "req=%d, rep=%d, clifd=%d\n",
4094 s, tv_remain(&now, &t->expire),
4095 s->cli_state,
4096 s->srv_state,
4097 FD_ISSET(s->cli_fd, StaticReadEvent),
4098 FD_ISSET(s->cli_fd, StaticWriteEvent),
4099 FD_ISSET(s->srv_fd, StaticReadEvent),
4100 FD_ISSET(s->srv_fd, StaticWriteEvent),
4101 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4102 );
willy tarreau0f7af912005-12-17 12:21:26 +01004103 }
4104}
4105
willy tarreaue39cd132005-12-17 13:00:18 +01004106void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4107 struct hdr_exp *exp;
4108
4109 while (*head != NULL)
4110 head = &(*head)->next;
4111
4112 exp = calloc(1, sizeof(struct hdr_exp));
4113
4114 exp->preg = preg;
4115 exp->replace = replace;
4116 exp->action = action;
4117 *head = exp;
4118}
4119
willy tarreau9fe663a2005-12-17 13:02:59 +01004120
willy tarreau0f7af912005-12-17 12:21:26 +01004121/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004122 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004123 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004124int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004125
willy tarreau9fe663a2005-12-17 13:02:59 +01004126 if (!strcmp(args[0], "global")) { /* new section */
4127 /* no option, nothing special to do */
4128 return 0;
4129 }
4130 else if (!strcmp(args[0], "daemon")) {
4131 global.mode |= MODE_DAEMON;
4132 }
4133 else if (!strcmp(args[0], "debug")) {
4134 global.mode |= MODE_DEBUG;
4135 }
4136 else if (!strcmp(args[0], "quiet")) {
4137 global.mode |= MODE_QUIET;
4138 }
4139 else if (!strcmp(args[0], "stats")) {
4140 global.mode |= MODE_STATS;
4141 }
4142 else if (!strcmp(args[0], "uid")) {
4143 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004144 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004145 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004146 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004147 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004148 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004149 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004150 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004151 global.uid = atol(args[1]);
4152 }
4153 else if (!strcmp(args[0], "gid")) {
4154 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004155 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004156 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004157 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004158 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004159 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004160 return -1;
4161 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004162 global.gid = atol(args[1]);
4163 }
4164 else if (!strcmp(args[0], "nbproc")) {
4165 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004166 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004167 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004168 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004169 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004170 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004171 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004172 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004173 global.nbproc = atol(args[1]);
4174 }
4175 else if (!strcmp(args[0], "maxconn")) {
4176 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004177 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004178 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004179 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004180 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004181 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004182 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004183 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004184 global.maxconn = atol(args[1]);
4185 }
4186 else if (!strcmp(args[0], "chroot")) {
4187 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004188 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004189 return 0;
4190 }
4191 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004192 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004193 return -1;
4194 }
4195 global.chroot = strdup(args[1]);
4196 }
4197 else if (!strcmp(args[0], "log")) { /* syslog server address */
4198 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004199 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004200
4201 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004202 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004203 return -1;
4204 }
4205
4206 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4207 if (!strcmp(log_facilities[facility], args[2]))
4208 break;
4209
4210 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004211 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004212 exit(1);
4213 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004214
4215 level = 7; /* max syslog level = debug */
4216 if (*(args[3])) {
4217 while (level >= 0 && strcmp(log_levels[level], args[3]))
4218 level--;
4219 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004220 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004221 exit(1);
4222 }
4223 }
4224
willy tarreau9fe663a2005-12-17 13:02:59 +01004225 sa = str2sa(args[1]);
4226 if (!sa->sin_port)
4227 sa->sin_port = htons(SYSLOG_PORT);
4228
4229 if (global.logfac1 == -1) {
4230 global.logsrv1 = *sa;
4231 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004232 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004233 }
4234 else if (global.logfac2 == -1) {
4235 global.logsrv2 = *sa;
4236 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004237 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004238 }
4239 else {
4240 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4241 return -1;
4242 }
4243
4244 }
4245 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004246 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004247 return -1;
4248 }
4249 return 0;
4250}
4251
4252
4253/*
4254 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4255 */
4256int cfg_parse_listen(char *file, int linenum, char **args) {
4257 static struct proxy *curproxy = NULL;
4258 struct server *newsrv = NULL;
4259
4260 if (!strcmp(args[0], "listen")) { /* new proxy */
4261 if (strchr(args[2], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004262 Alert("parsing [%s:%d] : '%s' expects <id> and <addr:port> as arguments.\n",
4263 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004264 return -1;
4265 }
4266
4267 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004268 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004269 return -1;
4270 }
4271 curproxy->next = proxy;
4272 proxy = curproxy;
4273 curproxy->id = strdup(args[1]);
4274 curproxy->listen_addr = *str2sa(args[2]);
4275 curproxy->state = PR_STNEW;
4276 /* set default values */
4277 curproxy->maxconn = cfg_maxpconn;
4278 curproxy->conn_retries = CONN_RETRIES;
4279 curproxy->options = 0;
4280 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
4281 curproxy->mode = PR_MODE_TCP;
4282 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
4283 curproxy->to_log = 0;
4284 return 0;
4285 }
4286 else if (curproxy == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004287 Alert("parsing [%s:%d] : 'listen' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004288 return -1;
4289 }
4290
4291 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
4292 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
4293 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
4294 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
4295 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004296 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004297 return -1;
4298 }
4299 }
4300 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
4301 curproxy->state = PR_STDISABLED;
4302 }
4303 else if (!strcmp(args[0], "cookie")) { /* cookie name */
4304 int cur_arg;
4305 if (curproxy->cookie_name != NULL) {
4306 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
4307 file, linenum);
4308 return 0;
4309 }
4310
4311 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004312 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
4313 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004314 return -1;
4315 }
4316 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004317 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004318
4319 cur_arg = 2;
4320 while (*(args[cur_arg])) {
4321 if (!strcmp(args[cur_arg], "rewrite")) {
4322 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01004323 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004324 else if (!strcmp(args[cur_arg], "indirect")) {
4325 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01004326 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004327 else if (!strcmp(args[cur_arg], "insert")) {
4328 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01004329 }
willy tarreau240afa62005-12-17 13:14:35 +01004330 else if (!strcmp(args[cur_arg], "nocache")) {
4331 curproxy->options |= PR_O_COOK_NOC;
4332 }
willy tarreaucd878942005-12-17 13:27:43 +01004333 else if (!strcmp(args[cur_arg], "postonly")) {
4334 curproxy->options |= PR_O_COOK_POST;
4335 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004336 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004337 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
4338 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004339 return -1;
4340 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004341 cur_arg++;
4342 }
4343 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004344 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatibles.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004345 file, linenum);
4346 return -1;
4347 }
4348 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004349 else if (!strcmp(args[0], "capture")) { /* name of a cookie to capture */
4350 if (curproxy->capture_name != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004351 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4352 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004353 return 0;
4354 }
4355
4356 if (*(args[4]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004357 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
4358 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004359 return -1;
4360 }
4361 curproxy->capture_name = strdup(args[2]);
4362 curproxy->capture_namelen = strlen(curproxy->capture_name);
4363 curproxy->capture_len = atol(args[4]);
4364 if (curproxy->capture_len >= CAPTURE_LEN) {
4365 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
4366 file, linenum, CAPTURE_LEN - 1);
4367 curproxy->capture_len = CAPTURE_LEN - 1;
4368 }
4369 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004370 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
4371 if (curproxy->contimeout != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004372 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004373 return 0;
4374 }
4375 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004376 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4377 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004378 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004379 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004380 curproxy->contimeout = atol(args[1]);
4381 }
4382 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
4383 if (curproxy->clitimeout != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004384 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4385 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004386 return 0;
4387 }
4388 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004389 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4390 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004391 return -1;
4392 }
4393 curproxy->clitimeout = atol(args[1]);
4394 }
4395 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
4396 if (curproxy->srvtimeout != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004397 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004398 return 0;
4399 }
4400 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004401 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4402 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004403 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004404 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004405 curproxy->srvtimeout = atol(args[1]);
4406 }
4407 else if (!strcmp(args[0], "retries")) { /* connection retries */
4408 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004409 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
4410 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004411 return -1;
4412 }
4413 curproxy->conn_retries = atol(args[1]);
4414 }
4415 else if (!strcmp(args[0], "option")) {
4416 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004417 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004418 return -1;
4419 }
4420 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004421 /* enable reconnections to dispatch */
4422 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004423#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004424 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004425 /* enable transparent proxy connections */
4426 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004427#endif
4428 else if (!strcmp(args[1], "keepalive"))
4429 /* enable keep-alive */
4430 curproxy->options |= PR_O_KEEPALIVE;
4431 else if (!strcmp(args[1], "forwardfor"))
4432 /* insert x-forwarded-for field */
4433 curproxy->options |= PR_O_FWDFOR;
4434 else if (!strcmp(args[1], "httplog")) {
4435 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01004436 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
4437 }
4438 else if (!strcmp(args[1], "dontlognull")) {
4439 /* don't log empty requests */
4440 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004441 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004442 else if (!strcmp(args[1], "httpchk")) {
4443 /* use HTTP request to check servers' health */
4444 curproxy->options |= PR_O_HTTP_CHK;
willy tarreau2f6ba652005-12-17 13:57:42 +01004445 if (*args[2]) {
4446 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
4447 curproxy->check_req = (char *)malloc(reqlen);
4448 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4449 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
4450 } else {
4451 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
4452 curproxy->check_len = strlen(DEF_CHECK_REQ);
4453 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004454 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004455 else if (!strcmp(args[1], "persist")) {
4456 /* persist on using the server specified by the cookie, even when it's down */
4457 curproxy->options |= PR_O_PERSIST;
4458 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004459 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004460 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004461 return -1;
4462 }
4463 return 0;
4464 }
4465 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4466 /* enable reconnections to dispatch */
4467 curproxy->options |= PR_O_REDISP;
4468 }
willy tarreaua1598082005-12-17 13:08:06 +01004469#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004470 else if (!strcmp(args[0], "transparent")) {
4471 /* enable transparent proxy connections */
4472 curproxy->options |= PR_O_TRANSP;
4473 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004474#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004475 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4476 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004477 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004478 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004479 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004480 curproxy->maxconn = atol(args[1]);
4481 }
4482 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4483 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004484 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004485 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004486 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004487 curproxy->grace = atol(args[1]);
4488 }
4489 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
4490 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004491 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004492 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004493 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004494 curproxy->dispatch_addr = *str2sa(args[1]);
4495 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004496 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01004497 if (*(args[1])) {
4498 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004499 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004500 }
4501 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004502 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004503 return -1;
4504 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004505 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004506 else /* if no option is set, use round-robin by default */
4507 curproxy->options |= PR_O_BALANCE_RR;
4508 }
4509 else if (!strcmp(args[0], "server")) { /* server address */
4510 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004511
willy tarreau9fe663a2005-12-17 13:02:59 +01004512 if (strchr(args[2], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004513 Alert("parsing [%s:%d] : '%s' expects <name> and <addr:port> as arguments.\n",
4514 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004515 return -1;
4516 }
4517 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4518 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4519 return -1;
4520 }
4521 newsrv->next = curproxy->srv;
4522 curproxy->srv = newsrv;
4523 newsrv->proxy = curproxy;
4524 newsrv->id = strdup(args[1]);
4525 newsrv->addr = *str2sa(args[2]);
4526 newsrv->state = SRV_RUNNING; /* early server setup */
4527 newsrv->curfd = -1; /* no health-check in progress */
4528 newsrv->inter = DEF_CHKINTR;
4529 newsrv->rise = DEF_RISETIME;
4530 newsrv->fall = DEF_FALLTIME;
4531 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4532 cur_arg = 3;
4533 while (*args[cur_arg]) {
4534 if (!strcmp(args[cur_arg], "cookie")) {
4535 newsrv->cookie = strdup(args[cur_arg + 1]);
4536 newsrv->cklen = strlen(args[cur_arg + 1]);
4537 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004538 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004539 else if (!strcmp(args[cur_arg], "rise")) {
4540 newsrv->rise = atol(args[cur_arg + 1]);
4541 newsrv->health = newsrv->rise;
4542 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004543 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004544 else if (!strcmp(args[cur_arg], "fall")) {
4545 newsrv->fall = atol(args[cur_arg + 1]);
4546 cur_arg += 2;
4547 }
4548 else if (!strcmp(args[cur_arg], "inter")) {
4549 newsrv->inter = atol(args[cur_arg + 1]);
4550 cur_arg += 2;
4551 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004552 else if (!strcmp(args[cur_arg], "backup")) {
4553 newsrv->state |= SRV_BACKUP;
4554 cur_arg ++;
4555 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004556 else if (!strcmp(args[cur_arg], "check")) {
4557 struct task *t;
4558
4559 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
4560 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004561 return -1;
4562 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004563
4564 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4565 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4566 t->state = TASK_IDLE;
4567 t->process = process_chk;
4568 t->context = newsrv;
4569
4570 if (curproxy->state != PR_STDISABLED) {
4571 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4572 task_queue(t);
4573 task_wakeup(&rq, t);
4574 }
4575
4576 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004577 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004578 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004579 Alert("parsing [%s:%d] : server %s only supports options 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004580 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004581 return -1;
4582 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004583 }
4584 curproxy->nbservers++;
4585 }
4586 else if (!strcmp(args[0], "log")) { /* syslog server address */
4587 struct sockaddr_in *sa;
4588 int facility;
4589
4590 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4591 curproxy->logfac1 = global.logfac1;
4592 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004593 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004594 curproxy->logfac2 = global.logfac2;
4595 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01004596 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01004597 }
4598 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01004599 int level;
4600
willy tarreau0f7af912005-12-17 12:21:26 +01004601 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4602 if (!strcmp(log_facilities[facility], args[2]))
4603 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004604
willy tarreau0f7af912005-12-17 12:21:26 +01004605 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004606 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01004607 exit(1);
4608 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004609
willy tarreau8337c6b2005-12-17 13:41:01 +01004610 level = 7; /* max syslog level = debug */
4611 if (*(args[3])) {
4612 while (level >= 0 && strcmp(log_levels[level], args[3]))
4613 level--;
4614 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004615 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004616 exit(1);
4617 }
4618 }
4619
willy tarreau0f7af912005-12-17 12:21:26 +01004620 sa = str2sa(args[1]);
4621 if (!sa->sin_port)
4622 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004623
willy tarreau0f7af912005-12-17 12:21:26 +01004624 if (curproxy->logfac1 == -1) {
4625 curproxy->logsrv1 = *sa;
4626 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004627 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004628 }
4629 else if (curproxy->logfac2 == -1) {
4630 curproxy->logsrv2 = *sa;
4631 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004632 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004633 }
4634 else {
4635 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004636 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004637 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004638 }
4639 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004640 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004641 file, linenum);
4642 return -1;
4643 }
4644 }
willy tarreaua1598082005-12-17 13:08:06 +01004645 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
4646 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004647 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n",
4648 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01004649 return -1;
4650 }
4651
4652 curproxy->source_addr = *str2sa(args[1]);
4653 curproxy->options |= PR_O_BIND_SRC;
4654 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004655 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4656 regex_t *preg;
4657
4658 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004659 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4660 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004661 return -1;
4662 }
4663
4664 preg = calloc(1, sizeof(regex_t));
4665 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004666 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004667 return -1;
4668 }
4669
4670 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4671 }
4672 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4673 regex_t *preg;
4674
4675 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004676 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004677 return -1;
4678 }
4679
4680 preg = calloc(1, sizeof(regex_t));
4681 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004682 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004683 return -1;
4684 }
4685
4686 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4687 }
4688 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
4689 regex_t *preg;
4690
4691 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004692 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004693 return -1;
4694 }
4695
4696 preg = calloc(1, sizeof(regex_t));
4697 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004698 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004699 return -1;
4700 }
4701
4702 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4703 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004704 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
4705 regex_t *preg;
4706
4707 if (*(args[1]) == 0) {
4708 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
4709 return -1;
4710 }
4711
4712 preg = calloc(1, sizeof(regex_t));
4713 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4714 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
4715 return -1;
4716 }
4717
4718 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
4719 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004720 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4721 regex_t *preg;
4722
4723 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004724 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004725 return -1;
4726 }
4727
4728 preg = calloc(1, sizeof(regex_t));
4729 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004730 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004731 return -1;
4732 }
4733
4734 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4735 }
4736 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4737 regex_t *preg;
4738
4739 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004740 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4741 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004742 return -1;
4743 }
4744
4745 preg = calloc(1, sizeof(regex_t));
4746 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004747 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004748 return -1;
4749 }
4750
4751 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4752 }
4753 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4754 regex_t *preg;
4755
4756 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004757 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004758 return -1;
4759 }
4760
4761 preg = calloc(1, sizeof(regex_t));
4762 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004763 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004764 return -1;
4765 }
4766
4767 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4768 }
4769 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4770 regex_t *preg;
4771
4772 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004773 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004774 return -1;
4775 }
4776
4777 preg = calloc(1, sizeof(regex_t));
4778 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004779 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004780 return -1;
4781 }
4782
4783 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4784 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004785 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
4786 regex_t *preg;
4787
4788 if (*(args[1]) == 0) {
4789 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
4790 return -1;
4791 }
4792
4793 preg = calloc(1, sizeof(regex_t));
4794 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4795 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
4796 return -1;
4797 }
4798
4799 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
4800 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004801 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4802 regex_t *preg;
4803
4804 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004805 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004806 return -1;
4807 }
4808
4809 preg = calloc(1, sizeof(regex_t));
4810 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004811 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004812 return -1;
4813 }
4814
4815 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4816 }
4817 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4818 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004819 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004820 return 0;
4821 }
4822
4823 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004824 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004825 return -1;
4826 }
4827
4828 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004829 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004830 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004831 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004832
4833 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004834 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4835 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004836 return -1;
4837 }
4838
4839 preg = calloc(1, sizeof(regex_t));
4840 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004841 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004842 return -1;
4843 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004844
4845 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4846 }
4847 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4848 regex_t *preg;
4849
4850 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004851 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004852 return -1;
4853 }
willy tarreaue39cd132005-12-17 13:00:18 +01004854
willy tarreau9fe663a2005-12-17 13:02:59 +01004855 preg = calloc(1, sizeof(regex_t));
4856 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004857 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004858 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004859 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004860
4861 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4862 }
4863 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004864 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004865
willy tarreau9fe663a2005-12-17 13:02:59 +01004866 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004867 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4868 file, linenum, args[0]);
willy tarreaue39cd132005-12-17 13:00:18 +01004869 return -1;
4870 }
4871
4872 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004873 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004874 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreaue39cd132005-12-17 13:00:18 +01004875 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004876 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004877
4878 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4879 }
4880 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4881 regex_t *preg;
4882
4883 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004884 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004885 return -1;
4886 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004887
willy tarreau9fe663a2005-12-17 13:02:59 +01004888 preg = calloc(1, sizeof(regex_t));
4889 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004890 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004891 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004892 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004893
4894 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4895 }
4896 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4897 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004898 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004899 return 0;
4900 }
4901
4902 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004903 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004904 return -1;
4905 }
4906
4907 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4908 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004909 else if (!strcmp(args[0], "errorloc")) { /* error location */
4910 int errnum;
4911 char *err;
4912
4913 if (*(args[2]) == 0) {
4914 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
4915 return -1;
4916 }
4917
4918 errnum = atol(args[1]);
4919 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
4920 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
4921
4922 if (errnum == 400) {
4923 if (curproxy->errmsg.msg400) {
4924 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4925 free(curproxy->errmsg.msg400);
4926 }
4927 curproxy->errmsg.msg400 = err;
4928 curproxy->errmsg.len400 = strlen(err);
4929 }
4930 else if (errnum == 403) {
4931 if (curproxy->errmsg.msg403) {
4932 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4933 free(curproxy->errmsg.msg403);
4934 }
4935 curproxy->errmsg.msg403 = err;
4936 curproxy->errmsg.len403 = strlen(err);
4937 }
4938 else if (errnum == 408) {
4939 if (curproxy->errmsg.msg408) {
4940 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4941 free(curproxy->errmsg.msg408);
4942 }
4943 curproxy->errmsg.msg408 = err;
4944 curproxy->errmsg.len408 = strlen(err);
4945 }
4946 else if (errnum == 500) {
4947 if (curproxy->errmsg.msg500) {
4948 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4949 free(curproxy->errmsg.msg500);
4950 }
4951 curproxy->errmsg.msg500 = err;
4952 curproxy->errmsg.len500 = strlen(err);
4953 }
4954 else if (errnum == 502) {
4955 if (curproxy->errmsg.msg502) {
4956 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4957 free(curproxy->errmsg.msg502);
4958 }
4959 curproxy->errmsg.msg502 = err;
4960 curproxy->errmsg.len502 = strlen(err);
4961 }
4962 else if (errnum == 503) {
4963 if (curproxy->errmsg.msg503) {
4964 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4965 free(curproxy->errmsg.msg503);
4966 }
4967 curproxy->errmsg.msg503 = err;
4968 curproxy->errmsg.len503 = strlen(err);
4969 }
4970 else if (errnum == 504) {
4971 if (curproxy->errmsg.msg504) {
4972 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4973 free(curproxy->errmsg.msg504);
4974 }
4975 curproxy->errmsg.msg504 = err;
4976 curproxy->errmsg.len504 = strlen(err);
4977 }
4978 else {
4979 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
4980 free(err);
4981 }
4982 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004983 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004984 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01004985 return -1;
4986 }
4987 return 0;
4988}
willy tarreaue39cd132005-12-17 13:00:18 +01004989
willy tarreau5cbea6f2005-12-17 12:48:26 +01004990
willy tarreau9fe663a2005-12-17 13:02:59 +01004991/*
4992 * This function reads and parses the configuration file given in the argument.
4993 * returns 0 if OK, -1 if error.
4994 */
4995int readcfgfile(char *file) {
4996 char thisline[256];
4997 char *line;
4998 FILE *f;
4999 int linenum = 0;
5000 char *end;
5001 char *args[MAX_LINE_ARGS];
5002 int arg;
5003 int cfgerr = 0;
5004 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01005005
willy tarreau9fe663a2005-12-17 13:02:59 +01005006 struct proxy *curproxy = NULL;
5007 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005008
willy tarreau9fe663a2005-12-17 13:02:59 +01005009 if ((f=fopen(file,"r")) == NULL)
5010 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005011
willy tarreau9fe663a2005-12-17 13:02:59 +01005012 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
5013 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005014
willy tarreau9fe663a2005-12-17 13:02:59 +01005015 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005016
willy tarreau9fe663a2005-12-17 13:02:59 +01005017 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01005018 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01005019 line++;
5020
5021 arg = 0;
5022 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01005023
willy tarreau9fe663a2005-12-17 13:02:59 +01005024 while (*line && arg < MAX_LINE_ARGS) {
5025 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
5026 * C equivalent value. Other combinations left unchanged (eg: \1).
5027 */
5028 if (*line == '\\') {
5029 int skip = 0;
5030 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
5031 *line = line[1];
5032 skip = 1;
5033 }
5034 else if (line[1] == 'r') {
5035 *line = '\r';
5036 skip = 1;
5037 }
5038 else if (line[1] == 'n') {
5039 *line = '\n';
5040 skip = 1;
5041 }
5042 else if (line[1] == 't') {
5043 *line = '\t';
5044 skip = 1;
5045 }
5046 else if (line[1] == 'x' && (line + 3 < end )) {
5047 unsigned char hex1, hex2;
5048 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
5049 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
5050 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
5051 *line = (hex1<<4) + hex2;
5052 skip = 3;
5053 }
5054 if (skip) {
5055 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
5056 end -= skip;
5057 }
5058 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005059 }
willy tarreaua1598082005-12-17 13:08:06 +01005060 else if (*line == '#' || *line == '\n' || *line == '\r') {
5061 /* end of string, end of loop */
5062 *line = 0;
5063 break;
5064 }
willy tarreauc29948c2005-12-17 13:10:27 +01005065 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005066 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01005067 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01005068 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01005069 line++;
5070 args[++arg] = line;
5071 }
5072 else {
5073 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005074 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005075 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005076
willy tarreau9fe663a2005-12-17 13:02:59 +01005077 /* empty line */
5078 if (!**args)
5079 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01005080
willy tarreau9fe663a2005-12-17 13:02:59 +01005081 /* zero out remaining args */
5082 while (++arg < MAX_LINE_ARGS) {
5083 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005084 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005085
willy tarreau9fe663a2005-12-17 13:02:59 +01005086 if (!strcmp(args[0], "listen")) /* new proxy */
5087 confsect = CFG_LISTEN;
5088 else if (!strcmp(args[0], "global")) /* global config */
5089 confsect = CFG_GLOBAL;
5090 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005091
willy tarreau9fe663a2005-12-17 13:02:59 +01005092 switch (confsect) {
5093 case CFG_LISTEN:
5094 if (cfg_parse_listen(file, linenum, args) < 0)
5095 return -1;
5096 break;
5097 case CFG_GLOBAL:
5098 if (cfg_parse_global(file, linenum, args) < 0)
5099 return -1;
5100 break;
5101 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01005102 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005103 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005104 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005105
5106
willy tarreau0f7af912005-12-17 12:21:26 +01005107 }
5108 fclose(f);
5109
5110 /*
5111 * Now, check for the integrity of all that we have collected.
5112 */
5113
5114 if ((curproxy = proxy) == NULL) {
5115 Alert("parsing %s : no <listen> line. Nothing to do !\n",
5116 file);
5117 return -1;
5118 }
5119
5120 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01005121 if (curproxy->state == PR_STDISABLED) {
5122 curproxy = curproxy->next;
5123 continue;
5124 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005125 if ((curproxy->mode != PR_MODE_HEALTH) &&
5126 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01005127 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005128 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
5129 file, curproxy->id);
5130 cfgerr++;
5131 }
5132 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
5133 if (curproxy->options & PR_O_TRANSP) {
5134 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
5135 file, curproxy->id);
5136 cfgerr++;
5137 }
5138 else if (curproxy->srv == NULL) {
5139 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
5140 file, curproxy->id);
5141 cfgerr++;
5142 }
willy tarreaua1598082005-12-17 13:08:06 +01005143 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005144 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
5145 file, curproxy->id);
5146 }
5147 }
5148 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01005149 if (curproxy->cookie_name != NULL) {
5150 Warning("parsing %s : cookie will be ignored for listener %s.\n",
5151 file, curproxy->id);
5152 }
5153 if ((newsrv = curproxy->srv) != NULL) {
5154 Warning("parsing %s : servers will be ignored for listener %s.\n",
5155 file, curproxy->id);
5156 }
willy tarreaue39cd132005-12-17 13:00:18 +01005157 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005158 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
5159 file, curproxy->id);
5160 }
willy tarreaue39cd132005-12-17 13:00:18 +01005161 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005162 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
5163 file, curproxy->id);
5164 }
5165 }
5166 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
5167 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
5168 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
5169 file, curproxy->id);
5170 cfgerr++;
5171 }
5172 else {
5173 while (newsrv != NULL) {
5174 /* nothing to check for now */
5175 newsrv = newsrv->next;
5176 }
5177 }
5178 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005179 if (curproxy->errmsg.msg400 == NULL) {
5180 curproxy->errmsg.msg400 = (char *)HTTP_400;
5181 curproxy->errmsg.len400 = strlen(HTTP_400);
5182 }
5183 if (curproxy->errmsg.msg403 == NULL) {
5184 curproxy->errmsg.msg403 = (char *)HTTP_403;
5185 curproxy->errmsg.len403 = strlen(HTTP_403);
5186 }
5187 if (curproxy->errmsg.msg408 == NULL) {
5188 curproxy->errmsg.msg408 = (char *)HTTP_408;
5189 curproxy->errmsg.len408 = strlen(HTTP_408);
5190 }
5191 if (curproxy->errmsg.msg500 == NULL) {
5192 curproxy->errmsg.msg500 = (char *)HTTP_500;
5193 curproxy->errmsg.len500 = strlen(HTTP_500);
5194 }
5195 if (curproxy->errmsg.msg502 == NULL) {
5196 curproxy->errmsg.msg502 = (char *)HTTP_502;
5197 curproxy->errmsg.len502 = strlen(HTTP_502);
5198 }
5199 if (curproxy->errmsg.msg503 == NULL) {
5200 curproxy->errmsg.msg503 = (char *)HTTP_503;
5201 curproxy->errmsg.len503 = strlen(HTTP_503);
5202 }
5203 if (curproxy->errmsg.msg504 == NULL) {
5204 curproxy->errmsg.msg504 = (char *)HTTP_504;
5205 curproxy->errmsg.len504 = strlen(HTTP_504);
5206 }
willy tarreau0f7af912005-12-17 12:21:26 +01005207 curproxy = curproxy->next;
5208 }
5209 if (cfgerr > 0) {
5210 Alert("Errors found in configuration file, aborting.\n");
5211 return -1;
5212 }
5213 else
5214 return 0;
5215}
5216
5217
5218/*
5219 * This function initializes all the necessary variables. It only returns
5220 * if everything is OK. If something fails, it exits.
5221 */
5222void init(int argc, char **argv) {
5223 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01005224 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01005225 char *old_argv = *argv;
5226 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01005227 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01005228
5229 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005230 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005231 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
5232 sizeof(int)*8);
5233 exit(1);
5234 }
5235
5236 pid = getpid();
5237 progname = *argv;
5238 while ((tmp = strchr(progname, '/')) != NULL)
5239 progname = tmp + 1;
5240
5241 argc--; argv++;
5242 while (argc > 0) {
5243 char *flag;
5244
5245 if (**argv == '-') {
5246 flag = *argv+1;
5247
5248 /* 1 arg */
5249 if (*flag == 'v') {
5250 display_version();
5251 exit(0);
5252 }
5253 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01005254 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01005255 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01005256 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005257 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01005258 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01005259#if STATTIME > 0
5260 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01005261 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01005262 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01005263 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01005264#endif
5265 else { /* >=2 args */
5266 argv++; argc--;
5267 if (argc == 0)
5268 usage(old_argv);
5269
5270 switch (*flag) {
5271 case 'n' : cfg_maxconn = atol(*argv); break;
5272 case 'N' : cfg_maxpconn = atol(*argv); break;
5273 case 'f' : cfg_cfgfile = *argv; break;
5274 default: usage(old_argv);
5275 }
5276 }
5277 }
5278 else
5279 usage(old_argv);
5280 argv++; argc--;
5281 }
5282
willy tarreau0f7af912005-12-17 12:21:26 +01005283 if (!cfg_cfgfile)
5284 usage(old_argv);
5285
5286 gethostname(hostname, MAX_HOSTNAME_LEN);
5287
5288 if (readcfgfile(cfg_cfgfile) < 0) {
5289 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
5290 exit(1);
5291 }
5292
willy tarreau9fe663a2005-12-17 13:02:59 +01005293 if (cfg_maxconn > 0)
5294 global.maxconn = cfg_maxconn;
5295
5296 if (global.maxconn == 0)
5297 global.maxconn = DEFAULT_MAXCONN;
5298
5299 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
5300
5301 if (arg_mode & MODE_DEBUG) {
5302 /* command line debug mode inhibits configuration mode */
5303 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5304 }
willy tarreau750a4722005-12-17 13:21:24 +01005305 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01005306
5307 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
5308 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
5309 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5310 }
5311
5312 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
5313 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
5314 global.nbproc = 1;
5315 }
5316
5317 if (global.nbproc < 1)
5318 global.nbproc = 1;
5319
willy tarreau0f7af912005-12-17 12:21:26 +01005320 ReadEvent = (fd_set *)calloc(1,
5321 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005322 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005323 WriteEvent = (fd_set *)calloc(1,
5324 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005325 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005326 StaticReadEvent = (fd_set *)calloc(1,
5327 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005328 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005329 StaticWriteEvent = (fd_set *)calloc(1,
5330 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005331 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005332
5333 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01005334 sizeof(struct fdtab) * (global.maxsock));
5335 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01005336 fdtab[i].state = FD_STCLOSE;
5337 }
5338}
5339
5340/*
5341 * this function starts all the proxies. It returns 0 if OK, -1 if not.
5342 */
5343int start_proxies() {
5344 struct proxy *curproxy;
5345 int one = 1;
5346 int fd;
5347
5348 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
5349
5350 if (curproxy->state == PR_STDISABLED)
5351 continue;
5352
5353 if ((fd = curproxy->listen_fd =
5354 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
5355 Alert("cannot create listening socket for proxy %s. Aborting.\n",
5356 curproxy->id);
5357 return -1;
5358 }
5359
willy tarreau9fe663a2005-12-17 13:02:59 +01005360 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005361 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
5362 curproxy->id);
5363 close(fd);
5364 return -1;
5365 }
5366
willy tarreau0f7af912005-12-17 12:21:26 +01005367 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
5368 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
5369 (char *) &one, sizeof(one)) == -1)) {
5370 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
5371 curproxy->id);
5372 close(fd);
5373 return -1;
5374 }
5375
5376 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
5377 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
5378 curproxy->id);
5379 }
5380
5381 if (bind(fd,
5382 (struct sockaddr *)&curproxy->listen_addr,
5383 sizeof(curproxy->listen_addr)) == -1) {
5384 Alert("cannot bind socket for proxy %s. Aborting.\n",
5385 curproxy->id);
5386 close(fd);
5387 return -1;
5388 }
5389
5390 if (listen(fd, curproxy->maxconn) == -1) {
5391 Alert("cannot listen to socket for proxy %s. Aborting.\n",
5392 curproxy->id);
5393 close(fd);
5394 return -1;
5395 }
5396
5397 /* the function for the accept() event */
5398 fdtab[fd].read = &event_accept;
5399 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005400 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01005401 curproxy->state = PR_STRUN;
5402 fdtab[fd].state = FD_STLISTEN;
5403 FD_SET(fd, StaticReadEvent);
5404 fd_insert(fd);
5405 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01005406
willy tarreaua1598082005-12-17 13:08:06 +01005407 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005408
willy tarreau0f7af912005-12-17 12:21:26 +01005409 }
5410 return 0;
5411}
5412
5413
5414int main(int argc, char **argv) {
5415 init(argc, argv);
5416
willy tarreau9fe663a2005-12-17 13:02:59 +01005417 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01005418 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005419 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01005420 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01005421 }
5422
5423 signal(SIGQUIT, dump);
5424 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01005425 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005426
5427 /* on very high loads, a sigpipe sometimes happen just between the
5428 * getsockopt() which tells "it's OK to write", and the following write :-(
5429 */
willy tarreau3242e862005-12-17 12:27:53 +01005430#ifndef MSG_NOSIGNAL
5431 signal(SIGPIPE, SIG_IGN);
5432#endif
willy tarreau0f7af912005-12-17 12:21:26 +01005433
5434 if (start_proxies() < 0)
5435 exit(1);
5436
willy tarreau9fe663a2005-12-17 13:02:59 +01005437 /* open log files */
5438
5439 /* chroot if needed */
5440 if (global.chroot != NULL) {
5441 if (chroot(global.chroot) == -1) {
5442 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
5443 exit(1);
5444 }
5445 chdir("/");
5446 }
5447
5448 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01005449 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005450 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
5451 exit(1);
5452 }
5453
willy tarreau036e1ce2005-12-17 13:46:33 +01005454 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005455 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
5456 exit(1);
5457 }
5458
5459 if (global.mode & MODE_DAEMON) {
5460 int ret = 0;
5461 int proc;
5462
5463 /* the father launches the required number of processes */
5464 for (proc = 0; proc < global.nbproc; proc++) {
5465 ret = fork();
5466 if (ret < 0) {
5467 Alert("[%s.main()] Cannot fork.\n", argv[0]);
5468 exit(1); /* there has been an error */
5469 }
5470 else if (ret == 0) /* child breaks here */
5471 break;
5472 }
5473 if (proc == global.nbproc)
5474 exit(0); /* parent must leave */
5475
willy tarreau750a4722005-12-17 13:21:24 +01005476 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
5477 * that we can detach from the TTY. We MUST NOT do it in other cases since
5478 * it would have already be done, and 0-2 would have been affected to listening
5479 * sockets
5480 */
5481 if (!(global.mode & MODE_QUIET)) {
5482 /* detach from the tty */
5483 fclose(stdin); fclose(stdout); fclose(stderr);
5484 close(0); close(1); close(2); /* close all fd's */
5485 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
5486 }
willy tarreaua1598082005-12-17 13:08:06 +01005487 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01005488 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01005489 }
5490
willy tarreau0f7af912005-12-17 12:21:26 +01005491 select_loop();
5492
5493 exit(0);
5494}