blob: 91d597e3e14ee7c6dcc9c3670d3e42974f93e579 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreaudd07e972005-12-18 00:48:48 +01003 * 2000-2004 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
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 tarreaudd07e972005-12-18 00:48:48 +010056#define HAPROXY_VERSION "1.2.1"
57#define HAPROXY_DATE "2004/04/18"
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
willy tarreaudd07e972005-12-18 00:48:48 +0100296#define MODE_CHECK 32
willy tarreau5cbea6f2005-12-17 12:48:26 +0100297
298/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100299#define SRV_RUNNING 1 /* the server is UP */
300#define SRV_BACKUP 2 /* this server is a backup server */
301#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0f7af912005-12-17 12:21:26 +0100302
willy tarreaue39cd132005-12-17 13:00:18 +0100303/* what to do when a header matches a regex */
304#define ACT_ALLOW 0 /* allow the request */
305#define ACT_REPLACE 1 /* replace the matching header */
306#define ACT_REMOVE 2 /* remove the matching header */
307#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100308#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100309
willy tarreau9fe663a2005-12-17 13:02:59 +0100310/* configuration sections */
311#define CFG_NONE 0
312#define CFG_GLOBAL 1
313#define CFG_LISTEN 2
314
willy tarreaua1598082005-12-17 13:08:06 +0100315/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100316#define LW_DATE 1 /* date */
317#define LW_CLIP 2 /* CLient IP */
318#define LW_SVIP 4 /* SerVer IP */
319#define LW_SVID 8 /* server ID */
320#define LW_REQ 16 /* http REQuest */
321#define LW_RESP 32 /* http RESPonse */
322#define LW_PXIP 64 /* proxy IP */
323#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100324#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100325
willy tarreau0f7af912005-12-17 12:21:26 +0100326/*********************************************************************/
327
328#define LIST_HEAD(a) ((void *)(&(a)))
329
330/*********************************************************************/
331
332struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100333 struct hdr_exp *next;
334 regex_t *preg; /* expression to look for */
335 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
336 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100337};
338
339struct buffer {
340 unsigned int l; /* data length */
341 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100342 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100343 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100344 char data[BUFSIZE];
345};
346
347struct server {
348 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100349 int state; /* server state (SRV_*) */
350 int cklen; /* the len of the cookie, to speed up checks */
351 char *cookie; /* the id set in the cookie */
352 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100353 struct sockaddr_in addr; /* the address to connect to */
willy tarreaua41a8b42005-12-17 14:02:24 +0100354 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100355 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100356 int rise, fall; /* time in iterations */
357 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100358 int result; /* 0 = connect OK, -1 = connect KO */
359 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100360 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100361};
362
willy tarreau5cbea6f2005-12-17 12:48:26 +0100363/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100364struct task {
365 struct task *next, *prev; /* chaining ... */
366 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100367 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100368 int state; /* task state : IDLE or RUNNING */
369 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100370 int (*process)(struct task *t); /* the function which processes the task */
371 void *context; /* the task's context */
372};
373
374/* WARNING: if new fields are added, they must be initialized in event_accept() */
375struct session {
376 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100377 /* application specific below */
378 struct timeval crexpire; /* expiration date for a client read */
379 struct timeval cwexpire; /* expiration date for a client write */
380 struct timeval srexpire; /* expiration date for a server read */
381 struct timeval swexpire; /* expiration date for a server write */
382 struct timeval cnexpire; /* expiration date for a connect */
383 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
384 struct proxy *proxy; /* the proxy this socket belongs to */
385 int cli_fd; /* the client side fd */
386 int srv_fd; /* the server side fd */
387 int cli_state; /* state of the client side */
388 int srv_state; /* state of the server side */
389 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100390 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100391 struct buffer *req; /* request buffer */
392 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100393 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100394 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100395 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100396 struct {
397 int logwait; /* log fields waiting to be collected : LW_* */
398 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
399 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
400 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
401 long t_data; /* delay before the first data byte from the server ... */
402 unsigned long t_close; /* total session duration */
403 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100404 char *cli_cookie; /* cookie presented by the client, in capture mode */
405 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100406 int status; /* HTTP status from the server, negative if from proxy */
407 long long bytes; /* number of bytes transferred from the server */
408 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100409 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100410};
411
willy tarreaua41a8b42005-12-17 14:02:24 +0100412struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100413 int fd; /* the listen socket */
414 struct sockaddr_storage addr; /* the address we listen to */
415 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100416};
417
418
willy tarreau0f7af912005-12-17 12:21:26 +0100419struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100420 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100421 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100422 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100423 struct server *srv, *cursrv; /* known servers, current server */
424 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100425 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100426 int cookie_len; /* strlen(cookie_len), computed only once */
427 char *capture_name; /* beginning of the name of the cookie to capture */
428 int capture_namelen; /* length of the cookie name to match */
429 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100430 int clitimeout; /* client I/O timeout (in milliseconds) */
431 int srvtimeout; /* server I/O timeout (in milliseconds) */
432 int contimeout; /* connect timeout (in milliseconds) */
433 char *id; /* proxy id */
434 int nbconn; /* # of active sessions */
435 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100436 int conn_retries; /* maximum number of connect retries */
437 int options; /* PR_O_REDISP, PR_O_TRANSP */
438 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100439 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100440 struct proxy *next;
441 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
442 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100443 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100444 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100445 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100446 int nb_reqadd, nb_rspadd;
447 struct hdr_exp *req_exp; /* regular expressions for request headers */
448 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
449 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100450 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100451 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
452 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100453 struct {
454 char *msg400; /* message for error 400 */
455 int len400; /* message length for error 400 */
456 char *msg403; /* message for error 403 */
457 int len403; /* message length for error 403 */
458 char *msg408; /* message for error 408 */
459 int len408; /* message length for error 408 */
460 char *msg500; /* message for error 500 */
461 int len500; /* message length for error 500 */
462 char *msg502; /* message for error 502 */
463 int len502; /* message length for error 502 */
464 char *msg503; /* message for error 503 */
465 int len503; /* message length for error 503 */
466 char *msg504; /* message for error 504 */
467 int len504; /* message length for error 504 */
468 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100469};
470
471/* info about one given fd */
472struct fdtab {
473 int (*read)(int fd); /* read function */
474 int (*write)(int fd); /* write function */
475 struct task *owner; /* the session (or proxy) associated with this fd */
476 int state; /* the state of this fd */
477};
478
479/*********************************************************************/
480
willy tarreau0f7af912005-12-17 12:21:26 +0100481int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100482char *cfg_cfgfile = NULL; /* configuration file */
483char *progname = NULL; /* program name */
484int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100485
486/* global options */
487static struct {
488 int uid;
489 int gid;
490 int nbproc;
491 int maxconn;
492 int maxsock; /* max # of sockets */
493 int mode;
494 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100495 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100496 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100497 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100498 struct sockaddr_in logsrv1, logsrv2;
499} global = {
500 logfac1 : -1,
501 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100502 loglev1 : 7, /* max syslog level : debug */
503 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100504 /* others NULL OK */
505};
506
willy tarreau0f7af912005-12-17 12:21:26 +0100507/*********************************************************************/
508
509fd_set *ReadEvent,
510 *WriteEvent,
511 *StaticReadEvent,
512 *StaticWriteEvent;
513
514void **pool_session = NULL,
515 **pool_buffer = NULL,
516 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100517 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100518 **pool_task = NULL,
519 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100520
521struct proxy *proxy = NULL; /* list of all existing proxies */
522struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100523struct task *rq = NULL; /* global run queue */
524struct task wait_queue = { /* global wait queue */
525 prev:LIST_HEAD(wait_queue),
526 next:LIST_HEAD(wait_queue)
527};
willy tarreau0f7af912005-12-17 12:21:26 +0100528
willy tarreau0f7af912005-12-17 12:21:26 +0100529static int totalconn = 0; /* total # of terminated sessions */
530static int actconn = 0; /* # of active sessions */
531static int maxfd = 0; /* # of the highest fd + 1 */
532static int listeners = 0; /* # of listeners */
533static int stopping = 0; /* non zero means stopping in progress */
534static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100535static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100536
537static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100538/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100539static char trash[BUFSIZE];
540
willy tarreaudd07e972005-12-18 00:48:48 +0100541const int zero = 0;
542const int one = 1;
543
willy tarreau0f7af912005-12-17 12:21:26 +0100544/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100545 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100546 */
547
548#define MAX_SYSLOG_LEN 1024
549#define NB_LOG_FACILITIES 24
550const char *log_facilities[NB_LOG_FACILITIES] = {
551 "kern", "user", "mail", "daemon",
552 "auth", "syslog", "lpr", "news",
553 "uucp", "cron", "auth2", "ftp",
554 "ntp", "audit", "alert", "cron2",
555 "local0", "local1", "local2", "local3",
556 "local4", "local5", "local6", "local7"
557};
558
559
560#define NB_LOG_LEVELS 8
561const char *log_levels[NB_LOG_LEVELS] = {
562 "emerg", "alert", "crit", "err",
563 "warning", "notice", "info", "debug"
564};
565
566#define SYSLOG_PORT 514
567
568const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
569 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100570
571const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
572const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
573const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
574const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
575 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
576 unknown, Set-cookie Rewritten */
577
willy tarreau0f7af912005-12-17 12:21:26 +0100578#define MAX_HOSTNAME_LEN 32
579static char hostname[MAX_HOSTNAME_LEN] = "";
580
willy tarreau8337c6b2005-12-17 13:41:01 +0100581const char *HTTP_302 =
582 "HTTP/1.0 302 Found\r\n"
583 "Cache-Control: no-cache\r\n"
584 "Connection: close\r\n"
585 "Location: "; /* not terminated since it will be concatenated with the URL */
586
willy tarreaua1598082005-12-17 13:08:06 +0100587const char *HTTP_400 =
588 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100589 "Cache-Control: no-cache\r\n"
590 "Connection: close\r\n"
591 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100592 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100593
willy tarreaua1598082005-12-17 13:08:06 +0100594const char *HTTP_403 =
595 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100596 "Cache-Control: no-cache\r\n"
597 "Connection: close\r\n"
598 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100599 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
600
willy tarreau8337c6b2005-12-17 13:41:01 +0100601const char *HTTP_408 =
602 "HTTP/1.0 408 Request Time-out\r\n"
603 "Cache-Control: no-cache\r\n"
604 "Connection: close\r\n"
605 "\r\n"
606 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
607
willy tarreau750a4722005-12-17 13:21:24 +0100608const char *HTTP_500 =
609 "HTTP/1.0 500 Server Error\r\n"
610 "Cache-Control: no-cache\r\n"
611 "Connection: close\r\n"
612 "\r\n"
613 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100614
615const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100616 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100617 "Cache-Control: no-cache\r\n"
618 "Connection: close\r\n"
619 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100620 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
621
622const char *HTTP_503 =
623 "HTTP/1.0 503 Service Unavailable\r\n"
624 "Cache-Control: no-cache\r\n"
625 "Connection: close\r\n"
626 "\r\n"
627 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
628
629const char *HTTP_504 =
630 "HTTP/1.0 504 Gateway Time-out\r\n"
631 "Cache-Control: no-cache\r\n"
632 "Connection: close\r\n"
633 "\r\n"
634 "<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 +0100635
willy tarreau0f7af912005-12-17 12:21:26 +0100636/*********************************************************************/
637/* statistics ******************************************************/
638/*********************************************************************/
639
willy tarreau750a4722005-12-17 13:21:24 +0100640#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100641static int stats_tsk_lsrch, stats_tsk_rsrch,
642 stats_tsk_good, stats_tsk_right, stats_tsk_left,
643 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100644#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100645
646
647/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100648/* debugging *******************************************************/
649/*********************************************************************/
650#ifdef DEBUG_FULL
651static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
652static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
653#endif
654
655/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100656/* function prototypes *********************************************/
657/*********************************************************************/
658
659int event_accept(int fd);
660int event_cli_read(int fd);
661int event_cli_write(int fd);
662int event_srv_read(int fd);
663int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100664int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100665
666/*********************************************************************/
667/* general purpose functions ***************************************/
668/*********************************************************************/
669
670void display_version() {
671 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreaudd07e972005-12-18 00:48:48 +0100672 printf("Copyright 2000-2004 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100673}
674
675/*
676 * This function prints the command line usage and exits
677 */
678void usage(char *name) {
679 display_version();
680 fprintf(stderr,
681 "Usage : %s -f <cfgfile> [ -vd"
682#if STATTIME > 0
683 "sl"
684#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100685 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100686 " -v displays version\n"
687 " -d enters debug mode\n"
688#if STATTIME > 0
689 " -s enables statistics output\n"
690 " -l enables long statistics format\n"
691#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100692 " -D goes daemon ; implies -q\n"
693 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100694 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100695 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100696 " -N sets the default, per-proxy maximum # of connections (%d)\n"
697 " -p writes pids of all children to this file\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100698 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100699 exit(1);
700}
701
702
703/*
704 * Displays the message on stderr with the date and pid.
705 */
706void Alert(char *fmt, ...) {
707 va_list argp;
708 struct timeval tv;
709 struct tm *tm;
710
willy tarreau9fe663a2005-12-17 13:02:59 +0100711 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100712 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100713
willy tarreau5cbea6f2005-12-17 12:48:26 +0100714 gettimeofday(&tv, NULL);
715 tm=localtime(&tv.tv_sec);
716 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100717 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100718 vfprintf(stderr, fmt, argp);
719 fflush(stderr);
720 va_end(argp);
721 }
willy tarreau0f7af912005-12-17 12:21:26 +0100722}
723
724
725/*
726 * Displays the message on stderr with the date and pid.
727 */
728void Warning(char *fmt, ...) {
729 va_list argp;
730 struct timeval tv;
731 struct tm *tm;
732
willy tarreau9fe663a2005-12-17 13:02:59 +0100733 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100734 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100735
willy tarreau5cbea6f2005-12-17 12:48:26 +0100736 gettimeofday(&tv, NULL);
737 tm=localtime(&tv.tv_sec);
738 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100739 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100740 vfprintf(stderr, fmt, argp);
741 fflush(stderr);
742 va_end(argp);
743 }
744}
745
746/*
747 * Displays the message on <out> only if quiet mode is not set.
748 */
749void qfprintf(FILE *out, char *fmt, ...) {
750 va_list argp;
751
willy tarreau9fe663a2005-12-17 13:02:59 +0100752 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100753 va_start(argp, fmt);
754 vfprintf(out, fmt, argp);
755 fflush(out);
756 va_end(argp);
757 }
willy tarreau0f7af912005-12-17 12:21:26 +0100758}
759
760
761/*
762 * converts <str> to a struct sockaddr_in* which is locally allocated.
763 * The format is "addr:port", where "addr" can be empty or "*" to indicate
764 * INADDR_ANY.
765 */
766struct sockaddr_in *str2sa(char *str) {
767 static struct sockaddr_in sa;
768 char *c;
769 int port;
770
willy tarreaua1598082005-12-17 13:08:06 +0100771 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100772 str=strdup(str);
773
774 if ((c=strrchr(str,':')) != NULL) {
775 *c++=0;
776 port=atol(c);
777 }
778 else
779 port=0;
780
781 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
782 sa.sin_addr.s_addr = INADDR_ANY;
783 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100784 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100785 struct hostent *he;
786
787 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100788 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100789 }
790 else
791 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
792 }
793 sa.sin_port=htons(port);
794 sa.sin_family=AF_INET;
795
796 free(str);
797 return &sa;
798}
799
willy tarreau9fe663a2005-12-17 13:02:59 +0100800
801/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100802 * converts <str> to a list of listeners which are dynamically allocated.
803 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
804 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
805 * - <port> is a numerical port from 1 to 65535 ;
806 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
807 * This can be repeated as many times as necessary, separated by a coma.
808 * The <tail> argument is a pointer to a current list which should be appended
809 * to the tail of the new list. The pointer to the new list is returned.
810 */
811struct listener *str2listener(char *str, struct listener *tail) {
812 struct listener *l;
813 char *c, *next, *range, *dupstr;
814 int port, end;
815
816 next = dupstr = strdup(str);
willy tarreaua41a8b42005-12-17 14:02:24 +0100817 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100818 struct sockaddr_storage ss;
819
willy tarreaua41a8b42005-12-17 14:02:24 +0100820 str = next;
821 /* 1) look for the end of the first address */
822 if ((next = strrchr(str, ',')) != NULL) {
823 *next++ = 0;
824 }
825
willy tarreau8a86dbf2005-12-18 00:45:59 +0100826 /* 2) look for the addr/port delimiter, it's the last colon. */
827 if ((range = strrchr(str, ':')) == NULL) {
828 Alert("Missing port number: '%s'\n", str);
829 }
830
831 *range++ = 0;
832
833 if (strrchr(str, ':') != NULL) {
834 /* IPv6 address contains ':' */
835 memset(&ss, 0, sizeof(ss));
836 ss.ss_family = AF_INET6;
837
838 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
839 Alert("Invalid server address: '%s'\n", str);
840 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100841 }
842 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100843 memset(&ss, 0, sizeof(ss));
844 ss.ss_family = AF_INET;
845
846 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
847 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
848 }
849 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
850 struct hostent *he;
851
852 if ((he = gethostbyname(str)) == NULL) {
853 Alert("Invalid server name: '%s'\n", str);
854 }
855 else
856 ((struct sockaddr_in *)&ss)->sin_addr =
857 *(struct in_addr *) *(he->h_addr_list);
858 }
859 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100860
861 /* 3) look for the port-end delimiter */
862 if ((c = strchr(range, '-')) != NULL) {
863 *c++ = 0;
864 end = atol(c);
865 }
866 else {
867 end = atol(range);
868 }
869
870 for (port = atol(range); port <= end; port++) {
871 l = (struct listener *)calloc(1, sizeof(struct listener));
872 l->next = tail;
873 tail = l;
874
willy tarreau8a86dbf2005-12-18 00:45:59 +0100875 l->addr = ss;
876 if (ss.ss_family == AF_INET6)
877 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
878 else
879 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
880
willy tarreaua41a8b42005-12-17 14:02:24 +0100881 } /* end for(port) */
882 } /* end while(next) */
883 free(dupstr);
884 return tail;
885}
886
887
888/*
willy tarreau9fe663a2005-12-17 13:02:59 +0100889 * This function sends a syslog message to both log servers of a proxy,
890 * or to global log servers if the proxy is NULL.
891 * It also tries not to waste too much time computing the message header.
892 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100893 */
894void send_log(struct proxy *p, int level, char *message, ...) {
895 static int logfd = -1; /* syslog UDP socket */
896 static long tvsec = -1; /* to force the string to be initialized */
897 struct timeval tv;
898 va_list argp;
899 static char logmsg[MAX_SYSLOG_LEN];
900 static char *dataptr = NULL;
901 int fac_level;
902 int hdr_len, data_len;
903 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +0100904 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +0100905 int nbloggers = 0;
906 char *log_ptr;
907
908 if (logfd < 0) {
909 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
910 return;
911 }
912
913 if (level < 0 || progname == NULL || message == NULL)
914 return;
915
916 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100917 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100918 /* this string is rebuild only once a second */
919 struct tm *tm = localtime(&tv.tv_sec);
920 tvsec = tv.tv_sec;
921
willy tarreauc29948c2005-12-17 13:10:27 +0100922 hdr_len = snprintf(logmsg, sizeof(logmsg),
923 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
924 monthname[tm->tm_mon],
925 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
926 progname, pid);
927 /* WARNING: depending upon implementations, snprintf may return
928 * either -1 or the number of bytes that would be needed to store
929 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100930 */
willy tarreauc29948c2005-12-17 13:10:27 +0100931 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
932 hdr_len = sizeof(logmsg);
933
934 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100935 }
936
937 va_start(argp, message);
938 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100939 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
940 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100941 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100942 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100943
944 if (p == NULL) {
945 if (global.logfac1 >= 0) {
946 sa[nbloggers] = &global.logsrv1;
947 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100948 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100949 nbloggers++;
950 }
951 if (global.logfac2 >= 0) {
952 sa[nbloggers] = &global.logsrv2;
953 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100954 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100955 nbloggers++;
956 }
957 } else {
958 if (p->logfac1 >= 0) {
959 sa[nbloggers] = &p->logsrv1;
960 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100961 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100962 nbloggers++;
963 }
964 if (p->logfac2 >= 0) {
965 sa[nbloggers] = &p->logsrv2;
966 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100967 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100968 nbloggers++;
969 }
970 }
971
972 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +0100973 /* we can filter the level of the messages that are sent to each logger */
974 if (level > loglevel[nbloggers])
975 continue;
976
willy tarreauc29948c2005-12-17 13:10:27 +0100977 /* For each target, we may have a different facility.
978 * We can also have a different log level for each message.
979 * This induces variations in the message header length.
980 * Since we don't want to recompute it each time, nor copy it every
981 * time, we only change the facility in the pre-computed header,
982 * and we change the pointer to the header accordingly.
983 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100984 fac_level = (facilities[nbloggers] << 3) + level;
985 log_ptr = logmsg + 3; /* last digit of the log level */
986 do {
987 *log_ptr = '0' + fac_level % 10;
988 fac_level /= 10;
989 log_ptr--;
990 } while (fac_level && log_ptr > logmsg);
991 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100992
willy tarreauc29948c2005-12-17 13:10:27 +0100993 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100994
995#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100996 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100997 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
998#else
willy tarreauc29948c2005-12-17 13:10:27 +0100999 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001000 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1001#endif
1002 }
willy tarreau0f7af912005-12-17 12:21:26 +01001003}
1004
1005
1006/* sets <tv> to the current time */
1007static inline struct timeval *tv_now(struct timeval *tv) {
1008 if (tv)
1009 gettimeofday(tv, NULL);
1010 return tv;
1011}
1012
1013/*
1014 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1015 */
1016static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1017 if (!tv || !from)
1018 return NULL;
1019 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1020 tv->tv_sec = from->tv_sec + (ms/1000);
1021 while (tv->tv_usec >= 1000000) {
1022 tv->tv_usec -= 1000000;
1023 tv->tv_sec++;
1024 }
1025 return tv;
1026}
1027
1028/*
1029 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1030 */
1031static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001032 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001033 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001034 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001035 return 1;
1036 else if (tv1->tv_usec < tv2->tv_usec)
1037 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001038 else if (tv1->tv_usec > tv2->tv_usec)
1039 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001040 else
1041 return 0;
1042}
1043
1044/*
1045 * returns the absolute difference, in ms, between tv1 and tv2
1046 */
1047unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1048 int cmp;
1049 unsigned long ret;
1050
1051
willy tarreauef900ab2005-12-17 12:52:52 +01001052 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001053 if (!cmp)
1054 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001055 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001056 struct timeval *tmp = tv1;
1057 tv1 = tv2;
1058 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001059 }
willy tarreauef900ab2005-12-17 12:52:52 +01001060 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001061 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001062 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001063 else
willy tarreauef900ab2005-12-17 12:52:52 +01001064 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001065 return (unsigned long) ret;
1066}
1067
1068/*
willy tarreau750a4722005-12-17 13:21:24 +01001069 * returns the difference, in ms, between tv1 and tv2
1070 */
1071static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1072 unsigned long ret;
1073
willy tarreau6e682ce2005-12-17 13:26:49 +01001074 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1075 if (tv2->tv_usec > tv1->tv_usec)
1076 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001077 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001078 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001079 return (unsigned long) ret;
1080}
1081
1082/*
willy tarreau0f7af912005-12-17 12:21:26 +01001083 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1084 */
1085static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001086 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001087 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001088 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001089 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1090 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001091 else
1092 return 0;
1093 }
willy tarreau0f7af912005-12-17 12:21:26 +01001094 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;
willy tarreau750a4722005-12-17 13:21:24 +01001097 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1098 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1099 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001100 else
1101 return 0;
1102}
1103
1104/*
1105 * returns the remaining time between tv1=now and event=tv2
1106 * if tv2 is passed, 0 is returned.
1107 */
1108static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1109 unsigned long ret;
1110
willy tarreau0f7af912005-12-17 12:21:26 +01001111 if (tv_cmp_ms(tv1, tv2) >= 0)
1112 return 0; /* event elapsed */
1113
willy tarreauef900ab2005-12-17 12:52:52 +01001114 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001115 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001116 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001117 else
willy tarreauef900ab2005-12-17 12:52:52 +01001118 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001119 return (unsigned long) ret;
1120}
1121
1122
1123/*
1124 * zeroes a struct timeval
1125 */
1126
1127static inline struct timeval *tv_eternity(struct timeval *tv) {
1128 tv->tv_sec = tv->tv_usec = 0;
1129 return tv;
1130}
1131
1132/*
1133 * returns 1 if tv is null, else 0
1134 */
1135static inline int tv_iseternity(struct timeval *tv) {
1136 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1137 return 1;
1138 else
1139 return 0;
1140}
1141
1142/*
1143 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1144 * considering that 0 is the eternity.
1145 */
1146static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1147 if (tv_iseternity(tv1))
1148 if (tv_iseternity(tv2))
1149 return 0; /* same */
1150 else
1151 return 1; /* tv1 later than tv2 */
1152 else if (tv_iseternity(tv2))
1153 return -1; /* tv2 later than tv1 */
1154
1155 if (tv1->tv_sec > tv2->tv_sec)
1156 return 1;
1157 else if (tv1->tv_sec < tv2->tv_sec)
1158 return -1;
1159 else if (tv1->tv_usec > tv2->tv_usec)
1160 return 1;
1161 else if (tv1->tv_usec < tv2->tv_usec)
1162 return -1;
1163 else
1164 return 0;
1165}
1166
1167/*
1168 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1169 * considering that 0 is the eternity.
1170 */
1171static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1172 if (tv_iseternity(tv1))
1173 if (tv_iseternity(tv2))
1174 return 0; /* same */
1175 else
1176 return 1; /* tv1 later than tv2 */
1177 else if (tv_iseternity(tv2))
1178 return -1; /* tv2 later than tv1 */
1179
willy tarreauefae1842005-12-17 12:51:03 +01001180 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001181 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001182 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001183 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001184 return -1;
1185 else
1186 return 0;
1187 }
1188 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001189 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001190 return 1;
1191 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001192 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001193 return -1;
1194 else
1195 return 0;
1196}
1197
1198/*
1199 * returns the first event between tv1 and tv2 into tvmin.
1200 * a zero tv is ignored. tvmin is returned.
1201 */
1202static inline struct timeval *tv_min(struct timeval *tvmin,
1203 struct timeval *tv1, struct timeval *tv2) {
1204
1205 if (tv_cmp2(tv1, tv2) <= 0)
1206 *tvmin = *tv1;
1207 else
1208 *tvmin = *tv2;
1209
1210 return tvmin;
1211}
1212
1213
1214
1215/***********************************************************/
1216/* fd management ***************************************/
1217/***********************************************************/
1218
1219
1220
willy tarreau5cbea6f2005-12-17 12:48:26 +01001221/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1222 * The file descriptor is also closed.
1223 */
willy tarreau0f7af912005-12-17 12:21:26 +01001224static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001225 FD_CLR(fd, StaticReadEvent);
1226 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001227 close(fd);
1228 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001229
1230 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1231 maxfd--;
1232}
1233
1234/* recomputes the maxfd limit from the fd */
1235static inline void fd_insert(int fd) {
1236 if (fd+1 > maxfd)
1237 maxfd = fd+1;
1238}
1239
1240/*************************************************************/
1241/* task management ***************************************/
1242/*************************************************************/
1243
willy tarreau5cbea6f2005-12-17 12:48:26 +01001244/* puts the task <t> in run queue <q>, and returns <t> */
1245static inline struct task *task_wakeup(struct task **q, struct task *t) {
1246 if (t->state == TASK_RUNNING)
1247 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001248 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001249 t->rqnext = *q;
1250 t->state = TASK_RUNNING;
1251 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001252 }
1253}
1254
willy tarreau5cbea6f2005-12-17 12:48:26 +01001255/* removes the task <t> from the queue <q>
1256 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001257 * set the run queue to point to the next one, and return it
1258 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001259static inline struct task *task_sleep(struct task **q, struct task *t) {
1260 if (t->state == TASK_RUNNING) {
1261 *q = t->rqnext;
1262 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001263 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001264 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001265}
1266
1267/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001268 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001269 * from the run queue. A pointer to the task itself is returned.
1270 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001271static inline struct task *task_delete(struct task *t) {
1272 t->prev->next = t->next;
1273 t->next->prev = t->prev;
1274 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001275}
1276
1277/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001278 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001279 */
1280static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001281 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001282}
1283
willy tarreau5cbea6f2005-12-17 12:48:26 +01001284/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001285 * may be only moved or left where it was, depending on its timing requirements.
1286 * <task> is returned.
1287 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001288struct task *task_queue(struct task *task) {
1289 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001290 struct task *start_from;
1291
1292 /* first, test if the task was already in a list */
1293 if (task->prev == NULL) {
1294 // start_from = list;
1295 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001296#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001297 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001298#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001299 /* insert the unlinked <task> into the list, searching back from the last entry */
1300 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1301 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001302#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001303 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001304#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001305 }
1306
1307 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1308 // start_from = start_from->next;
1309 // stats_tsk_nsrch++;
1310 // }
1311 }
1312 else if (task->prev == list ||
1313 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1314 start_from = task->next;
1315 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001316#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001317 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001318#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001319 return task; /* it's already in the right place */
1320 }
1321
willy tarreau750a4722005-12-17 13:21:24 +01001322#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001323 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001324#endif
1325
1326 /* if the task is not at the right place, there's little chance that
1327 * it has only shifted a bit, and it will nearly always be queued
1328 * at the end of the list because of constant timeouts
1329 * (observed in real case).
1330 */
1331#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1332 start_from = list->prev; /* assume we'll queue to the end of the list */
1333 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1334 start_from = start_from->prev;
1335#if STATTIME > 0
1336 stats_tsk_lsrch++;
1337#endif
1338 }
1339#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001340 /* insert the unlinked <task> into the list, searching after position <start_from> */
1341 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1342 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001343#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001344 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001345#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001346 }
willy tarreau750a4722005-12-17 13:21:24 +01001347#endif /* WE_REALLY_... */
1348
willy tarreau0f7af912005-12-17 12:21:26 +01001349 /* we need to unlink it now */
1350 task_delete(task);
1351 }
1352 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001353#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001354 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001355#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001356#ifdef LEFT_TO_TOP /* not very good */
1357 start_from = list;
1358 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1359 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001360#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001361 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001362#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001363 }
1364#else
1365 start_from = task->prev->prev; /* valid because of the previous test above */
1366 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1367 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001368#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001369 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001370#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001371 }
1372#endif
1373 /* we need to unlink it now */
1374 task_delete(task);
1375 }
1376 task->prev = start_from;
1377 task->next = start_from->next;
1378 task->next->prev = task;
1379 start_from->next = task;
1380 return task;
1381}
1382
1383
1384/*********************************************************************/
1385/* more specific functions ***************************************/
1386/*********************************************************************/
1387
1388/* some prototypes */
1389static int maintain_proxies(void);
1390
willy tarreau5cbea6f2005-12-17 12:48:26 +01001391/* this either returns the sockname or the original destination address. Code
1392 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1393 */
1394static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001395#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001396 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1397#else
willy tarreaua1598082005-12-17 13:08:06 +01001398#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001399 return getsockname(fd, (struct sockaddr *)sa, salen);
1400#else
1401 return -1;
1402#endif
1403#endif
1404}
1405
1406/*
1407 * frees the context associated to a session. It must have been removed first.
1408 */
1409static inline void session_free(struct session *s) {
1410 if (s->req)
1411 pool_free(buffer, s->req);
1412 if (s->rep)
1413 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001414 if (s->logs.uri)
1415 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001416 if (s->logs.cli_cookie)
1417 pool_free(capture, s->logs.cli_cookie);
1418 if (s->logs.srv_cookie)
1419 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001420
willy tarreau5cbea6f2005-12-17 12:48:26 +01001421 pool_free(session, s);
1422}
1423
willy tarreau0f7af912005-12-17 12:21:26 +01001424
1425/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001426 * This function tries to find a running server for the proxy <px>. A first
1427 * pass looks for active servers, and if none is found, a second pass also
1428 * looks for backup servers.
1429 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1430 */
1431static inline struct server *find_server(struct proxy *px) {
1432 struct server *srv = px->cursrv;
1433 int ignore_backup = 1;
1434
1435 do {
1436 do {
1437 if (srv == NULL)
1438 srv = px->srv;
1439 if (srv->state & SRV_RUNNING
1440 && !((srv->state & SRV_BACKUP) && ignore_backup))
1441 return srv;
1442 srv = srv->next;
1443 } while (srv != px->cursrv);
1444 } while (ignore_backup--);
1445 return NULL;
1446}
1447
1448/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001449 * This function initiates a connection to the current server (s->srv) if (s->direct)
1450 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001451 * it's OK, -1 if it's impossible.
1452 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001453int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001454 int fd;
1455
1456 // fprintf(stderr,"connect_server : s=%p\n",s);
1457
willy tarreaue39cd132005-12-17 13:00:18 +01001458 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001459 s->srv_addr = s->srv->addr;
1460 }
1461 else if (s->proxy->options & PR_O_BALANCE) {
1462 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001463 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001464
willy tarreau8337c6b2005-12-17 13:41:01 +01001465 srv = find_server(s->proxy);
1466
1467 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001468 return -1;
1469
willy tarreau8337c6b2005-12-17 13:41:01 +01001470 s->srv_addr = srv->addr;
1471 s->srv = srv;
1472 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001473 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001474 else /* unknown balancing algorithm */
1475 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001476 }
willy tarreaua1598082005-12-17 13:08:06 +01001477 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001478 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001479 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001480 }
1481 else if (s->proxy->options & PR_O_TRANSP) {
1482 /* in transparent mode, use the original dest addr if no dispatch specified */
1483 int salen = sizeof(struct sockaddr_in);
1484 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1485 qfprintf(stderr, "Cannot get original server address.\n");
1486 return -1;
1487 }
1488 }
willy tarreau0f7af912005-12-17 12:21:26 +01001489
willy tarreaua41a8b42005-12-17 14:02:24 +01001490 /* if this server remaps proxied ports, we'll use
1491 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001492 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001493 struct sockaddr_in sockname;
1494 int namelen;
1495
1496 namelen = sizeof(sockname);
1497 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1498 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1499 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1500 }
1501
willy tarreau0f7af912005-12-17 12:21:26 +01001502 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001503 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001504 return -1;
1505 }
1506
willy tarreau9fe663a2005-12-17 13:02:59 +01001507 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001508 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1509 close(fd);
1510 return -1;
1511 }
1512
willy tarreau0f7af912005-12-17 12:21:26 +01001513 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1514 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001515 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001516 close(fd);
1517 return -1;
1518 }
1519
willy tarreaua1598082005-12-17 13:08:06 +01001520 /* allow specific binding */
1521 if (s->proxy->options & PR_O_BIND_SRC &&
1522 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1523 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1524 close(fd);
1525 return -1;
1526 }
1527
willy tarreau0f7af912005-12-17 12:21:26 +01001528 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1529 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001530 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001531 close(fd);
1532 return -1;
1533 }
1534 else if (errno != EALREADY && errno != EISCONN) {
1535 close(fd);
1536 return -1;
1537 }
1538 }
1539
willy tarreau5cbea6f2005-12-17 12:48:26 +01001540 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001541 fdtab[fd].read = &event_srv_read;
1542 fdtab[fd].write = &event_srv_write;
1543 fdtab[fd].state = FD_STCONN; /* connection in progress */
1544
1545 FD_SET(fd, StaticWriteEvent); /* for connect status */
1546
1547 fd_insert(fd);
1548
1549 if (s->proxy->contimeout)
1550 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1551 else
1552 tv_eternity(&s->cnexpire);
1553 return 0;
1554}
1555
1556/*
1557 * this function is called on a read event from a client socket.
1558 * It returns 0.
1559 */
1560int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001561 struct task *t = fdtab[fd].owner;
1562 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001563 struct buffer *b = s->req;
1564 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001565
1566 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1567
willy tarreau0f7af912005-12-17 12:21:26 +01001568 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001569 while (1) {
1570 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1571 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001572 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001573 }
1574 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001575 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001576 }
1577 else {
1578 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001579 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1580 * since it means that the rewrite protection has been removed. This
1581 * implies that the if statement can be removed.
1582 */
1583 if (max > b->rlim - b->data)
1584 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001585 }
1586
1587 if (max == 0) { /* not anymore room to store data */
1588 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001589 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001590 }
1591
willy tarreau3242e862005-12-17 12:27:53 +01001592#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001593 {
1594 int skerr, lskerr;
1595
1596 lskerr = sizeof(skerr);
1597 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1598 if (skerr)
1599 ret = -1;
1600 else
1601 ret = recv(fd, b->r, max, 0);
1602 }
willy tarreau3242e862005-12-17 12:27:53 +01001603#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001604 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001605#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001606 if (ret > 0) {
1607 b->r += ret;
1608 b->l += ret;
1609 s->res_cr = RES_DATA;
1610
1611 if (b->r == b->data + BUFSIZE) {
1612 b->r = b->data; /* wrap around the buffer */
1613 }
willy tarreaua1598082005-12-17 13:08:06 +01001614
1615 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001616 /* we hope to read more data or to get a close on next round */
1617 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001618 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001619 else if (ret == 0) {
1620 s->res_cr = RES_NULL;
1621 break;
1622 }
1623 else if (errno == EAGAIN) {/* ignore EAGAIN */
1624 break;
1625 }
1626 else {
1627 s->res_cr = RES_ERROR;
1628 fdtab[fd].state = FD_STERROR;
1629 break;
1630 }
1631 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001632 }
1633 else {
1634 s->res_cr = RES_ERROR;
1635 fdtab[fd].state = FD_STERROR;
1636 }
1637
willy tarreau5cbea6f2005-12-17 12:48:26 +01001638 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001639 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001640 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1641 else
1642 tv_eternity(&s->crexpire);
1643
1644 task_wakeup(&rq, t);
1645 }
willy tarreau0f7af912005-12-17 12:21:26 +01001646
willy tarreau0f7af912005-12-17 12:21:26 +01001647 return 0;
1648}
1649
1650
1651/*
1652 * this function is called on a read event from a server socket.
1653 * It returns 0.
1654 */
1655int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001656 struct task *t = fdtab[fd].owner;
1657 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001658 struct buffer *b = s->rep;
1659 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001660
1661 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1662
willy tarreau0f7af912005-12-17 12:21:26 +01001663 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001664 while (1) {
1665 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1666 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001667 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001668 }
1669 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001670 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001671 }
1672 else {
1673 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001674 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1675 * since it means that the rewrite protection has been removed. This
1676 * implies that the if statement can be removed.
1677 */
1678 if (max > b->rlim - b->data)
1679 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001680 }
1681
1682 if (max == 0) { /* not anymore room to store data */
1683 FD_CLR(fd, StaticReadEvent);
1684 break;
1685 }
1686
willy tarreau3242e862005-12-17 12:27:53 +01001687#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001688 {
1689 int skerr, lskerr;
1690
1691 lskerr = sizeof(skerr);
1692 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1693 if (skerr)
1694 ret = -1;
1695 else
1696 ret = recv(fd, b->r, max, 0);
1697 }
willy tarreau3242e862005-12-17 12:27:53 +01001698#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001699 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001700#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001701 if (ret > 0) {
1702 b->r += ret;
1703 b->l += ret;
1704 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001705
willy tarreau5cbea6f2005-12-17 12:48:26 +01001706 if (b->r == b->data + BUFSIZE) {
1707 b->r = b->data; /* wrap around the buffer */
1708 }
willy tarreaua1598082005-12-17 13:08:06 +01001709
1710 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001711 /* we hope to read more data or to get a close on next round */
1712 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001713 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001714 else if (ret == 0) {
1715 s->res_sr = RES_NULL;
1716 break;
1717 }
1718 else if (errno == EAGAIN) {/* ignore EAGAIN */
1719 break;
1720 }
1721 else {
1722 s->res_sr = RES_ERROR;
1723 fdtab[fd].state = FD_STERROR;
1724 break;
1725 }
1726 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001727 }
1728 else {
1729 s->res_sr = RES_ERROR;
1730 fdtab[fd].state = FD_STERROR;
1731 }
1732
willy tarreau5cbea6f2005-12-17 12:48:26 +01001733 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001734 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001735 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1736 else
1737 tv_eternity(&s->srexpire);
1738
1739 task_wakeup(&rq, t);
1740 }
willy tarreau0f7af912005-12-17 12:21:26 +01001741
willy tarreau0f7af912005-12-17 12:21:26 +01001742 return 0;
1743}
1744
1745/*
1746 * this function is called on a write event from a client socket.
1747 * It returns 0.
1748 */
1749int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001750 struct task *t = fdtab[fd].owner;
1751 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001752 struct buffer *b = s->rep;
1753 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001754
1755 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1756
1757 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001758 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001759 // max = BUFSIZE; BUG !!!!
1760 max = 0;
1761 }
1762 else if (b->r > b->w) {
1763 max = b->r - b->w;
1764 }
1765 else
1766 max = b->data + BUFSIZE - b->w;
1767
willy tarreau0f7af912005-12-17 12:21:26 +01001768 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001769#ifndef MSG_NOSIGNAL
1770 int skerr, lskerr;
1771#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001772
1773 if (max == 0) {
1774 s->res_cw = RES_NULL;
1775 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001776 tv_eternity(&s->cwexpire);
1777 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001778 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001779 }
1780
willy tarreau3242e862005-12-17 12:27:53 +01001781#ifndef MSG_NOSIGNAL
1782 lskerr=sizeof(skerr);
1783 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1784 if (skerr)
1785 ret = -1;
1786 else
1787 ret = send(fd, b->w, max, MSG_DONTWAIT);
1788#else
willy tarreau0f7af912005-12-17 12:21:26 +01001789 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001790#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001791
1792 if (ret > 0) {
1793 b->l -= ret;
1794 b->w += ret;
1795
1796 s->res_cw = RES_DATA;
1797
1798 if (b->w == b->data + BUFSIZE) {
1799 b->w = b->data; /* wrap around the buffer */
1800 }
1801 }
1802 else if (ret == 0) {
1803 /* nothing written, just make as if we were never called */
1804// s->res_cw = RES_NULL;
1805 return 0;
1806 }
1807 else if (errno == EAGAIN) /* ignore EAGAIN */
1808 return 0;
1809 else {
1810 s->res_cw = RES_ERROR;
1811 fdtab[fd].state = FD_STERROR;
1812 }
1813 }
1814 else {
1815 s->res_cw = RES_ERROR;
1816 fdtab[fd].state = FD_STERROR;
1817 }
1818
willy tarreaub1ff9db2005-12-17 13:51:03 +01001819 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001820 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001821 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
1822 s->crexpire = s->cwexpire;
1823 }
willy tarreau0f7af912005-12-17 12:21:26 +01001824 else
1825 tv_eternity(&s->cwexpire);
1826
willy tarreau5cbea6f2005-12-17 12:48:26 +01001827 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001828 return 0;
1829}
1830
1831
1832/*
1833 * this function is called on a write event from a server socket.
1834 * It returns 0.
1835 */
1836int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001837 struct task *t = fdtab[fd].owner;
1838 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001839 struct buffer *b = s->req;
1840 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001841
1842 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1843
1844 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001845 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001846 // max = BUFSIZE; BUG !!!!
1847 max = 0;
1848 }
1849 else if (b->r > b->w) {
1850 max = b->r - b->w;
1851 }
1852 else
1853 max = b->data + BUFSIZE - b->w;
1854
willy tarreau0f7af912005-12-17 12:21:26 +01001855 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001856#ifndef MSG_NOSIGNAL
1857 int skerr, lskerr;
1858#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001859 if (max == 0) {
1860 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001861 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001862 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001863 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01001864 tv_eternity(&s->swexpire);
1865 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01001866 return 0;
1867 }
1868
willy tarreauef900ab2005-12-17 12:52:52 +01001869
willy tarreau3242e862005-12-17 12:27:53 +01001870#ifndef MSG_NOSIGNAL
1871 lskerr=sizeof(skerr);
1872 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1873 if (skerr)
1874 ret = -1;
1875 else
1876 ret = send(fd, b->w, max, MSG_DONTWAIT);
1877#else
willy tarreau0f7af912005-12-17 12:21:26 +01001878 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001879#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001880 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001881 if (ret > 0) {
1882 b->l -= ret;
1883 b->w += ret;
1884
1885 s->res_sw = RES_DATA;
1886
1887 if (b->w == b->data + BUFSIZE) {
1888 b->w = b->data; /* wrap around the buffer */
1889 }
1890 }
1891 else if (ret == 0) {
1892 /* nothing written, just make as if we were never called */
1893 // s->res_sw = RES_NULL;
1894 return 0;
1895 }
1896 else if (errno == EAGAIN) /* ignore EAGAIN */
1897 return 0;
1898 else {
1899 s->res_sw = RES_ERROR;
1900 fdtab[fd].state = FD_STERROR;
1901 }
1902 }
1903 else {
1904 s->res_sw = RES_ERROR;
1905 fdtab[fd].state = FD_STERROR;
1906 }
1907
willy tarreaub1ff9db2005-12-17 13:51:03 +01001908 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001909 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001910 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
1911 s->srexpire = s->swexpire;
1912 }
willy tarreau0f7af912005-12-17 12:21:26 +01001913 else
1914 tv_eternity(&s->swexpire);
1915
willy tarreau5cbea6f2005-12-17 12:48:26 +01001916 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001917 return 0;
1918}
1919
1920
1921/*
willy tarreaue39cd132005-12-17 13:00:18 +01001922 * returns a message to the client ; the connection is shut down for read,
1923 * and the request is cleared so that no server connection can be initiated.
1924 * The client must be in a valid state for this (HEADER, DATA ...).
1925 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01001926 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001927 */
1928void client_retnclose(struct session *s, int len, const char *msg) {
1929 FD_CLR(s->cli_fd, StaticReadEvent);
1930 FD_SET(s->cli_fd, StaticWriteEvent);
1931 tv_eternity(&s->crexpire);
1932 shutdown(s->cli_fd, SHUT_RD);
1933 s->cli_state = CL_STSHUTR;
1934 strcpy(s->rep->data, msg);
1935 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001936 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001937 s->rep->r += len;
1938 s->req->l = 0;
1939}
1940
1941
1942/*
1943 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01001944 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001945 */
1946void client_return(struct session *s, int len, const char *msg) {
1947 strcpy(s->rep->data, msg);
1948 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001949 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001950 s->rep->r += len;
1951 s->req->l = 0;
1952}
1953
willy tarreau9fe663a2005-12-17 13:02:59 +01001954/*
1955 * send a log for the session when we have enough info about it
1956 */
1957void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001958 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01001959 struct proxy *p = s->proxy;
1960 int log;
1961 char *uri;
1962 char *pxid;
1963 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01001964 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01001965
1966 /* This is a first attempt at a better logging system.
1967 * For now, we rely on send_log() to provide the date, although it obviously
1968 * is the date of the log and not of the request, and most fields are not
1969 * computed.
1970 */
1971
willy tarreaua1598082005-12-17 13:08:06 +01001972 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001973
willy tarreau8a86dbf2005-12-18 00:45:59 +01001974 if (s->cli_addr.ss_family == AF_INET)
1975 inet_ntop(AF_INET,
1976 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1977 pn, sizeof(pn));
1978 else
1979 inet_ntop(AF_INET6,
1980 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
1981 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01001982
willy tarreauc1cae632005-12-17 14:12:23 +01001983 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01001984 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01001985 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01001986
willy tarreauc1cae632005-12-17 14:12:23 +01001987 tm = localtime(&s->logs.tv_accept.tv_sec);
1988 if (p->to_log & LW_REQ) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001989 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
1990 pn,
1991 (s->cli_addr.ss_family == AF_INET) ?
1992 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
1993 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01001994 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1995 tm->tm_hour, tm->tm_min, tm->tm_sec,
1996 pxid, srv,
1997 s->logs.t_request,
1998 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1999 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
2000 s->logs.t_close,
2001 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002002 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2003 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002004 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2005 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2006 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2007 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01002008 uri);
2009 }
2010 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002011 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d %lld %c%c\n",
2012 pn,
2013 (s->cli_addr.ss_family == AF_INET) ?
2014 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2015 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002016 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2017 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002018 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002019 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreaua1598082005-12-17 13:08:06 +01002020 s->logs.t_close,
willy tarreauc1cae632005-12-17 14:12:23 +01002021 s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002022 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01002023 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01002024 }
2025
2026 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002027}
2028
willy tarreaue39cd132005-12-17 13:00:18 +01002029
2030/*
willy tarreau0f7af912005-12-17 12:21:26 +01002031 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002032 * to an accept. It tries to accept as many connections as possible.
2033 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002034 */
2035int event_accept(int fd) {
2036 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002037 struct session *s;
2038 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002039 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002040
willy tarreau5cbea6f2005-12-17 12:48:26 +01002041 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002042 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002043 int laddr = sizeof(addr);
2044 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2045 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002046
willy tarreau5cbea6f2005-12-17 12:48:26 +01002047 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2048 Alert("out of memory in event_accept().\n");
2049 FD_CLR(fd, StaticReadEvent);
2050 p->state = PR_STIDLE;
2051 close(cfd);
2052 return 0;
2053 }
willy tarreau0f7af912005-12-17 12:21:26 +01002054
willy tarreau5cbea6f2005-12-17 12:48:26 +01002055 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2056 Alert("out of memory in event_accept().\n");
2057 FD_CLR(fd, StaticReadEvent);
2058 p->state = PR_STIDLE;
2059 close(cfd);
2060 pool_free(session, s);
2061 return 0;
2062 }
willy tarreau0f7af912005-12-17 12:21:26 +01002063
willy tarreau5cbea6f2005-12-17 12:48:26 +01002064 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002065 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002066 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2067 close(cfd);
2068 pool_free(task, t);
2069 pool_free(session, s);
2070 return 0;
2071 }
willy tarreau0f7af912005-12-17 12:21:26 +01002072
willy tarreau5cbea6f2005-12-17 12:48:26 +01002073 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2074 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2075 (char *) &one, sizeof(one)) == -1)) {
2076 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2077 close(cfd);
2078 pool_free(task, t);
2079 pool_free(session, s);
2080 return 0;
2081 }
willy tarreau0f7af912005-12-17 12:21:26 +01002082
willy tarreau9fe663a2005-12-17 13:02:59 +01002083 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2084 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2085 t->state = TASK_IDLE;
2086 t->process = process_session;
2087 t->context = s;
2088
2089 s->task = t;
2090 s->proxy = p;
2091 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2092 s->srv_state = SV_STIDLE;
2093 s->req = s->rep = NULL; /* will be allocated later */
2094 s->flags = 0;
2095 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2096 s->cli_fd = cfd;
2097 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002098 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002099 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002100
2101 s->logs.logwait = p->to_log;
2102 s->logs.tv_accept = now;
2103 s->logs.t_request = -1;
2104 s->logs.t_connect = -1;
2105 s->logs.t_data = -1;
2106 s->logs.t_close = 0;
2107 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002108 s->logs.cli_cookie = NULL;
2109 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002110 s->logs.status = -1;
2111 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002112
willy tarreau2f6ba652005-12-17 13:57:42 +01002113 s->uniq_id = totalconn;
2114
willy tarreau5cbea6f2005-12-17 12:48:26 +01002115 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2116 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002117 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002118 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002119
willy tarreau5cbea6f2005-12-17 12:48:26 +01002120 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002121 if (addr.ss_family != AF_INET ||
2122 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002123 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002124
willy tarreau9fe663a2005-12-17 13:02:59 +01002125 if (p->to_log) {
2126 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002127 if (s->logs.logwait & LW_CLIP)
2128 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002129 sess_log(s);
2130 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002131 else if (s->cli_addr.ss_family == AF_INET) {
2132 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2133 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2134 sn, sizeof(sn)) &&
2135 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2136 pn, sizeof(pn))) {
2137 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2138 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2139 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2140 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2141 }
2142 }
2143 else {
2144 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2145 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2146 sn, sizeof(sn)) &&
2147 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2148 pn, sizeof(pn))) {
2149 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2150 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2151 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2152 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2153 }
2154 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002155 }
willy tarreau0f7af912005-12-17 12:21:26 +01002156
willy tarreau9fe663a2005-12-17 13:02:59 +01002157 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002158 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002159 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002160 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002161 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002162 if (addr.ss_family != AF_INET ||
2163 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002164 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002165
willy tarreau8a86dbf2005-12-18 00:45:59 +01002166 if (s->cli_addr.ss_family == AF_INET) {
2167 char pn[INET_ADDRSTRLEN];
2168 inet_ntop(AF_INET,
2169 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2170 pn, sizeof(pn));
2171
2172 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2173 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2174 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2175 }
2176 else {
2177 char pn[INET6_ADDRSTRLEN];
2178 inet_ntop(AF_INET6,
2179 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2180 pn, sizeof(pn));
2181
2182 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2183 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2184 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2185 }
2186
willy tarreauef900ab2005-12-17 12:52:52 +01002187 write(1, trash, len);
2188 }
willy tarreau0f7af912005-12-17 12:21:26 +01002189
willy tarreau5cbea6f2005-12-17 12:48:26 +01002190 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2191 close(cfd); /* nothing can be done for this fd without memory */
2192 pool_free(task, t);
2193 pool_free(session, s);
2194 return 0;
2195 }
2196 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002197 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002198 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2199 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002200 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002201 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002202
willy tarreau5cbea6f2005-12-17 12:48:26 +01002203 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2204 pool_free(buffer, s->req);
2205 close(cfd); /* nothing can be done for this fd without memory */
2206 pool_free(task, t);
2207 pool_free(session, s);
2208 return 0;
2209 }
2210 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002211 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002212 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 +01002213
willy tarreau5cbea6f2005-12-17 12:48:26 +01002214 fdtab[cfd].read = &event_cli_read;
2215 fdtab[cfd].write = &event_cli_write;
2216 fdtab[cfd].owner = t;
2217 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002218
willy tarreau5cbea6f2005-12-17 12:48:26 +01002219 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002220 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2221 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2222 else
2223 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002224 }
2225 else {
2226 FD_SET(cfd, StaticReadEvent);
2227 }
2228
2229 fd_insert(cfd);
2230
2231 tv_eternity(&s->cnexpire);
2232 tv_eternity(&s->srexpire);
2233 tv_eternity(&s->swexpire);
2234 tv_eternity(&s->cwexpire);
2235
2236 if (s->proxy->clitimeout)
2237 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2238 else
2239 tv_eternity(&s->crexpire);
2240
2241 t->expire = s->crexpire;
2242
2243 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002244
2245 if (p->mode != PR_MODE_HEALTH)
2246 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002247
2248 p->nbconn++;
2249 actconn++;
2250 totalconn++;
2251
2252 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2253 } /* end of while (p->nbconn < p->maxconn) */
2254 return 0;
2255}
willy tarreau0f7af912005-12-17 12:21:26 +01002256
willy tarreau0f7af912005-12-17 12:21:26 +01002257
willy tarreau5cbea6f2005-12-17 12:48:26 +01002258/*
2259 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002260 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2261 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002262 * or -1 if an error occured.
2263 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002264int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002265 struct task *t = fdtab[fd].owner;
2266 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002267
willy tarreau5cbea6f2005-12-17 12:48:26 +01002268 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002269 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002270 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002271 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002272 if (skerr)
2273 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002274 else {
2275 if (s->proxy->options & PR_O_HTTP_CHK) {
2276 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002277 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002278 * so we'll send the request, and won't wake the checker up now.
2279 */
2280#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002281 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002282#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002283 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002284#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002285 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002286 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2287 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2288 return 0;
2289 }
2290 else
2291 s->result = -1;
2292 }
2293 else {
2294 /* good TCP connection is enough */
2295 s->result = 1;
2296 }
2297 }
2298
2299 task_wakeup(&rq, t);
2300 return 0;
2301}
2302
willy tarreau0f7af912005-12-17 12:21:26 +01002303
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002304/*
2305 * This function is used only for server health-checks. It handles
2306 * the server's reply to an HTTP request. It returns 1 if the server replies
2307 * 2xx or 3xx (valid responses), or -1 in other cases.
2308 */
2309int event_srv_chk_r(int fd) {
2310 char reply[64];
2311 int len;
2312 struct task *t = fdtab[fd].owner;
2313 struct server *s = t->context;
2314
2315 int skerr, lskerr;
2316 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002317
2318 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002319#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002320 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2321 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002322 len = recv(fd, reply, sizeof(reply), 0);
2323#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002324 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2325 * but the connection was closed on the remote end. Fortunately, recv still
2326 * works correctly and we don't need to do the getsockopt() on linux.
2327 */
2328 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002329#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002330 if ((len >= sizeof("HTTP/1.0 000")) &&
2331 !memcmp(reply, "HTTP/1.", 7) &&
2332 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2333 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002334
2335 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002336 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002337 return 0;
2338}
2339
2340
2341/*
2342 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2343 * and moves <end> just after the end of <str>.
2344 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2345 * the shift value (positive or negative) is returned.
2346 * If there's no space left, the move is not done.
2347 *
2348 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002349int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002350 int delta;
2351 int len;
2352
2353 len = strlen(str);
2354 delta = len - (end - pos);
2355
2356 if (delta + b->r >= b->data + BUFSIZE)
2357 return 0; /* no space left */
2358
2359 /* first, protect the end of the buffer */
2360 memmove(end + delta, end, b->data + b->l - end);
2361
2362 /* now, copy str over pos */
2363 memcpy(pos, str,len);
2364
willy tarreau5cbea6f2005-12-17 12:48:26 +01002365 /* we only move data after the displaced zone */
2366 if (b->r > pos) b->r += delta;
2367 if (b->w > pos) b->w += delta;
2368 if (b->h > pos) b->h += delta;
2369 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002370 b->l += delta;
2371
2372 return delta;
2373}
2374
willy tarreau8337c6b2005-12-17 13:41:01 +01002375/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002376 * len is 0.
2377 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002378int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002379 int delta;
2380
2381 delta = len - (end - pos);
2382
2383 if (delta + b->r >= b->data + BUFSIZE)
2384 return 0; /* no space left */
2385
2386 /* first, protect the end of the buffer */
2387 memmove(end + delta, end, b->data + b->l - end);
2388
2389 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002390 if (len)
2391 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002392
willy tarreau5cbea6f2005-12-17 12:48:26 +01002393 /* we only move data after the displaced zone */
2394 if (b->r > pos) b->r += delta;
2395 if (b->w > pos) b->w += delta;
2396 if (b->h > pos) b->h += delta;
2397 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002398 b->l += delta;
2399
2400 return delta;
2401}
2402
2403
2404int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2405 char *old_dst = dst;
2406
2407 while (*str) {
2408 if (*str == '\\') {
2409 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002410 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002411 int len, num;
2412
2413 num = *str - '0';
2414 str++;
2415
willy tarreau8a86dbf2005-12-18 00:45:59 +01002416 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002417 len = matches[num].rm_eo - matches[num].rm_so;
2418 memcpy(dst, src + matches[num].rm_so, len);
2419 dst += len;
2420 }
2421
2422 }
2423 else if (*str == 'x') {
2424 unsigned char hex1, hex2;
2425 str++;
2426
2427 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2428
2429 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2430 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2431 *dst++ = (hex1<<4) + hex2;
2432 }
2433 else
2434 *dst++ = *str++;
2435 }
2436 else
2437 *dst++ = *str++;
2438 }
2439 *dst = 0;
2440 return dst - old_dst;
2441}
2442
willy tarreau9fe663a2005-12-17 13:02:59 +01002443
willy tarreau0f7af912005-12-17 12:21:26 +01002444/*
2445 * manages the client FSM and its socket. BTW, it also tries to handle the
2446 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2447 * 0 else.
2448 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002449int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002450 int s = t->srv_state;
2451 int c = t->cli_state;
2452 struct buffer *req = t->req;
2453 struct buffer *rep = t->rep;
2454
willy tarreau750a4722005-12-17 13:21:24 +01002455#ifdef DEBUG_FULL
2456 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2457#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002458 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2459 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2460 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2461 //);
2462 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002463 /* now parse the partial (or complete) headers */
2464 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2465 char *ptr;
2466 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002467
willy tarreau5cbea6f2005-12-17 12:48:26 +01002468 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002469
willy tarreau0f7af912005-12-17 12:21:26 +01002470 /* look for the end of the current header */
2471 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2472 ptr++;
2473
willy tarreau5cbea6f2005-12-17 12:48:26 +01002474 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002475 int line, len;
2476 /* we can only get here after an end of headers */
2477 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002478
willy tarreaue39cd132005-12-17 13:00:18 +01002479 if (t->flags & SN_CLDENY) {
2480 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002481 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002482 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002483 if (!(t->flags & SN_ERR_MASK))
2484 t->flags |= SN_ERR_PRXCOND;
2485 if (!(t->flags & SN_FINST_MASK))
2486 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002487 return 1;
2488 }
2489
willy tarreau5cbea6f2005-12-17 12:48:26 +01002490 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002491 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2492 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002493 }
willy tarreau0f7af912005-12-17 12:21:26 +01002494
willy tarreau9fe663a2005-12-17 13:02:59 +01002495 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002496 if (t->cli_addr.ss_family == AF_INET) {
2497 unsigned char *pn;
2498 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
2499 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2500 pn[0], pn[1], pn[2], pn[3]);
2501 buffer_replace2(req, req->h, req->h, trash, len);
2502 }
2503 else if (t->cli_addr.ss_family == AF_INET6) {
2504 char pn[INET6_ADDRSTRLEN];
2505 inet_ntop(AF_INET6,
2506 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2507 pn, sizeof(pn));
2508 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
2509 buffer_replace2(req, req->h, req->h, trash, len);
2510 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002511 }
2512
willy tarreaucd878942005-12-17 13:27:43 +01002513 if (!memcmp(req->data, "POST ", 5))
2514 t->flags |= SN_POST; /* this is a POST request */
2515
willy tarreau5cbea6f2005-12-17 12:48:26 +01002516 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002517 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002518
willy tarreau750a4722005-12-17 13:21:24 +01002519 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002520 /* FIXME: we'll set the client in a wait state while we try to
2521 * connect to the server. Is this really needed ? wouldn't it be
2522 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002523 //FD_CLR(t->cli_fd, StaticReadEvent);
2524 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002525
2526 /* FIXME: if we break here (as up to 1.1.23), having the client
2527 * shutdown its connection can lead to an abort further.
2528 * it's better to either return 1 or even jump directly to the
2529 * data state which will save one schedule.
2530 */
2531 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002532
2533 if (!t->proxy->clitimeout ||
2534 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2535 /* If the client has no timeout, or if the server is not ready yet,
2536 * and we know for sure that it can expire, then it's cleaner to
2537 * disable the timeout on the client side so that too low values
2538 * cannot make the sessions abort too early.
2539 */
2540 tv_eternity(&t->crexpire);
2541
willy tarreau197e8ec2005-12-17 14:10:59 +01002542 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002543 }
willy tarreau0f7af912005-12-17 12:21:26 +01002544
willy tarreau5cbea6f2005-12-17 12:48:26 +01002545 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2546 if (ptr > req->r - 2) {
2547 /* this is a partial header, let's wait for more to come */
2548 req->lr = ptr;
2549 break;
2550 }
willy tarreau0f7af912005-12-17 12:21:26 +01002551
willy tarreau5cbea6f2005-12-17 12:48:26 +01002552 /* now we know that *ptr is either \r or \n,
2553 * and that there are at least 1 char after it.
2554 */
2555 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2556 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2557 else
2558 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002559
willy tarreau5cbea6f2005-12-17 12:48:26 +01002560 /*
2561 * now we know that we have a full header ; we can do whatever
2562 * we want with these pointers :
2563 * req->h = beginning of header
2564 * ptr = end of header (first \r or \n)
2565 * req->lr = beginning of next line (next rep->h)
2566 * req->r = end of data (not used at this stage)
2567 */
willy tarreau0f7af912005-12-17 12:21:26 +01002568
willy tarreau8337c6b2005-12-17 13:41:01 +01002569 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002570 /* we have a complete HTTP request that we must log */
2571 int urilen;
2572
willy tarreaua1598082005-12-17 13:08:06 +01002573 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002574 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002575 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002576 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002577 if (!(t->flags & SN_ERR_MASK))
2578 t->flags |= SN_ERR_PRXCOND;
2579 if (!(t->flags & SN_FINST_MASK))
2580 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002581 return 1;
2582 }
2583
2584 urilen = ptr - req->h;
2585 if (urilen >= REQURI_LEN)
2586 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002587 memcpy(t->logs.uri, req->h, urilen);
2588 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002589
willy tarreaua1598082005-12-17 13:08:06 +01002590 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002591 sess_log(t);
2592 }
2593
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002595
willy tarreau9fe663a2005-12-17 13:02:59 +01002596 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002597 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002598 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 +01002599 max = ptr - req->h;
2600 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002601 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002602 trash[len++] = '\n';
2603 write(1, trash, len);
2604 }
willy tarreau0f7af912005-12-17 12:21:26 +01002605
willy tarreau5cbea6f2005-12-17 12:48:26 +01002606 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002607 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2608 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002609 char term;
2610
2611 term = *ptr;
2612 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002613 exp = t->proxy->req_exp;
2614 do {
2615 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2616 switch (exp->action) {
2617 case ACT_ALLOW:
2618 if (!(t->flags & SN_CLDENY))
2619 t->flags |= SN_CLALLOW;
2620 break;
2621 case ACT_REPLACE:
2622 if (!(t->flags & SN_CLDENY)) {
2623 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2624 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2625 }
2626 break;
2627 case ACT_REMOVE:
2628 if (!(t->flags & SN_CLDENY))
2629 delete_header = 1;
2630 break;
2631 case ACT_DENY:
2632 if (!(t->flags & SN_CLALLOW))
2633 t->flags |= SN_CLDENY;
2634 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002635 case ACT_PASS: /* we simply don't deny this one */
2636 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002637 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002638 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002639 }
willy tarreaue39cd132005-12-17 13:00:18 +01002640 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002641 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002642 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002643
willy tarreau240afa62005-12-17 13:14:35 +01002644 /* Now look for cookies. Conforming to RFC2109, we have to support
2645 * attributes whose name begin with a '$', and associate them with
2646 * the right cookie, if we want to delete this cookie.
2647 * So there are 3 cases for each cookie read :
2648 * 1) it's a special attribute, beginning with a '$' : ignore it.
2649 * 2) it's a server id cookie that we *MAY* want to delete : save
2650 * some pointers on it (last semi-colon, beginning of cookie...)
2651 * 3) it's an application cookie : we *MAY* have to delete a previous
2652 * "special" cookie.
2653 * At the end of loop, if a "special" cookie remains, we may have to
2654 * remove it. If no application cookie persists in the header, we
2655 * *MUST* delete it
2656 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002657 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002658 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01002659 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002660 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002661 char *del_colon, *del_cookie, *colon;
2662 int app_cookies;
2663
willy tarreau5cbea6f2005-12-17 12:48:26 +01002664 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002665 colon = p1;
2666 /* del_cookie == NULL => nothing to be deleted */
2667 del_colon = del_cookie = NULL;
2668 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002669
2670 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002671 /* skip spaces and colons, but keep an eye on these ones */
2672 while (p1 < ptr) {
2673 if (*p1 == ';' || *p1 == ',')
2674 colon = p1;
2675 else if (!isspace((int)*p1))
2676 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002677 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002678 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002679
2680 if (p1 == ptr)
2681 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002682
2683 /* p1 is at the beginning of the cookie name */
2684 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002685 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002686 p2++;
2687
2688 if (p2 == ptr)
2689 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002690
2691 p3 = p2 + 1; /* skips the '=' sign */
2692 if (p3 == ptr)
2693 break;
2694
willy tarreau240afa62005-12-17 13:14:35 +01002695 p4 = p3;
2696 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002697 p4++;
2698
2699 /* here, we have the cookie name between p1 and p2,
2700 * and its value between p3 and p4.
2701 * we can process it.
2702 */
2703
willy tarreau240afa62005-12-17 13:14:35 +01002704 if (*p1 == '$') {
2705 /* skip this one */
2706 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002707 else {
2708 /* first, let's see if we want to capture it */
2709 if (t->proxy->capture_name != NULL &&
2710 t->logs.cli_cookie == NULL &&
2711 (p4 - p1 >= t->proxy->capture_namelen) &&
2712 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2713 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002714
willy tarreau8337c6b2005-12-17 13:41:01 +01002715 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2716 Alert("HTTP logging : out of memory.\n");
2717 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002718
willy tarreau8337c6b2005-12-17 13:41:01 +01002719 if (log_len > t->proxy->capture_len)
2720 log_len = t->proxy->capture_len;
2721 memcpy(t->logs.cli_cookie, p1, log_len);
2722 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002723 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002724
2725 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2726 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2727 /* Cool... it's the right one */
2728 struct server *srv = t->proxy->srv;
2729
2730 while (srv &&
2731 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2732 srv = srv->next;
2733 }
2734
willy tarreau036e1ce2005-12-17 13:46:33 +01002735 if (!srv) {
2736 t->flags &= ~SN_CK_MASK;
2737 t->flags |= SN_CK_INVALID;
2738 }
2739 else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002740 /* we found the server and it's usable */
willy tarreau036e1ce2005-12-17 13:46:33 +01002741 t->flags &= ~SN_CK_MASK;
2742 t->flags |= SN_CK_VALID | SN_DIRECT;
willy tarreau8337c6b2005-12-17 13:41:01 +01002743 t->srv = srv;
2744 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002745 else {
2746 t->flags &= ~SN_CK_MASK;
2747 t->flags |= SN_CK_DOWN;
2748 }
2749
willy tarreau8337c6b2005-12-17 13:41:01 +01002750 /* if this cookie was set in insert+indirect mode, then it's better that the
2751 * server never sees it.
2752 */
2753 if (del_cookie == NULL &&
2754 (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 +01002755 del_cookie = p1;
2756 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002757 }
willy tarreau240afa62005-12-17 13:14:35 +01002758 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002759 else {
2760 /* now we know that we must keep this cookie since it's
2761 * not ours. But if we wanted to delete our cookie
2762 * earlier, we cannot remove the complete header, but we
2763 * can remove the previous block itself.
2764 */
2765 app_cookies++;
2766
2767 if (del_cookie != NULL) {
2768 buffer_replace2(req, del_cookie, p1, NULL, 0);
2769 p4 -= (p1 - del_cookie);
2770 ptr -= (p1 - del_cookie);
2771 del_cookie = del_colon = NULL;
2772 }
willy tarreau240afa62005-12-17 13:14:35 +01002773 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002774 }
willy tarreau240afa62005-12-17 13:14:35 +01002775
willy tarreau5cbea6f2005-12-17 12:48:26 +01002776 /* we'll have to look for another cookie ... */
2777 p1 = p4;
2778 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002779
2780 /* There's no more cookie on this line.
2781 * We may have marked the last one(s) for deletion.
2782 * We must do this now in two ways :
2783 * - if there is no app cookie, we simply delete the header ;
2784 * - if there are app cookies, we must delete the end of the
2785 * string properly, including the colon/semi-colon before
2786 * the cookie name.
2787 */
2788 if (del_cookie != NULL) {
2789 if (app_cookies) {
2790 buffer_replace2(req, del_colon, ptr, NULL, 0);
2791 /* WARNING! <ptr> becomes invalid for now. If some code
2792 * below needs to rely on it before the end of the global
2793 * header loop, we need to correct it with this code :
2794 * ptr = del_colon;
2795 */
2796 }
2797 else
2798 delete_header = 1;
2799 }
2800 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002801
2802 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002803 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002804 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002805 }
willy tarreau240afa62005-12-17 13:14:35 +01002806 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2807
willy tarreau5cbea6f2005-12-17 12:48:26 +01002808 req->h = req->lr;
2809 } /* while (req->lr < req->r) */
2810
2811 /* end of header processing (even if incomplete) */
2812
willy tarreauef900ab2005-12-17 12:52:52 +01002813 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2814 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2815 * full. We cannot loop here since event_cli_read will disable it only if
2816 * req->l == rlim-data
2817 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002818 FD_SET(t->cli_fd, StaticReadEvent);
2819 if (t->proxy->clitimeout)
2820 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2821 else
2822 tv_eternity(&t->crexpire);
2823 }
2824
willy tarreaue39cd132005-12-17 13:00:18 +01002825 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002826 * won't be able to free more later, so the session will never terminate.
2827 */
willy tarreaue39cd132005-12-17 13:00:18 +01002828 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002829 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01002830 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01002831 if (!(t->flags & SN_ERR_MASK))
2832 t->flags |= SN_ERR_PRXCOND;
2833 if (!(t->flags & SN_FINST_MASK))
2834 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002835 return 1;
2836 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002837 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002838 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002839 tv_eternity(&t->crexpire);
2840 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002841 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002842 if (!(t->flags & SN_ERR_MASK))
2843 t->flags |= SN_ERR_CLICL;
2844 if (!(t->flags & SN_FINST_MASK))
2845 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002846 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002847 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002848 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2849
2850 /* read timeout : give up with an error message.
2851 */
2852 t->logs.status = 408;
2853 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01002854 if (!(t->flags & SN_ERR_MASK))
2855 t->flags |= SN_ERR_CLITO;
2856 if (!(t->flags & SN_FINST_MASK))
2857 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01002858 return 1;
2859 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002860
2861 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002862 }
2863 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01002864 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01002865 /* FIXME: this error handling is partly buggy because we always report
2866 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2867 * or HEADER phase. BTW, it's not logical to expire the client while
2868 * we're waiting for the server to connect.
2869 */
willy tarreau0f7af912005-12-17 12:21:26 +01002870 /* read or write error */
2871 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002872 tv_eternity(&t->crexpire);
2873 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002874 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002875 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002876 if (!(t->flags & SN_ERR_MASK))
2877 t->flags |= SN_ERR_CLICL;
2878 if (!(t->flags & SN_FINST_MASK))
2879 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002880 return 1;
2881 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002882 /* last read, or end of server write */
2883 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002884 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002885 tv_eternity(&t->crexpire);
2886 shutdown(t->cli_fd, SHUT_RD);
2887 t->cli_state = CL_STSHUTR;
2888 return 1;
2889 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002890 /* last server read and buffer empty */
2891 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002892 FD_CLR(t->cli_fd, StaticWriteEvent);
2893 tv_eternity(&t->cwexpire);
2894 shutdown(t->cli_fd, SHUT_WR);
2895 t->cli_state = CL_STSHUTW;
2896 return 1;
2897 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002898 /* read timeout */
2899 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2900 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01002901 tv_eternity(&t->crexpire);
2902 shutdown(t->cli_fd, SHUT_RD);
2903 t->cli_state = CL_STSHUTR;
2904 if (!(t->flags & SN_ERR_MASK))
2905 t->flags |= SN_ERR_CLITO;
2906 if (!(t->flags & SN_FINST_MASK))
2907 t->flags |= SN_FINST_D;
2908 return 1;
2909 }
2910 /* write timeout */
2911 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2912 FD_CLR(t->cli_fd, StaticWriteEvent);
2913 tv_eternity(&t->cwexpire);
2914 shutdown(t->cli_fd, SHUT_WR);
2915 t->cli_state = CL_STSHUTW;
2916 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01002917 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01002918 if (!(t->flags & SN_FINST_MASK))
2919 t->flags |= SN_FINST_D;
2920 return 1;
2921 }
willy tarreau0f7af912005-12-17 12:21:26 +01002922
willy tarreauc58fc692005-12-17 14:13:08 +01002923 if (req->l >= req->rlim - req->data) {
2924 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002925 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002926 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002927 FD_CLR(t->cli_fd, StaticReadEvent);
2928 tv_eternity(&t->crexpire);
2929 }
2930 }
2931 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002932 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002933 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2934 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01002935 if (!t->proxy->clitimeout ||
2936 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2937 /* If the client has no timeout, or if the server not ready yet, and we
2938 * know for sure that it can expire, then it's cleaner to disable the
2939 * timeout on the client side so that too low values cannot make the
2940 * sessions abort too early.
2941 */
willy tarreau0f7af912005-12-17 12:21:26 +01002942 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01002943 else
2944 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01002945 }
2946 }
2947
2948 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01002949 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002950 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2951 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2952 tv_eternity(&t->cwexpire);
2953 }
2954 }
2955 else { /* buffer not empty */
2956 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2957 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002958 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002959 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002960 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2961 t->crexpire = t->cwexpire;
2962 }
willy tarreau0f7af912005-12-17 12:21:26 +01002963 else
2964 tv_eternity(&t->cwexpire);
2965 }
2966 }
2967 return 0; /* other cases change nothing */
2968 }
2969 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002970 if (t->res_cw == RES_ERROR) {
2971 tv_eternity(&t->cwexpire);
2972 fd_delete(t->cli_fd);
2973 t->cli_state = CL_STCLOSE;
2974 if (!(t->flags & SN_ERR_MASK))
2975 t->flags |= SN_ERR_CLICL;
2976 if (!(t->flags & SN_FINST_MASK))
2977 t->flags |= SN_FINST_D;
2978 return 1;
2979 }
2980 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002981 tv_eternity(&t->cwexpire);
2982 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002983 t->cli_state = CL_STCLOSE;
2984 return 1;
2985 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002986 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2987 tv_eternity(&t->cwexpire);
2988 fd_delete(t->cli_fd);
2989 t->cli_state = CL_STCLOSE;
2990 if (!(t->flags & SN_ERR_MASK))
2991 t->flags |= SN_ERR_CLITO;
2992 if (!(t->flags & SN_FINST_MASK))
2993 t->flags |= SN_FINST_D;
2994 return 1;
2995 }
willy tarreau0f7af912005-12-17 12:21:26 +01002996 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002997 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002998 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2999 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3000 tv_eternity(&t->cwexpire);
3001 }
3002 }
3003 else { /* buffer not empty */
3004 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3005 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003006 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003007 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003008 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3009 t->crexpire = t->cwexpire;
3010 }
willy tarreau0f7af912005-12-17 12:21:26 +01003011 else
3012 tv_eternity(&t->cwexpire);
3013 }
3014 }
3015 return 0;
3016 }
3017 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003018 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003019 tv_eternity(&t->crexpire);
3020 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003021 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003022 if (!(t->flags & SN_ERR_MASK))
3023 t->flags |= SN_ERR_CLICL;
3024 if (!(t->flags & SN_FINST_MASK))
3025 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003026 return 1;
3027 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003028 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3029 tv_eternity(&t->crexpire);
3030 fd_delete(t->cli_fd);
3031 t->cli_state = CL_STCLOSE;
3032 return 1;
3033 }
3034 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3035 tv_eternity(&t->crexpire);
3036 fd_delete(t->cli_fd);
3037 t->cli_state = CL_STCLOSE;
3038 if (!(t->flags & SN_ERR_MASK))
3039 t->flags |= SN_ERR_CLITO;
3040 if (!(t->flags & SN_FINST_MASK))
3041 t->flags |= SN_FINST_D;
3042 return 1;
3043 }
willy tarreauef900ab2005-12-17 12:52:52 +01003044 else if (req->l >= req->rlim - req->data) {
3045 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003046 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003047 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003048 FD_CLR(t->cli_fd, StaticReadEvent);
3049 tv_eternity(&t->crexpire);
3050 }
3051 }
3052 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003053 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003054 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3055 FD_SET(t->cli_fd, StaticReadEvent);
3056 if (t->proxy->clitimeout)
3057 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3058 else
3059 tv_eternity(&t->crexpire);
3060 }
3061 }
3062 return 0;
3063 }
3064 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003065 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003066 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003067 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 +01003068 write(1, trash, len);
3069 }
3070 return 0;
3071 }
3072 return 0;
3073}
3074
3075
3076/*
3077 * manages the server FSM and its socket. It returns 1 if a state has changed
3078 * (and a resync may be needed), 0 else.
3079 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003080int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003081 int s = t->srv_state;
3082 int c = t->cli_state;
3083 struct buffer *req = t->req;
3084 struct buffer *rep = t->rep;
3085
willy tarreau750a4722005-12-17 13:21:24 +01003086#ifdef DEBUG_FULL
3087 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3088#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003089 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3090 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3091 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3092 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003093 if (s == SV_STIDLE) {
3094 if (c == CL_STHEADERS)
3095 return 0; /* stay in idle, waiting for data to reach the client side */
3096 else if (c == CL_STCLOSE ||
3097 c == CL_STSHUTW ||
3098 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3099 tv_eternity(&t->cnexpire);
3100 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003101 if (!(t->flags & SN_ERR_MASK))
3102 t->flags |= SN_ERR_CLICL;
3103 if (!(t->flags & SN_FINST_MASK))
3104 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003105 return 1;
3106 }
3107 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003108 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003109 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3110 t->srv_state = SV_STCONN;
3111 }
3112 else { /* try again */
3113 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003114 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003115 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003116 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003117 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3118 t->flags &= ~SN_CK_MASK;
3119 t->flags |= SN_CK_DOWN;
3120 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003121 }
3122
3123 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003124 t->srv_state = SV_STCONN;
3125 break;
3126 }
3127 }
3128 if (t->conn_retries < 0) {
3129 /* if conn_retries < 0 or other error, let's abort */
3130 tv_eternity(&t->cnexpire);
3131 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003132 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003133 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003134 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003135 if (!(t->flags & SN_ERR_MASK))
3136 t->flags |= SN_ERR_SRVCL;
3137 if (!(t->flags & SN_FINST_MASK))
3138 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003139 }
3140 }
3141 return 1;
3142 }
3143 }
3144 else if (s == SV_STCONN) { /* connection in progress */
3145 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3146 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3147 return 0; /* nothing changed */
3148 }
3149 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3150 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3151 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003152 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003153 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003154 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003155 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003156 if (t->conn_retries >= 0) {
3157 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003158 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003159 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003160 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3161 t->flags &= ~SN_CK_MASK;
3162 t->flags |= SN_CK_DOWN;
3163 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003164 }
3165 if (connect_server(t) == 0)
3166 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003167 }
3168 /* if conn_retries < 0 or other error, let's abort */
3169 tv_eternity(&t->cnexpire);
3170 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003171 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003172 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003173 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003174 if (!(t->flags & SN_ERR_MASK))
3175 t->flags |= SN_ERR_SRVCL;
3176 if (!(t->flags & SN_FINST_MASK))
3177 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003178 return 1;
3179 }
3180 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003181 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003182
willy tarreau0f7af912005-12-17 12:21:26 +01003183 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003184 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003185 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003186 tv_eternity(&t->swexpire);
3187 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003188 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003189 if (t->proxy->srvtimeout) {
3190 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3191 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3192 t->srexpire = t->swexpire;
3193 }
3194 else
3195 tv_eternity(&t->swexpire);
3196 }
willy tarreau0f7af912005-12-17 12:21:26 +01003197
3198 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3199 FD_SET(t->srv_fd, StaticReadEvent);
3200 if (t->proxy->srvtimeout)
3201 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3202 else
3203 tv_eternity(&t->srexpire);
3204
3205 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003206 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003207 }
willy tarreauef900ab2005-12-17 12:52:52 +01003208 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003209 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003210 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3211 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003212 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003213 return 1;
3214 }
3215 }
3216 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003217 /* now parse the partial (or complete) headers */
3218 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3219 char *ptr;
3220 int delete_header;
3221
3222 ptr = rep->lr;
3223
3224 /* look for the end of the current header */
3225 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3226 ptr++;
3227
3228 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003229 int line, len;
3230
3231 /* we can only get here after an end of headers */
3232 /* we'll have something else to do here : add new headers ... */
3233
willy tarreaucd878942005-12-17 13:27:43 +01003234 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3235 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003236 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003237 * insert a set-cookie here, except if we want to insert only on POST
3238 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003239 */
willy tarreau750a4722005-12-17 13:21:24 +01003240 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003241 t->proxy->cookie_name,
3242 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003243
willy tarreau036e1ce2005-12-17 13:46:33 +01003244 t->flags |= SN_SCK_INSERTED;
3245
willy tarreau750a4722005-12-17 13:21:24 +01003246 /* Here, we will tell an eventual cache on the client side that we don't
3247 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3248 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3249 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3250 */
willy tarreau240afa62005-12-17 13:14:35 +01003251 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003252 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3253 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003254
willy tarreau750a4722005-12-17 13:21:24 +01003255 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003256 }
3257
3258 /* headers to be added */
3259 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003260 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3261 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003262 }
3263
3264 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003265 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003266 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003267 break;
3268 }
3269
3270 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3271 if (ptr > rep->r - 2) {
3272 /* this is a partial header, let's wait for more to come */
3273 rep->lr = ptr;
3274 break;
3275 }
3276
3277 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3278 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3279
3280 /* now we know that *ptr is either \r or \n,
3281 * and that there are at least 1 char after it.
3282 */
3283 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3284 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3285 else
3286 rep->lr = ptr + 2; /* \r\n or \n\r */
3287
3288 /*
3289 * now we know that we have a full header ; we can do whatever
3290 * we want with these pointers :
3291 * rep->h = beginning of header
3292 * ptr = end of header (first \r or \n)
3293 * rep->lr = beginning of next line (next rep->h)
3294 * rep->r = end of data (not used at this stage)
3295 */
3296
willy tarreaua1598082005-12-17 13:08:06 +01003297
3298 if (t->logs.logwait & LW_RESP) {
3299 t->logs.logwait &= ~LW_RESP;
3300 t->logs.status = atoi(rep->h + 9);
3301 }
3302
willy tarreau5cbea6f2005-12-17 12:48:26 +01003303 delete_header = 0;
3304
willy tarreau9fe663a2005-12-17 13:02:59 +01003305 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003306 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003307 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 +01003308 max = ptr - rep->h;
3309 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003310 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003311 trash[len++] = '\n';
3312 write(1, trash, len);
3313 }
3314
3315 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01003316 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
3317 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003318 char term;
3319
3320 term = *ptr;
3321 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003322 exp = t->proxy->rsp_exp;
3323 do {
3324 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3325 switch (exp->action) {
3326 case ACT_ALLOW:
3327 if (!(t->flags & SN_SVDENY))
3328 t->flags |= SN_SVALLOW;
3329 break;
3330 case ACT_REPLACE:
3331 if (!(t->flags & SN_SVDENY)) {
3332 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3333 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3334 }
3335 break;
3336 case ACT_REMOVE:
3337 if (!(t->flags & SN_SVDENY))
3338 delete_header = 1;
3339 break;
3340 case ACT_DENY:
3341 if (!(t->flags & SN_SVALLOW))
3342 t->flags |= SN_SVDENY;
3343 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003344 case ACT_PASS: /* we simply don't deny this one */
3345 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003346 }
3347 break;
3348 }
willy tarreaue39cd132005-12-17 13:00:18 +01003349 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003350 *ptr = term; /* restore the string terminator */
3351 }
3352
3353 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003354 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3355 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
3356 && (ptr >= rep->h + 12)
willy tarreau906b2682005-12-17 13:49:52 +01003357 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003358 char *p1, *p2, *p3, *p4;
3359
3360 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3361
3362 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003363 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003364 p1++;
3365
3366 if (p1 == ptr || *p1 == ';') /* end of cookie */
3367 break;
3368
3369 /* p1 is at the beginning of the cookie name */
3370 p2 = p1;
3371
3372 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3373 p2++;
3374
3375 if (p2 == ptr || *p2 == ';') /* next cookie */
3376 break;
3377
3378 p3 = p2 + 1; /* skips the '=' sign */
3379 if (p3 == ptr)
3380 break;
3381
3382 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003383 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003384 p4++;
3385
3386 /* here, we have the cookie name between p1 and p2,
3387 * and its value between p3 and p4.
3388 * we can process it.
3389 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003390
3391 /* first, let's see if we want to capture it */
3392 if (t->proxy->capture_name != NULL &&
3393 t->logs.srv_cookie == NULL &&
3394 (p4 - p1 >= t->proxy->capture_namelen) &&
3395 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3396 int log_len = p4 - p1;
3397
3398 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3399 Alert("HTTP logging : out of memory.\n");
3400 }
3401
3402 if (log_len > t->proxy->capture_len)
3403 log_len = t->proxy->capture_len;
3404 memcpy(t->logs.srv_cookie, p1, log_len);
3405 t->logs.srv_cookie[log_len] = 0;
3406 }
3407
3408 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3409 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003410 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003411 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003412
3413 /* If the cookie is in insert mode on a known server, we'll delete
3414 * this occurrence because we'll insert another one later.
3415 * We'll delete it too if the "indirect" option is set and we're in
3416 * a direct access. */
3417 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003418 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003419 /* this header must be deleted */
3420 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003421 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003422 }
3423 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3424 /* replace bytes p3->p4 with the cookie name associated
3425 * with this server since we know it.
3426 */
3427 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003428 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003429 }
3430 break;
3431 }
3432 else {
3433 // fprintf(stderr,"Ignoring unknown cookie : ");
3434 // write(2, p1, p2-p1);
3435 // fprintf(stderr," = ");
3436 // write(2, p3, p4-p3);
3437 // fprintf(stderr,"\n");
3438 }
3439 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3440 } /* we're now at the end of the cookie value */
3441 } /* end of cookie processing */
3442
3443 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003444 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003445 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003446
willy tarreau5cbea6f2005-12-17 12:48:26 +01003447 rep->h = rep->lr;
3448 } /* while (rep->lr < rep->r) */
3449
3450 /* end of header processing (even if incomplete) */
3451
willy tarreauef900ab2005-12-17 12:52:52 +01003452 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3453 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3454 * full. We cannot loop here since event_srv_read will disable it only if
3455 * rep->l == rlim-data
3456 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003457 FD_SET(t->srv_fd, StaticReadEvent);
3458 if (t->proxy->srvtimeout)
3459 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3460 else
3461 tv_eternity(&t->srexpire);
3462 }
willy tarreau0f7af912005-12-17 12:21:26 +01003463
willy tarreau8337c6b2005-12-17 13:41:01 +01003464 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003465 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003466 tv_eternity(&t->srexpire);
3467 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003468 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003469 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003470 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003471 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003472 if (!(t->flags & SN_ERR_MASK))
3473 t->flags |= SN_ERR_SRVCL;
3474 if (!(t->flags & SN_FINST_MASK))
3475 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003476 return 1;
3477 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003478 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003479 * since we are in header mode, if there's no space left for headers, we
3480 * won't be able to free more later, so the session will never terminate.
3481 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003482 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 +01003483 FD_CLR(t->srv_fd, StaticReadEvent);
3484 tv_eternity(&t->srexpire);
3485 shutdown(t->srv_fd, SHUT_RD);
3486 t->srv_state = SV_STSHUTR;
3487 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003488 }
3489 /* read timeout : return a 504 to the client.
3490 */
3491 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3492 tv_eternity(&t->srexpire);
3493 tv_eternity(&t->swexpire);
3494 fd_delete(t->srv_fd);
3495 t->srv_state = SV_STCLOSE;
3496 t->logs.status = 504;
3497 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003498 if (!(t->flags & SN_ERR_MASK))
3499 t->flags |= SN_ERR_SRVTO;
3500 if (!(t->flags & SN_FINST_MASK))
3501 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003502 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003503
3504 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003505 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003506 /* FIXME!!! here, we don't want to switch to SHUTW if the
3507 * client shuts read too early, because we may still have
3508 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01003509 * The side-effect is that if the client completely closes its
3510 * connection during SV_STHEADER, the connection to the server
3511 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01003512 */
willy tarreau036e1ce2005-12-17 13:46:33 +01003513 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003514 FD_CLR(t->srv_fd, StaticWriteEvent);
3515 tv_eternity(&t->swexpire);
3516 shutdown(t->srv_fd, SHUT_WR);
3517 t->srv_state = SV_STSHUTW;
3518 return 1;
3519 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003520 /* write timeout */
3521 /* FIXME!!! here, we don't want to switch to SHUTW if the
3522 * client shuts read too early, because we may still have
3523 * some work to do on the headers.
3524 */
3525 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3526 FD_CLR(t->srv_fd, StaticWriteEvent);
3527 tv_eternity(&t->swexpire);
3528 shutdown(t->srv_fd, SHUT_WR);
3529 t->srv_state = SV_STSHUTW;
3530 if (!(t->flags & SN_ERR_MASK))
3531 t->flags |= SN_ERR_SRVTO;
3532 if (!(t->flags & SN_FINST_MASK))
3533 t->flags |= SN_FINST_H;
3534 return 1;
3535 }
willy tarreau0f7af912005-12-17 12:21:26 +01003536
3537 if (req->l == 0) {
3538 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3539 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3540 tv_eternity(&t->swexpire);
3541 }
3542 }
3543 else { /* client buffer not empty */
3544 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3545 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003546 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003547 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003548 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3549 t->srexpire = t->swexpire;
3550 }
willy tarreau0f7af912005-12-17 12:21:26 +01003551 else
3552 tv_eternity(&t->swexpire);
3553 }
3554 }
3555
willy tarreau5cbea6f2005-12-17 12:48:26 +01003556 /* be nice with the client side which would like to send a complete header
3557 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3558 * would read all remaining data at once ! The client should not write past rep->lr
3559 * when the server is in header state.
3560 */
3561 //return header_processed;
3562 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003563 }
3564 else if (s == SV_STDATA) {
3565 /* read or write error */
3566 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003567 tv_eternity(&t->srexpire);
3568 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003569 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003570 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003571 if (!(t->flags & SN_ERR_MASK))
3572 t->flags |= SN_ERR_SRVCL;
3573 if (!(t->flags & SN_FINST_MASK))
3574 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003575 return 1;
3576 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003577 /* last read, or end of client write */
3578 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003579 FD_CLR(t->srv_fd, StaticReadEvent);
3580 tv_eternity(&t->srexpire);
3581 shutdown(t->srv_fd, SHUT_RD);
3582 t->srv_state = SV_STSHUTR;
3583 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01003584 }
3585 /* end of client read and no more data to send */
3586 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
3587 FD_CLR(t->srv_fd, StaticWriteEvent);
3588 tv_eternity(&t->swexpire);
3589 shutdown(t->srv_fd, SHUT_WR);
3590 t->srv_state = SV_STSHUTW;
3591 return 1;
3592 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003593 /* read timeout */
3594 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3595 FD_CLR(t->srv_fd, StaticReadEvent);
3596 tv_eternity(&t->srexpire);
3597 shutdown(t->srv_fd, SHUT_RD);
3598 t->srv_state = SV_STSHUTR;
3599 if (!(t->flags & SN_ERR_MASK))
3600 t->flags |= SN_ERR_SRVTO;
3601 if (!(t->flags & SN_FINST_MASK))
3602 t->flags |= SN_FINST_D;
3603 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003604 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003605 /* write timeout */
3606 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003607 FD_CLR(t->srv_fd, StaticWriteEvent);
3608 tv_eternity(&t->swexpire);
3609 shutdown(t->srv_fd, SHUT_WR);
3610 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01003611 if (!(t->flags & SN_ERR_MASK))
3612 t->flags |= SN_ERR_SRVTO;
3613 if (!(t->flags & SN_FINST_MASK))
3614 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003615 return 1;
3616 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003617
3618 /* recompute request time-outs */
3619 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003620 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3621 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3622 tv_eternity(&t->swexpire);
3623 }
3624 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003625 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01003626 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3627 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003628 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003629 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003630 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3631 t->srexpire = t->swexpire;
3632 }
willy tarreau0f7af912005-12-17 12:21:26 +01003633 else
3634 tv_eternity(&t->swexpire);
3635 }
3636 }
3637
willy tarreaub1ff9db2005-12-17 13:51:03 +01003638 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01003639 if (rep->l == BUFSIZE) { /* no room to read more data */
3640 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3641 FD_CLR(t->srv_fd, StaticReadEvent);
3642 tv_eternity(&t->srexpire);
3643 }
3644 }
3645 else {
3646 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3647 FD_SET(t->srv_fd, StaticReadEvent);
3648 if (t->proxy->srvtimeout)
3649 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3650 else
3651 tv_eternity(&t->srexpire);
3652 }
3653 }
3654
3655 return 0; /* other cases change nothing */
3656 }
3657 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003658 if (t->res_sw == RES_ERROR) {
3659 //FD_CLR(t->srv_fd, StaticWriteEvent);
3660 tv_eternity(&t->swexpire);
3661 fd_delete(t->srv_fd);
3662 //close(t->srv_fd);
3663 t->srv_state = SV_STCLOSE;
3664 if (!(t->flags & SN_ERR_MASK))
3665 t->flags |= SN_ERR_SRVCL;
3666 if (!(t->flags & SN_FINST_MASK))
3667 t->flags |= SN_FINST_D;
3668 return 1;
3669 }
3670 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003671 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003672 tv_eternity(&t->swexpire);
3673 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003674 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003675 t->srv_state = SV_STCLOSE;
3676 return 1;
3677 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003678 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3679 //FD_CLR(t->srv_fd, StaticWriteEvent);
3680 tv_eternity(&t->swexpire);
3681 fd_delete(t->srv_fd);
3682 //close(t->srv_fd);
3683 t->srv_state = SV_STCLOSE;
3684 if (!(t->flags & SN_ERR_MASK))
3685 t->flags |= SN_ERR_SRVTO;
3686 if (!(t->flags & SN_FINST_MASK))
3687 t->flags |= SN_FINST_D;
3688 return 1;
3689 }
willy tarreau0f7af912005-12-17 12:21:26 +01003690 else if (req->l == 0) {
3691 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3692 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3693 tv_eternity(&t->swexpire);
3694 }
3695 }
3696 else { /* buffer not empty */
3697 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3698 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003699 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003700 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003701 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3702 t->srexpire = t->swexpire;
3703 }
willy tarreau0f7af912005-12-17 12:21:26 +01003704 else
3705 tv_eternity(&t->swexpire);
3706 }
3707 }
3708 return 0;
3709 }
3710 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003711 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003712 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003713 tv_eternity(&t->srexpire);
3714 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003715 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003716 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003717 if (!(t->flags & SN_ERR_MASK))
3718 t->flags |= SN_ERR_SRVCL;
3719 if (!(t->flags & SN_FINST_MASK))
3720 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003721 return 1;
3722 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003723 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
3724 //FD_CLR(t->srv_fd, StaticReadEvent);
3725 tv_eternity(&t->srexpire);
3726 fd_delete(t->srv_fd);
3727 //close(t->srv_fd);
3728 t->srv_state = SV_STCLOSE;
3729 return 1;
3730 }
3731 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3732 //FD_CLR(t->srv_fd, StaticReadEvent);
3733 tv_eternity(&t->srexpire);
3734 fd_delete(t->srv_fd);
3735 //close(t->srv_fd);
3736 t->srv_state = SV_STCLOSE;
3737 if (!(t->flags & SN_ERR_MASK))
3738 t->flags |= SN_ERR_SRVTO;
3739 if (!(t->flags & SN_FINST_MASK))
3740 t->flags |= SN_FINST_D;
3741 return 1;
3742 }
willy tarreau0f7af912005-12-17 12:21:26 +01003743 else if (rep->l == BUFSIZE) { /* no room to read more data */
3744 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3745 FD_CLR(t->srv_fd, StaticReadEvent);
3746 tv_eternity(&t->srexpire);
3747 }
3748 }
3749 else {
3750 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3751 FD_SET(t->srv_fd, StaticReadEvent);
3752 if (t->proxy->srvtimeout)
3753 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3754 else
3755 tv_eternity(&t->srexpire);
3756 }
3757 }
3758 return 0;
3759 }
3760 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003761 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003762 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003763 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 +01003764 write(1, trash, len);
3765 }
3766 return 0;
3767 }
3768 return 0;
3769}
3770
3771
willy tarreau5cbea6f2005-12-17 12:48:26 +01003772/* Processes the client and server jobs of a session task, then
3773 * puts it back to the wait queue in a clean state, or
3774 * cleans up its resources if it must be deleted. Returns
3775 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003776 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003777int process_session(struct task *t) {
3778 struct session *s = t->context;
3779 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003780
willy tarreau5cbea6f2005-12-17 12:48:26 +01003781 do {
3782 fsm_resync = 0;
3783 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3784 fsm_resync |= process_cli(s);
3785 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3786 fsm_resync |= process_srv(s);
3787 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3788 } while (fsm_resync);
3789
3790 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003791 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003792 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003793
willy tarreau5cbea6f2005-12-17 12:48:26 +01003794 tv_min(&min1, &s->crexpire, &s->cwexpire);
3795 tv_min(&min2, &s->srexpire, &s->swexpire);
3796 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003797 tv_min(&t->expire, &min1, &min2);
3798
3799 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003800 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003801
willy tarreau5cbea6f2005-12-17 12:48:26 +01003802 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003803 }
3804
willy tarreau5cbea6f2005-12-17 12:48:26 +01003805 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003806 actconn--;
3807
willy tarreau9fe663a2005-12-17 13:02:59 +01003808 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003809 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003810 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 +01003811 write(1, trash, len);
3812 }
3813
willy tarreau750a4722005-12-17 13:21:24 +01003814 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003815 if (s->rep != NULL)
3816 s->logs.bytes = s->rep->total;
3817
willy tarreau9fe663a2005-12-17 13:02:59 +01003818 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003819 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003820 sess_log(s);
3821
willy tarreau0f7af912005-12-17 12:21:26 +01003822 /* the task MUST not be in the run queue anymore */
3823 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003824 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003825 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003826 return -1; /* rest in peace for eternity */
3827}
3828
3829
3830
3831/*
3832 * manages a server health-check. Returns
3833 * the time the task accepts to wait, or -1 for infinity.
3834 */
3835int process_chk(struct task *t) {
3836 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01003837 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003838 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003839
willy tarreauef900ab2005-12-17 12:52:52 +01003840 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003841
3842 if (fd < 0) { /* no check currently running */
3843 //fprintf(stderr, "process_chk: 2\n");
3844 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3845 task_queue(t); /* restore t to its place in the task list */
3846 return tv_remain(&now, &t->expire);
3847 }
3848
3849 /* we'll initiate a new check */
3850 s->result = 0; /* no result yet */
3851 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003852 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003853 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3854 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3855 //fprintf(stderr, "process_chk: 3\n");
3856
willy tarreaua41a8b42005-12-17 14:02:24 +01003857 /* we'll connect to the check port on the server */
3858 sa = s->addr;
3859 sa.sin_port = htons(s->check_port);
3860
willy tarreau036e1ce2005-12-17 13:46:33 +01003861 /* allow specific binding */
3862 if (s->proxy->options & PR_O_BIND_SRC &&
3863 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
3864 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
3865 close(fd);
3866 s->result = -1;
3867 }
willy tarreaua41a8b42005-12-17 14:02:24 +01003868 else if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003869 /* OK, connection in progress or established */
3870
3871 //fprintf(stderr, "process_chk: 4\n");
3872
3873 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3874 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003875 fdtab[fd].read = &event_srv_chk_r;
3876 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003877 fdtab[fd].state = FD_STCONN; /* connection in progress */
3878 FD_SET(fd, StaticWriteEvent); /* for connect status */
3879 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003880 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3881 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003882 task_queue(t); /* restore t to its place in the task list */
3883 return tv_remain(&now, &t->expire);
3884 }
3885 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3886 s->result = -1; /* a real error */
3887 }
3888 }
3889 //fprintf(stderr, "process_chk: 5\n");
3890 close(fd);
3891 }
3892
3893 if (!s->result) { /* nothing done */
3894 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003895 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003896 task_queue(t); /* restore t to its place in the task list */
3897 return tv_remain(&now, &t->expire);
3898 }
3899
3900 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003901 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003902 s->health--; /* still good */
3903 else {
willy tarreaudd07e972005-12-18 00:48:48 +01003904 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01003905 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01003906 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003907 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01003908
willy tarreaudd07e972005-12-18 00:48:48 +01003909 if (find_server(s->proxy) == NULL) {
3910 Alert("Proxy %s has no server available !\n", s->proxy->id);
3911 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
3912 }
3913 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003914 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003915 }
3916
3917 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003918 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3919 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003920 }
3921 else {
3922 //fprintf(stderr, "process_chk: 8\n");
3923 /* there was a test running */
3924 if (s->result > 0) { /* good server detected */
3925 //fprintf(stderr, "process_chk: 9\n");
3926 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003927 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003928 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01003929 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003930 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003931 }
willy tarreauef900ab2005-12-17 12:52:52 +01003932
willy tarreaue47c8d72005-12-17 12:55:52 +01003933 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003934 s->state |= SRV_RUNNING;
3935 }
willy tarreauef900ab2005-12-17 12:52:52 +01003936 s->curfd = -1; /* no check running anymore */
3937 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003938 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003939 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003940 }
3941 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3942 //fprintf(stderr, "process_chk: 10\n");
3943 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003944 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003945 s->health--; /* still good */
3946 else {
willy tarreaudd07e972005-12-18 00:48:48 +01003947 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01003948
willy tarreaudd07e972005-12-18 00:48:48 +01003949 if (s->health == s->rise) {
3950 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003951 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01003952
3953 if (find_server(s->proxy) == NULL) {
3954 Alert("Proxy %s has no server available !\n", s->proxy->id);
3955 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
3956 }
willy tarreau535ae7a2005-12-17 12:58:00 +01003957 }
willy tarreauef900ab2005-12-17 12:52:52 +01003958
willy tarreau5cbea6f2005-12-17 12:48:26 +01003959 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003960 }
3961 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003962 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003963 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003964 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003965 }
3966 /* if result is 0 and there's no timeout, we have to wait again */
3967 }
3968 //fprintf(stderr, "process_chk: 11\n");
3969 s->result = 0;
3970 task_queue(t); /* restore t to its place in the task list */
3971 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003972}
3973
3974
willy tarreau5cbea6f2005-12-17 12:48:26 +01003975
willy tarreau0f7af912005-12-17 12:21:26 +01003976#if STATTIME > 0
3977int stats(void);
3978#endif
3979
3980/*
3981 * Main select() loop.
3982 */
3983
3984void select_loop() {
3985 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003986 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003987 int status;
3988 int fd,i;
3989 struct timeval delta;
3990 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003991 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003992
willy tarreau5cbea6f2005-12-17 12:48:26 +01003993 tv_now(&now);
3994
3995 while (1) {
3996 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003997
willy tarreau5cbea6f2005-12-17 12:48:26 +01003998 /* look for expired tasks and add them to the run queue.
3999 */
4000 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4001 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4002 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01004003 if (t->state & TASK_RUNNING)
4004 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004005
4006 /* wakeup expired entries. It doesn't matter if they are
4007 * already running because of a previous event
4008 */
4009 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01004010 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004011 task_wakeup(&rq, t);
4012 }
4013 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004014 /* first non-runnable task. Use its expiration date as an upper bound */
4015 int temp_time = tv_remain(&now, &t->expire);
4016 if (temp_time)
4017 next_time = temp_time;
4018 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004019 break;
4020 }
4021 }
4022
4023 /* process each task in the run queue now. Each task may be deleted
4024 * since we only use tnext.
4025 */
4026 tnext = rq;
4027 while ((t = tnext) != NULL) {
4028 int temp_time;
4029
4030 tnext = t->rqnext;
4031 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01004032 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004033 temp_time = t->process(t);
4034 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01004035 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004036 }
4037
willy tarreauef900ab2005-12-17 12:52:52 +01004038 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01004039
4040 /* maintain all proxies in a consistent state. This should quickly become a task */
4041 time2 = maintain_proxies();
4042 next_time = MINTIME(time2, next_time);
4043
4044 /* stop when there's no connection left and we don't allow them anymore */
4045 if (!actconn && listeners == 0)
4046 break;
4047
willy tarreau0f7af912005-12-17 12:21:26 +01004048
4049#if STATTIME > 0
4050 time2 = stats();
4051 // fprintf(stderr," stats = %d\n", time2);
4052 next_time = MINTIME(time2, next_time);
4053#endif
4054
willy tarreau5cbea6f2005-12-17 12:48:26 +01004055 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01004056 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004057 /* to avoid eventual select loops due to timer precision */
4058 next_time += SCHEDULER_RESOLUTION;
4059 delta.tv_sec = next_time / 1000;
4060 delta.tv_usec = (next_time % 1000) * 1000;
4061 }
4062 else if (next_time == 0) { /* allow select to return immediately when needed */
4063 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004064 }
4065
4066
4067 /* let's restore fdset state */
4068
4069 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004070 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004071 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
4072 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
4073 }
4074
4075// /* just a verification code, needs to be removed for performance */
4076// for (i=0; i<maxfd; i++) {
4077// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
4078// abort();
4079// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
4080// abort();
4081//
4082// }
4083
willy tarreau197e8ec2005-12-17 14:10:59 +01004084 status = select(maxfd,
4085 readnotnull ? ReadEvent : NULL,
4086 writenotnull ? WriteEvent : NULL,
4087 NULL,
4088 (next_time >= 0) ? &delta : NULL);
willy tarreau0f7af912005-12-17 12:21:26 +01004089
willy tarreau5cbea6f2005-12-17 12:48:26 +01004090 /* this is an experiment on the separation of the select work */
4091 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4092 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4093
willy tarreau0f7af912005-12-17 12:21:26 +01004094 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004095
willy tarreau0f7af912005-12-17 12:21:26 +01004096 if (status > 0) { /* must proceed with events */
4097
4098 int fds;
4099 char count;
4100
4101 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
4102 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
4103 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
4104
willy tarreau5cbea6f2005-12-17 12:48:26 +01004105 /* if we specify read first, the accepts and zero reads will be
4106 * seen first. Moreover, system buffers will be flushed faster.
4107 */
willy tarreau0f7af912005-12-17 12:21:26 +01004108 if (fdtab[fd].state == FD_STCLOSE)
4109 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01004110
4111 if (FD_ISSET(fd, ReadEvent))
4112 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004113
willy tarreau5cbea6f2005-12-17 12:48:26 +01004114 if (FD_ISSET(fd, WriteEvent))
4115 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004116 }
4117 }
4118 else {
4119 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
4120 }
willy tarreau0f7af912005-12-17 12:21:26 +01004121 }
4122}
4123
4124
4125#if STATTIME > 0
4126/*
4127 * Display proxy statistics regularly. It is designed to be called from the
4128 * select_loop().
4129 */
4130int stats(void) {
4131 static int lines;
4132 static struct timeval nextevt;
4133 static struct timeval lastevt;
4134 static struct timeval starttime = {0,0};
4135 unsigned long totaltime, deltatime;
4136 int ret;
4137
willy tarreau750a4722005-12-17 13:21:24 +01004138 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01004139 deltatime = (tv_diff(&lastevt, &now)?:1);
4140 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01004141
willy tarreau9fe663a2005-12-17 13:02:59 +01004142 if (global.mode & MODE_STATS) {
4143 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004144 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004145 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
4146 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004147 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004148 actconn, totalconn,
4149 stats_tsk_new, stats_tsk_good,
4150 stats_tsk_left, stats_tsk_right,
4151 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
4152 }
4153 }
4154
4155 tv_delayfrom(&nextevt, &now, STATTIME);
4156
4157 lastevt=now;
4158 }
4159 ret = tv_remain(&now, &nextevt);
4160 return ret;
4161}
4162#endif
4163
4164
4165/*
4166 * this function enables proxies when there are enough free sessions,
4167 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01004168 * select_loop(). It returns the time left before next expiration event
4169 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01004170 */
4171static int maintain_proxies(void) {
4172 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01004173 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004174 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01004175
4176 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004177 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01004178
4179 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01004180 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01004181 while (p) {
4182 if (p->nbconn < p->maxconn) {
4183 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004184 for (l = p->listen; l != NULL; l = l->next) {
4185 FD_SET(l->fd, StaticReadEvent);
4186 }
willy tarreau0f7af912005-12-17 12:21:26 +01004187 p->state = PR_STRUN;
4188 }
4189 }
4190 else {
4191 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004192 for (l = p->listen; l != NULL; l = l->next) {
4193 FD_CLR(l->fd, StaticReadEvent);
4194 }
willy tarreau0f7af912005-12-17 12:21:26 +01004195 p->state = PR_STIDLE;
4196 }
4197 }
4198 p = p->next;
4199 }
4200 }
4201 else { /* block all proxies */
4202 while (p) {
4203 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004204 for (l = p->listen; l != NULL; l = l->next) {
4205 FD_CLR(l->fd, StaticReadEvent);
4206 }
willy tarreau0f7af912005-12-17 12:21:26 +01004207 p->state = PR_STIDLE;
4208 }
4209 p = p->next;
4210 }
4211 }
4212
willy tarreau5cbea6f2005-12-17 12:48:26 +01004213 if (stopping) {
4214 p = proxy;
4215 while (p) {
4216 if (p->state != PR_STDISABLED) {
4217 int t;
4218 t = tv_remain(&now, &p->stop_time);
4219 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004220 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004221 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004222
willy tarreaua41a8b42005-12-17 14:02:24 +01004223 for (l = p->listen; l != NULL; l = l->next) {
4224 fd_delete(l->fd);
4225 listeners--;
4226 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004227 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004228 }
4229 else {
4230 tleft = MINTIME(t, tleft);
4231 }
4232 }
4233 p = p->next;
4234 }
4235 }
4236 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004237}
4238
4239/*
4240 * this function disables health-check servers so that the process will quickly be ignored
4241 * by load balancers.
4242 */
4243static void soft_stop(void) {
4244 struct proxy *p;
4245
4246 stopping = 1;
4247 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004248 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004249 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004250 if (p->state != PR_STDISABLED) {
4251 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004252 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004253 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004254 }
willy tarreau0f7af912005-12-17 12:21:26 +01004255 p = p->next;
4256 }
4257}
4258
4259/*
4260 * upon SIGUSR1, let's have a soft stop.
4261 */
4262void sig_soft_stop(int sig) {
4263 soft_stop();
4264 signal(sig, SIG_IGN);
4265}
4266
4267
willy tarreau8337c6b2005-12-17 13:41:01 +01004268/*
4269 * this function dumps every server's state when the process receives SIGHUP.
4270 */
4271void sig_dump_state(int sig) {
4272 struct proxy *p = proxy;
4273
4274 Warning("SIGHUP received, dumping servers states.\n");
4275 while (p) {
4276 struct server *s = p->srv;
4277
4278 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4279 while (s) {
4280 if (s->state & SRV_RUNNING) {
4281 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4282 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4283 }
4284 else {
4285 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4286 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4287 }
4288 s = s->next;
4289 }
willy tarreaudd07e972005-12-18 00:48:48 +01004290
4291 if (find_server(p) == NULL) {
4292 Warning("SIGHUP: proxy %s has no server available !\n", p);
4293 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
4294 }
4295
willy tarreau8337c6b2005-12-17 13:41:01 +01004296 p = p->next;
4297 }
4298 signal(sig, sig_dump_state);
4299}
4300
willy tarreau0f7af912005-12-17 12:21:26 +01004301void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004302 struct task *t, *tnext;
4303 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004304
willy tarreau5cbea6f2005-12-17 12:48:26 +01004305 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4306 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4307 tnext = t->next;
4308 s = t->context;
4309 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4310 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4311 "req=%d, rep=%d, clifd=%d\n",
4312 s, tv_remain(&now, &t->expire),
4313 s->cli_state,
4314 s->srv_state,
4315 FD_ISSET(s->cli_fd, StaticReadEvent),
4316 FD_ISSET(s->cli_fd, StaticWriteEvent),
4317 FD_ISSET(s->srv_fd, StaticReadEvent),
4318 FD_ISSET(s->srv_fd, StaticWriteEvent),
4319 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4320 );
willy tarreau0f7af912005-12-17 12:21:26 +01004321 }
4322}
4323
willy tarreaue39cd132005-12-17 13:00:18 +01004324void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4325 struct hdr_exp *exp;
4326
4327 while (*head != NULL)
4328 head = &(*head)->next;
4329
4330 exp = calloc(1, sizeof(struct hdr_exp));
4331
4332 exp->preg = preg;
4333 exp->replace = replace;
4334 exp->action = action;
4335 *head = exp;
4336}
4337
willy tarreau9fe663a2005-12-17 13:02:59 +01004338
willy tarreau0f7af912005-12-17 12:21:26 +01004339/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004340 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004341 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004342int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004343
willy tarreau9fe663a2005-12-17 13:02:59 +01004344 if (!strcmp(args[0], "global")) { /* new section */
4345 /* no option, nothing special to do */
4346 return 0;
4347 }
4348 else if (!strcmp(args[0], "daemon")) {
4349 global.mode |= MODE_DAEMON;
4350 }
4351 else if (!strcmp(args[0], "debug")) {
4352 global.mode |= MODE_DEBUG;
4353 }
4354 else if (!strcmp(args[0], "quiet")) {
4355 global.mode |= MODE_QUIET;
4356 }
4357 else if (!strcmp(args[0], "stats")) {
4358 global.mode |= MODE_STATS;
4359 }
4360 else if (!strcmp(args[0], "uid")) {
4361 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004362 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004363 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004364 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004365 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004366 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004367 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004368 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004369 global.uid = atol(args[1]);
4370 }
4371 else if (!strcmp(args[0], "gid")) {
4372 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004373 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004374 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004375 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004376 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004377 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004378 return -1;
4379 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004380 global.gid = atol(args[1]);
4381 }
4382 else if (!strcmp(args[0], "nbproc")) {
4383 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004384 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004385 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004386 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004387 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004388 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004389 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004390 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004391 global.nbproc = atol(args[1]);
4392 }
4393 else if (!strcmp(args[0], "maxconn")) {
4394 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004395 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004396 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004397 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004398 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004399 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004400 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004401 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004402 global.maxconn = atol(args[1]);
4403 }
4404 else if (!strcmp(args[0], "chroot")) {
4405 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004406 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004407 return 0;
4408 }
4409 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004410 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004411 return -1;
4412 }
4413 global.chroot = strdup(args[1]);
4414 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01004415 else if (!strcmp(args[0], "pidfile")) {
4416 if (global.pidfile != NULL) {
4417 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
4418 return 0;
4419 }
4420 if (*(args[1]) == 0) {
4421 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
4422 return -1;
4423 }
4424 global.pidfile = strdup(args[1]);
4425 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004426 else if (!strcmp(args[0], "log")) { /* syslog server address */
4427 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004428 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004429
4430 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004431 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004432 return -1;
4433 }
4434
4435 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4436 if (!strcmp(log_facilities[facility], args[2]))
4437 break;
4438
4439 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004440 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004441 exit(1);
4442 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004443
4444 level = 7; /* max syslog level = debug */
4445 if (*(args[3])) {
4446 while (level >= 0 && strcmp(log_levels[level], args[3]))
4447 level--;
4448 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004449 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004450 exit(1);
4451 }
4452 }
4453
willy tarreau9fe663a2005-12-17 13:02:59 +01004454 sa = str2sa(args[1]);
4455 if (!sa->sin_port)
4456 sa->sin_port = htons(SYSLOG_PORT);
4457
4458 if (global.logfac1 == -1) {
4459 global.logsrv1 = *sa;
4460 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004461 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004462 }
4463 else if (global.logfac2 == -1) {
4464 global.logsrv2 = *sa;
4465 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004466 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004467 }
4468 else {
4469 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4470 return -1;
4471 }
4472
4473 }
4474 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004475 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004476 return -1;
4477 }
4478 return 0;
4479}
4480
4481
willy tarreaua41a8b42005-12-17 14:02:24 +01004482void init_default_instance() {
4483 memset(&defproxy, 0, sizeof(defproxy));
4484 defproxy.mode = PR_MODE_TCP;
4485 defproxy.state = PR_STNEW;
4486 defproxy.maxconn = cfg_maxpconn;
4487 defproxy.conn_retries = CONN_RETRIES;
4488 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
4489}
4490
willy tarreau9fe663a2005-12-17 13:02:59 +01004491/*
4492 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4493 */
4494int cfg_parse_listen(char *file, int linenum, char **args) {
4495 static struct proxy *curproxy = NULL;
4496 struct server *newsrv = NULL;
4497
4498 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01004499 if (!*args[1]) {
4500 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
4501 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004502 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004503 return -1;
4504 }
4505
4506 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004507 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004508 return -1;
4509 }
4510 curproxy->next = proxy;
4511 proxy = curproxy;
4512 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01004513 if (strchr(args[2], ':') != NULL)
4514 curproxy->listen = str2listener(args[2], curproxy->listen);
4515
willy tarreau9fe663a2005-12-17 13:02:59 +01004516 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01004517 curproxy->state = defproxy.state;
4518 curproxy->maxconn = defproxy.maxconn;
4519 curproxy->conn_retries = defproxy.conn_retries;
4520 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004521
4522 if (defproxy.check_req)
4523 curproxy->check_req = strdup(defproxy.check_req);
4524 curproxy->check_len = defproxy.check_len;
4525
4526 if (defproxy.cookie_name)
4527 curproxy->cookie_name = strdup(defproxy.cookie_name);
4528 curproxy->cookie_len = defproxy.cookie_len;
4529
4530 if (defproxy.capture_name)
4531 curproxy->capture_name = strdup(defproxy.capture_name);
4532 curproxy->capture_namelen = defproxy.capture_namelen;
4533 curproxy->capture_len = defproxy.capture_len;
4534
4535 if (defproxy.errmsg.msg400)
4536 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
4537 curproxy->errmsg.len400 = defproxy.errmsg.len400;
4538
4539 if (defproxy.errmsg.msg403)
4540 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
4541 curproxy->errmsg.len403 = defproxy.errmsg.len403;
4542
4543 if (defproxy.errmsg.msg408)
4544 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
4545 curproxy->errmsg.len408 = defproxy.errmsg.len408;
4546
4547 if (defproxy.errmsg.msg500)
4548 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
4549 curproxy->errmsg.len500 = defproxy.errmsg.len500;
4550
4551 if (defproxy.errmsg.msg502)
4552 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
4553 curproxy->errmsg.len502 = defproxy.errmsg.len502;
4554
4555 if (defproxy.errmsg.msg503)
4556 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
4557 curproxy->errmsg.len503 = defproxy.errmsg.len503;
4558
4559 if (defproxy.errmsg.msg504)
4560 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
4561 curproxy->errmsg.len504 = defproxy.errmsg.len504;
4562
willy tarreaua41a8b42005-12-17 14:02:24 +01004563 curproxy->clitimeout = defproxy.clitimeout;
4564 curproxy->contimeout = defproxy.contimeout;
4565 curproxy->srvtimeout = defproxy.srvtimeout;
4566 curproxy->mode = defproxy.mode;
4567 curproxy->logfac1 = defproxy.logfac1;
4568 curproxy->logsrv1 = defproxy.logsrv1;
4569 curproxy->loglev1 = defproxy.loglev1;
4570 curproxy->logfac2 = defproxy.logfac2;
4571 curproxy->logsrv2 = defproxy.logsrv2;
4572 curproxy->loglev2 = defproxy.loglev2;
4573 curproxy->to_log = defproxy.to_log;
4574 curproxy->grace = defproxy.grace;
4575 curproxy->source_addr = defproxy.source_addr;
4576 return 0;
4577 }
4578 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004579 /* some variables may have already been initialized earlier */
4580 if (defproxy.check_req) free(defproxy.check_req);
4581 if (defproxy.cookie_name) free(defproxy.cookie_name);
4582 if (defproxy.capture_name) free(defproxy.capture_name);
4583 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
4584 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
4585 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
4586 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
4587 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
4588 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
4589 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
4590
4591 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01004592 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01004593 return 0;
4594 }
4595 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004596 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004597 return -1;
4598 }
4599
willy tarreaua41a8b42005-12-17 14:02:24 +01004600 if (!strcmp(args[0], "bind")) { /* new listen addresses */
4601 if (curproxy == &defproxy) {
4602 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4603 return -1;
4604 }
4605
4606 if (strchr(args[1], ':') == NULL) {
4607 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
4608 file, linenum, args[0]);
4609 return -1;
4610 }
4611 curproxy->listen = str2listener(args[1], curproxy->listen);
4612 return 0;
4613 }
4614 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01004615 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
4616 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
4617 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
4618 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004619 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004620 return -1;
4621 }
4622 }
4623 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
4624 curproxy->state = PR_STDISABLED;
4625 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004626 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
4627 curproxy->state = PR_STNEW;
4628 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004629 else if (!strcmp(args[0], "cookie")) { /* cookie name */
4630 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004631// if (curproxy == &defproxy) {
4632// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4633// return -1;
4634// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004635
willy tarreau9fe663a2005-12-17 13:02:59 +01004636 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004637// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
4638// file, linenum);
4639// return 0;
4640 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004641 }
4642
4643 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004644 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
4645 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004646 return -1;
4647 }
4648 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004649 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004650
4651 cur_arg = 2;
4652 while (*(args[cur_arg])) {
4653 if (!strcmp(args[cur_arg], "rewrite")) {
4654 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01004655 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004656 else if (!strcmp(args[cur_arg], "indirect")) {
4657 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01004658 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004659 else if (!strcmp(args[cur_arg], "insert")) {
4660 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01004661 }
willy tarreau240afa62005-12-17 13:14:35 +01004662 else if (!strcmp(args[cur_arg], "nocache")) {
4663 curproxy->options |= PR_O_COOK_NOC;
4664 }
willy tarreaucd878942005-12-17 13:27:43 +01004665 else if (!strcmp(args[cur_arg], "postonly")) {
4666 curproxy->options |= PR_O_COOK_POST;
4667 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004668 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004669 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
4670 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004671 return -1;
4672 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004673 cur_arg++;
4674 }
4675 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004676 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004677 file, linenum);
4678 return -1;
4679 }
4680 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004681 else if (!strcmp(args[0], "capture")) { /* name of a cookie to capture */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004682// if (curproxy == &defproxy) {
4683// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4684// return -1;
4685// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004686
willy tarreau8337c6b2005-12-17 13:41:01 +01004687 if (curproxy->capture_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004688// Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4689// file, linenum, args[0]);
4690// return 0;
4691 free(curproxy->capture_name);
willy tarreau8337c6b2005-12-17 13:41:01 +01004692 }
4693
4694 if (*(args[4]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004695 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
4696 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004697 return -1;
4698 }
4699 curproxy->capture_name = strdup(args[2]);
4700 curproxy->capture_namelen = strlen(curproxy->capture_name);
4701 curproxy->capture_len = atol(args[4]);
4702 if (curproxy->capture_len >= CAPTURE_LEN) {
4703 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
4704 file, linenum, CAPTURE_LEN - 1);
4705 curproxy->capture_len = CAPTURE_LEN - 1;
4706 }
4707 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004708 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004709 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004710 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004711 return 0;
4712 }
4713 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004714 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4715 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004716 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004717 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004718 curproxy->contimeout = atol(args[1]);
4719 }
4720 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004721 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004722 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4723 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004724 return 0;
4725 }
4726 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004727 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4728 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004729 return -1;
4730 }
4731 curproxy->clitimeout = atol(args[1]);
4732 }
4733 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004734 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004735 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004736 return 0;
4737 }
4738 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004739 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4740 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004741 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004742 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004743 curproxy->srvtimeout = atol(args[1]);
4744 }
4745 else if (!strcmp(args[0], "retries")) { /* connection retries */
4746 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004747 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
4748 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004749 return -1;
4750 }
4751 curproxy->conn_retries = atol(args[1]);
4752 }
4753 else if (!strcmp(args[0], "option")) {
4754 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004755 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004756 return -1;
4757 }
4758 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004759 /* enable reconnections to dispatch */
4760 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004761#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004762 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004763 /* enable transparent proxy connections */
4764 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004765#endif
4766 else if (!strcmp(args[1], "keepalive"))
4767 /* enable keep-alive */
4768 curproxy->options |= PR_O_KEEPALIVE;
4769 else if (!strcmp(args[1], "forwardfor"))
4770 /* insert x-forwarded-for field */
4771 curproxy->options |= PR_O_FWDFOR;
willy tarreauc1cae632005-12-17 14:12:23 +01004772 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01004773 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01004774 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
willy tarreauc1cae632005-12-17 14:12:23 +01004775 else if (!strcmp(args[1], "tcplog"))
4776 /* generate a detailed TCP log */
4777 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID;
willy tarreaua1598082005-12-17 13:08:06 +01004778 else if (!strcmp(args[1], "dontlognull")) {
4779 /* don't log empty requests */
4780 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004781 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004782 else if (!strcmp(args[1], "httpchk")) {
4783 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004784 if (curproxy->check_req != NULL) {
4785 free(curproxy->check_req);
4786 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004787 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004788 if (!*args[2]) { /* no argument */
4789 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
4790 curproxy->check_len = strlen(DEF_CHECK_REQ);
4791 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01004792 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
4793 curproxy->check_req = (char *)malloc(reqlen);
4794 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4795 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004796 } else { /* more arguments : METHOD URI [HTTP_VER] */
4797 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
4798 if (*args[4])
4799 reqlen += strlen(args[4]);
4800 else
4801 reqlen += strlen("HTTP/1.0");
4802
4803 curproxy->check_req = (char *)malloc(reqlen);
4804 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4805 "%s %s %s\r\n\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
willy tarreau2f6ba652005-12-17 13:57:42 +01004806 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004807 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004808 else if (!strcmp(args[1], "persist")) {
4809 /* persist on using the server specified by the cookie, even when it's down */
4810 curproxy->options |= PR_O_PERSIST;
4811 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004812 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004813 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004814 return -1;
4815 }
4816 return 0;
4817 }
4818 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4819 /* enable reconnections to dispatch */
4820 curproxy->options |= PR_O_REDISP;
4821 }
willy tarreaua1598082005-12-17 13:08:06 +01004822#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004823 else if (!strcmp(args[0], "transparent")) {
4824 /* enable transparent proxy connections */
4825 curproxy->options |= PR_O_TRANSP;
4826 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004827#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004828 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4829 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004830 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004831 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004832 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004833 curproxy->maxconn = atol(args[1]);
4834 }
4835 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4836 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004837 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004838 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004839 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004840 curproxy->grace = atol(args[1]);
4841 }
4842 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01004843 if (curproxy == &defproxy) {
4844 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4845 return -1;
4846 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004847 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004848 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004849 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004850 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004851 curproxy->dispatch_addr = *str2sa(args[1]);
4852 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004853 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01004854 if (*(args[1])) {
4855 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004856 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004857 }
4858 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004859 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004860 return -1;
4861 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004862 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004863 else /* if no option is set, use round-robin by default */
4864 curproxy->options |= PR_O_BALANCE_RR;
4865 }
4866 else if (!strcmp(args[0], "server")) { /* server address */
4867 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004868 char *rport;
4869 char *raddr;
4870 short realport;
4871 int do_check;
4872
4873 if (curproxy == &defproxy) {
4874 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4875 return -1;
4876 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004877
willy tarreaua41a8b42005-12-17 14:02:24 +01004878 if (!*args[2]) {
4879 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004880 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004881 return -1;
4882 }
4883 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4884 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4885 return -1;
4886 }
4887 newsrv->next = curproxy->srv;
4888 curproxy->srv = newsrv;
4889 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01004890
4891 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004892 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01004893 newsrv->id = strdup(args[1]);
4894
4895 /* several ways to check the port component :
4896 * - IP => port=+0, relative
4897 * - IP: => port=+0, relative
4898 * - IP:N => port=N, absolute
4899 * - IP:+N => port=+N, relative
4900 * - IP:-N => port=-N, relative
4901 */
4902 raddr = strdup(args[2]);
4903 rport = strchr(raddr, ':');
4904 if (rport) {
4905 *rport++ = 0;
4906 realport = atol(rport);
4907 if (!isdigit((int)*rport))
4908 newsrv->state |= SRV_MAPPORTS;
4909 } else {
4910 realport = 0;
4911 newsrv->state |= SRV_MAPPORTS;
4912 }
4913
4914 newsrv->addr = *str2sa(raddr);
4915 newsrv->addr.sin_port = htons(realport);
4916 free(raddr);
4917
willy tarreau9fe663a2005-12-17 13:02:59 +01004918 newsrv->curfd = -1; /* no health-check in progress */
4919 newsrv->inter = DEF_CHKINTR;
4920 newsrv->rise = DEF_RISETIME;
4921 newsrv->fall = DEF_FALLTIME;
4922 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4923 cur_arg = 3;
4924 while (*args[cur_arg]) {
4925 if (!strcmp(args[cur_arg], "cookie")) {
4926 newsrv->cookie = strdup(args[cur_arg + 1]);
4927 newsrv->cklen = strlen(args[cur_arg + 1]);
4928 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004929 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004930 else if (!strcmp(args[cur_arg], "rise")) {
4931 newsrv->rise = atol(args[cur_arg + 1]);
4932 newsrv->health = newsrv->rise;
4933 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004934 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004935 else if (!strcmp(args[cur_arg], "fall")) {
4936 newsrv->fall = atol(args[cur_arg + 1]);
4937 cur_arg += 2;
4938 }
4939 else if (!strcmp(args[cur_arg], "inter")) {
4940 newsrv->inter = atol(args[cur_arg + 1]);
4941 cur_arg += 2;
4942 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004943 else if (!strcmp(args[cur_arg], "port")) {
4944 newsrv->check_port = atol(args[cur_arg + 1]);
4945 cur_arg += 2;
4946 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004947 else if (!strcmp(args[cur_arg], "backup")) {
4948 newsrv->state |= SRV_BACKUP;
4949 cur_arg ++;
4950 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004951 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004952 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004953 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004954 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004955 else {
willy tarreaua41a8b42005-12-17 14:02:24 +01004956 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
4957 file, linenum, newsrv->id);
4958 return -1;
4959 }
4960 }
4961
4962 if (do_check) {
4963 struct task *t;
4964
4965 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
4966 newsrv->check_port = realport; /* by default */
4967 if (!newsrv->check_port) {
4968 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004969 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004970 return -1;
4971 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004972
4973 if ((t = pool_alloc(task)) == NULL) {
4974 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4975 return -1;
4976 }
4977
4978 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4979 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4980 t->state = TASK_IDLE;
4981 t->process = process_chk;
4982 t->context = newsrv;
4983
4984 if (curproxy->state != PR_STDISABLED) {
4985 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4986 task_queue(t);
4987 task_wakeup(&rq, t);
4988 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004989 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004990
willy tarreau9fe663a2005-12-17 13:02:59 +01004991 curproxy->nbservers++;
4992 }
4993 else if (!strcmp(args[0], "log")) { /* syslog server address */
4994 struct sockaddr_in *sa;
4995 int facility;
4996
4997 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4998 curproxy->logfac1 = global.logfac1;
4999 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005000 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005001 curproxy->logfac2 = global.logfac2;
5002 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01005003 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01005004 }
5005 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01005006 int level;
5007
willy tarreau0f7af912005-12-17 12:21:26 +01005008 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5009 if (!strcmp(log_facilities[facility], args[2]))
5010 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01005011
willy tarreau0f7af912005-12-17 12:21:26 +01005012 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005013 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01005014 exit(1);
5015 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005016
willy tarreau8337c6b2005-12-17 13:41:01 +01005017 level = 7; /* max syslog level = debug */
5018 if (*(args[3])) {
5019 while (level >= 0 && strcmp(log_levels[level], args[3]))
5020 level--;
5021 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005022 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005023 exit(1);
5024 }
5025 }
5026
willy tarreau0f7af912005-12-17 12:21:26 +01005027 sa = str2sa(args[1]);
5028 if (!sa->sin_port)
5029 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01005030
willy tarreau0f7af912005-12-17 12:21:26 +01005031 if (curproxy->logfac1 == -1) {
5032 curproxy->logsrv1 = *sa;
5033 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005034 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005035 }
5036 else if (curproxy->logfac2 == -1) {
5037 curproxy->logsrv2 = *sa;
5038 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005039 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005040 }
5041 else {
5042 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005043 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005044 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005045 }
5046 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005047 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005048 file, linenum);
5049 return -1;
5050 }
5051 }
willy tarreaua1598082005-12-17 13:08:06 +01005052 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01005053 if (!*args[1]) {
5054 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005055 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01005056 return -1;
5057 }
5058
5059 curproxy->source_addr = *str2sa(args[1]);
5060 curproxy->options |= PR_O_BIND_SRC;
5061 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005062 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
5063 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005064 if (curproxy == &defproxy) {
5065 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5066 return -1;
5067 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005068
5069 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005070 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5071 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005072 return -1;
5073 }
5074
5075 preg = calloc(1, sizeof(regex_t));
5076 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005077 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005078 return -1;
5079 }
5080
5081 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5082 }
5083 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
5084 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005085 if (curproxy == &defproxy) {
5086 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5087 return -1;
5088 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005089
5090 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005091 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005092 return -1;
5093 }
5094
5095 preg = calloc(1, sizeof(regex_t));
5096 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005097 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005098 return -1;
5099 }
5100
5101 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5102 }
5103 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
5104 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005105 if (curproxy == &defproxy) {
5106 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5107 return -1;
5108 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005109
5110 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005111 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005112 return -1;
5113 }
5114
5115 preg = calloc(1, sizeof(regex_t));
5116 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005117 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005118 return -1;
5119 }
5120
5121 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5122 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005123 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
5124 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005125 if (curproxy == &defproxy) {
5126 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5127 return -1;
5128 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005129
5130 if (*(args[1]) == 0) {
5131 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5132 return -1;
5133 }
5134
5135 preg = calloc(1, sizeof(regex_t));
5136 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5137 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5138 return -1;
5139 }
5140
5141 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5142 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005143 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
5144 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005145 if (curproxy == &defproxy) {
5146 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5147 return -1;
5148 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005149
5150 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005151 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005152 return -1;
5153 }
5154
5155 preg = calloc(1, sizeof(regex_t));
5156 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005157 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005158 return -1;
5159 }
5160
5161 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5162 }
5163 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
5164 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005165 if (curproxy == &defproxy) {
5166 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5167 return -1;
5168 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005169
5170 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005171 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5172 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005173 return -1;
5174 }
5175
5176 preg = calloc(1, sizeof(regex_t));
5177 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005178 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005179 return -1;
5180 }
5181
5182 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5183 }
5184 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
5185 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005186 if (curproxy == &defproxy) {
5187 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5188 return -1;
5189 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005190
5191 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005192 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005193 return -1;
5194 }
5195
5196 preg = calloc(1, sizeof(regex_t));
5197 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005198 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005199 return -1;
5200 }
5201
5202 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5203 }
5204 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
5205 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005206 if (curproxy == &defproxy) {
5207 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5208 return -1;
5209 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005210
5211 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005212 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005213 return -1;
5214 }
5215
5216 preg = calloc(1, sizeof(regex_t));
5217 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005218 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005219 return -1;
5220 }
5221
5222 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5223 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005224 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
5225 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005226 if (curproxy == &defproxy) {
5227 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5228 return -1;
5229 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005230
5231 if (*(args[1]) == 0) {
5232 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5233 return -1;
5234 }
5235
5236 preg = calloc(1, sizeof(regex_t));
5237 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5238 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5239 return -1;
5240 }
5241
5242 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5243 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005244 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
5245 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005246 if (curproxy == &defproxy) {
5247 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5248 return -1;
5249 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005250
5251 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005252 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005253 return -1;
5254 }
5255
5256 preg = calloc(1, sizeof(regex_t));
5257 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005258 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005259 return -1;
5260 }
5261
5262 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5263 }
5264 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005265 if (curproxy == &defproxy) {
5266 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5267 return -1;
5268 }
5269
willy tarreau9fe663a2005-12-17 13:02:59 +01005270 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005271 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005272 return 0;
5273 }
5274
5275 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005276 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005277 return -1;
5278 }
5279
5280 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005281 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005282 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01005283 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01005284
5285 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005286 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5287 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005288 return -1;
5289 }
5290
5291 preg = calloc(1, sizeof(regex_t));
5292 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005293 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005294 return -1;
5295 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005296
5297 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5298 }
5299 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
5300 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005301 if (curproxy == &defproxy) {
5302 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5303 return -1;
5304 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005305
5306 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005307 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005308 return -1;
5309 }
willy tarreaue39cd132005-12-17 13:00:18 +01005310
willy tarreau9fe663a2005-12-17 13:02:59 +01005311 preg = calloc(1, sizeof(regex_t));
5312 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005313 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005314 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005315 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005316
5317 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5318 }
5319 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01005320 regex_t *preg;
5321 if (curproxy == &defproxy) {
5322 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5323 return -1;
5324 }
willy tarreaue39cd132005-12-17 13:00:18 +01005325
willy tarreaua41a8b42005-12-17 14:02:24 +01005326 if (*(args[1]) == 0 || *(args[2]) == 0) {
5327 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5328 file, linenum, args[0]);
5329 return -1;
5330 }
willy tarreaue39cd132005-12-17 13:00:18 +01005331
willy tarreaua41a8b42005-12-17 14:02:24 +01005332 preg = calloc(1, sizeof(regex_t));
5333 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5334 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5335 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005336 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005337
5338 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5339 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005340 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
5341 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005342 if (curproxy == &defproxy) {
5343 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5344 return -1;
5345 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005346
5347 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005348 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005349 return -1;
5350 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005351
willy tarreau9fe663a2005-12-17 13:02:59 +01005352 preg = calloc(1, sizeof(regex_t));
5353 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005354 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005355 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005356 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005357
5358 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5359 }
5360 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005361 if (curproxy == &defproxy) {
5362 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5363 return -1;
5364 }
5365
willy tarreau9fe663a2005-12-17 13:02:59 +01005366 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005367 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005368 return 0;
5369 }
5370
5371 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005372 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005373 return -1;
5374 }
5375
5376 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
5377 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005378 else if (!strcmp(args[0], "errorloc")) { /* error location */
5379 int errnum;
5380 char *err;
5381
willy tarreaueedaa9f2005-12-17 14:08:03 +01005382 // if (curproxy == &defproxy) {
5383 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5384 // return -1;
5385 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005386
willy tarreau8337c6b2005-12-17 13:41:01 +01005387 if (*(args[2]) == 0) {
5388 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
5389 return -1;
5390 }
5391
5392 errnum = atol(args[1]);
5393 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
5394 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
5395
5396 if (errnum == 400) {
5397 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005398 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005399 free(curproxy->errmsg.msg400);
5400 }
5401 curproxy->errmsg.msg400 = err;
5402 curproxy->errmsg.len400 = strlen(err);
5403 }
5404 else if (errnum == 403) {
5405 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005406 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005407 free(curproxy->errmsg.msg403);
5408 }
5409 curproxy->errmsg.msg403 = err;
5410 curproxy->errmsg.len403 = strlen(err);
5411 }
5412 else if (errnum == 408) {
5413 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005414 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005415 free(curproxy->errmsg.msg408);
5416 }
5417 curproxy->errmsg.msg408 = err;
5418 curproxy->errmsg.len408 = strlen(err);
5419 }
5420 else if (errnum == 500) {
5421 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005422 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005423 free(curproxy->errmsg.msg500);
5424 }
5425 curproxy->errmsg.msg500 = err;
5426 curproxy->errmsg.len500 = strlen(err);
5427 }
5428 else if (errnum == 502) {
5429 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005430 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005431 free(curproxy->errmsg.msg502);
5432 }
5433 curproxy->errmsg.msg502 = err;
5434 curproxy->errmsg.len502 = strlen(err);
5435 }
5436 else if (errnum == 503) {
5437 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005438 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005439 free(curproxy->errmsg.msg503);
5440 }
5441 curproxy->errmsg.msg503 = err;
5442 curproxy->errmsg.len503 = strlen(err);
5443 }
5444 else if (errnum == 504) {
5445 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005446 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005447 free(curproxy->errmsg.msg504);
5448 }
5449 curproxy->errmsg.msg504 = err;
5450 curproxy->errmsg.len504 = strlen(err);
5451 }
5452 else {
5453 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
5454 free(err);
5455 }
5456 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005457 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005458 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01005459 return -1;
5460 }
5461 return 0;
5462}
willy tarreaue39cd132005-12-17 13:00:18 +01005463
willy tarreau5cbea6f2005-12-17 12:48:26 +01005464
willy tarreau9fe663a2005-12-17 13:02:59 +01005465/*
5466 * This function reads and parses the configuration file given in the argument.
5467 * returns 0 if OK, -1 if error.
5468 */
5469int readcfgfile(char *file) {
5470 char thisline[256];
5471 char *line;
5472 FILE *f;
5473 int linenum = 0;
5474 char *end;
5475 char *args[MAX_LINE_ARGS];
5476 int arg;
5477 int cfgerr = 0;
5478 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01005479
willy tarreau9fe663a2005-12-17 13:02:59 +01005480 struct proxy *curproxy = NULL;
5481 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005482
willy tarreau9fe663a2005-12-17 13:02:59 +01005483 if ((f=fopen(file,"r")) == NULL)
5484 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005485
willy tarreaueedaa9f2005-12-17 14:08:03 +01005486 init_default_instance();
5487
willy tarreau9fe663a2005-12-17 13:02:59 +01005488 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
5489 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005490
willy tarreau9fe663a2005-12-17 13:02:59 +01005491 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005492
willy tarreau9fe663a2005-12-17 13:02:59 +01005493 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01005494 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01005495 line++;
5496
5497 arg = 0;
5498 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01005499
willy tarreau9fe663a2005-12-17 13:02:59 +01005500 while (*line && arg < MAX_LINE_ARGS) {
5501 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
5502 * C equivalent value. Other combinations left unchanged (eg: \1).
5503 */
5504 if (*line == '\\') {
5505 int skip = 0;
5506 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
5507 *line = line[1];
5508 skip = 1;
5509 }
5510 else if (line[1] == 'r') {
5511 *line = '\r';
5512 skip = 1;
5513 }
5514 else if (line[1] == 'n') {
5515 *line = '\n';
5516 skip = 1;
5517 }
5518 else if (line[1] == 't') {
5519 *line = '\t';
5520 skip = 1;
5521 }
5522 else if (line[1] == 'x' && (line + 3 < end )) {
5523 unsigned char hex1, hex2;
5524 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
5525 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
5526 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
5527 *line = (hex1<<4) + hex2;
5528 skip = 3;
5529 }
5530 if (skip) {
5531 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
5532 end -= skip;
5533 }
5534 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005535 }
willy tarreaua1598082005-12-17 13:08:06 +01005536 else if (*line == '#' || *line == '\n' || *line == '\r') {
5537 /* end of string, end of loop */
5538 *line = 0;
5539 break;
5540 }
willy tarreauc29948c2005-12-17 13:10:27 +01005541 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005542 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01005543 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01005544 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01005545 line++;
5546 args[++arg] = line;
5547 }
5548 else {
5549 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005550 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005551 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005552
willy tarreau9fe663a2005-12-17 13:02:59 +01005553 /* empty line */
5554 if (!**args)
5555 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01005556
willy tarreau9fe663a2005-12-17 13:02:59 +01005557 /* zero out remaining args */
5558 while (++arg < MAX_LINE_ARGS) {
5559 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005560 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005561
willy tarreaua41a8b42005-12-17 14:02:24 +01005562 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01005563 confsect = CFG_LISTEN;
5564 else if (!strcmp(args[0], "global")) /* global config */
5565 confsect = CFG_GLOBAL;
5566 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005567
willy tarreau9fe663a2005-12-17 13:02:59 +01005568 switch (confsect) {
5569 case CFG_LISTEN:
5570 if (cfg_parse_listen(file, linenum, args) < 0)
5571 return -1;
5572 break;
5573 case CFG_GLOBAL:
5574 if (cfg_parse_global(file, linenum, args) < 0)
5575 return -1;
5576 break;
5577 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01005578 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005579 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005580 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005581
5582
willy tarreau0f7af912005-12-17 12:21:26 +01005583 }
5584 fclose(f);
5585
5586 /*
5587 * Now, check for the integrity of all that we have collected.
5588 */
5589
5590 if ((curproxy = proxy) == NULL) {
5591 Alert("parsing %s : no <listen> line. Nothing to do !\n",
5592 file);
5593 return -1;
5594 }
5595
5596 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01005597 if (curproxy->state == PR_STDISABLED) {
5598 curproxy = curproxy->next;
5599 continue;
5600 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005601 if ((curproxy->mode != PR_MODE_HEALTH) &&
5602 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01005603 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005604 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
5605 file, curproxy->id);
5606 cfgerr++;
5607 }
5608 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
5609 if (curproxy->options & PR_O_TRANSP) {
5610 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
5611 file, curproxy->id);
5612 cfgerr++;
5613 }
5614 else if (curproxy->srv == NULL) {
5615 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
5616 file, curproxy->id);
5617 cfgerr++;
5618 }
willy tarreaua1598082005-12-17 13:08:06 +01005619 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005620 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
5621 file, curproxy->id);
5622 }
5623 }
5624 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01005625 if (curproxy->cookie_name != NULL) {
5626 Warning("parsing %s : cookie will be ignored for listener %s.\n",
5627 file, curproxy->id);
5628 }
5629 if ((newsrv = curproxy->srv) != NULL) {
5630 Warning("parsing %s : servers will be ignored for listener %s.\n",
5631 file, curproxy->id);
5632 }
willy tarreaue39cd132005-12-17 13:00:18 +01005633 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005634 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
5635 file, curproxy->id);
5636 }
willy tarreaue39cd132005-12-17 13:00:18 +01005637 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005638 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
5639 file, curproxy->id);
5640 }
5641 }
5642 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
5643 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
5644 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
5645 file, curproxy->id);
5646 cfgerr++;
5647 }
5648 else {
5649 while (newsrv != NULL) {
5650 /* nothing to check for now */
5651 newsrv = newsrv->next;
5652 }
5653 }
5654 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005655 if (curproxy->errmsg.msg400 == NULL) {
5656 curproxy->errmsg.msg400 = (char *)HTTP_400;
5657 curproxy->errmsg.len400 = strlen(HTTP_400);
5658 }
5659 if (curproxy->errmsg.msg403 == NULL) {
5660 curproxy->errmsg.msg403 = (char *)HTTP_403;
5661 curproxy->errmsg.len403 = strlen(HTTP_403);
5662 }
5663 if (curproxy->errmsg.msg408 == NULL) {
5664 curproxy->errmsg.msg408 = (char *)HTTP_408;
5665 curproxy->errmsg.len408 = strlen(HTTP_408);
5666 }
5667 if (curproxy->errmsg.msg500 == NULL) {
5668 curproxy->errmsg.msg500 = (char *)HTTP_500;
5669 curproxy->errmsg.len500 = strlen(HTTP_500);
5670 }
5671 if (curproxy->errmsg.msg502 == NULL) {
5672 curproxy->errmsg.msg502 = (char *)HTTP_502;
5673 curproxy->errmsg.len502 = strlen(HTTP_502);
5674 }
5675 if (curproxy->errmsg.msg503 == NULL) {
5676 curproxy->errmsg.msg503 = (char *)HTTP_503;
5677 curproxy->errmsg.len503 = strlen(HTTP_503);
5678 }
5679 if (curproxy->errmsg.msg504 == NULL) {
5680 curproxy->errmsg.msg504 = (char *)HTTP_504;
5681 curproxy->errmsg.len504 = strlen(HTTP_504);
5682 }
willy tarreau0f7af912005-12-17 12:21:26 +01005683 curproxy = curproxy->next;
5684 }
5685 if (cfgerr > 0) {
5686 Alert("Errors found in configuration file, aborting.\n");
5687 return -1;
5688 }
5689 else
5690 return 0;
5691}
5692
5693
5694/*
5695 * This function initializes all the necessary variables. It only returns
5696 * if everything is OK. If something fails, it exits.
5697 */
5698void init(int argc, char **argv) {
5699 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01005700 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01005701 char *old_argv = *argv;
5702 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01005703 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01005704 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01005705
5706 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01005707 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005708 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
5709 sizeof(int)*8);
5710 exit(1);
5711 }
5712
5713 pid = getpid();
5714 progname = *argv;
5715 while ((tmp = strchr(progname, '/')) != NULL)
5716 progname = tmp + 1;
5717
5718 argc--; argv++;
5719 while (argc > 0) {
5720 char *flag;
5721
5722 if (**argv == '-') {
5723 flag = *argv+1;
5724
5725 /* 1 arg */
5726 if (*flag == 'v') {
5727 display_version();
5728 exit(0);
5729 }
5730 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01005731 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01005732 else if (*flag == 'c')
5733 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01005734 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01005735 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005736 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01005737 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01005738#if STATTIME > 0
5739 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01005740 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01005741 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01005742 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01005743#endif
5744 else { /* >=2 args */
5745 argv++; argc--;
5746 if (argc == 0)
5747 usage(old_argv);
5748
5749 switch (*flag) {
5750 case 'n' : cfg_maxconn = atol(*argv); break;
5751 case 'N' : cfg_maxpconn = atol(*argv); break;
5752 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01005753 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01005754 default: usage(old_argv);
5755 }
5756 }
5757 }
5758 else
5759 usage(old_argv);
5760 argv++; argc--;
5761 }
5762
willy tarreaudd07e972005-12-18 00:48:48 +01005763 global.mode = (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG));
5764
willy tarreau0f7af912005-12-17 12:21:26 +01005765 if (!cfg_cfgfile)
5766 usage(old_argv);
5767
5768 gethostname(hostname, MAX_HOSTNAME_LEN);
5769
5770 if (readcfgfile(cfg_cfgfile) < 0) {
5771 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
5772 exit(1);
5773 }
5774
willy tarreaudd07e972005-12-18 00:48:48 +01005775 if (arg_mode & MODE_CHECK) {
5776 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
5777 exit(0);
5778 }
5779
willy tarreau9fe663a2005-12-17 13:02:59 +01005780 if (cfg_maxconn > 0)
5781 global.maxconn = cfg_maxconn;
5782
willy tarreaufe2c5c12005-12-17 14:14:34 +01005783 if (cfg_pidfile) {
5784 if (global.pidfile)
5785 free(global.pidfile);
5786 global.pidfile = strdup(cfg_pidfile);
5787 }
5788
willy tarreau9fe663a2005-12-17 13:02:59 +01005789 if (global.maxconn == 0)
5790 global.maxconn = DEFAULT_MAXCONN;
5791
5792 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
5793
5794 if (arg_mode & MODE_DEBUG) {
5795 /* command line debug mode inhibits configuration mode */
5796 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5797 }
willy tarreau750a4722005-12-17 13:21:24 +01005798 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01005799
5800 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
5801 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
5802 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5803 }
5804
5805 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
5806 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
5807 global.nbproc = 1;
5808 }
5809
5810 if (global.nbproc < 1)
5811 global.nbproc = 1;
5812
willy tarreau0f7af912005-12-17 12:21:26 +01005813 ReadEvent = (fd_set *)calloc(1,
5814 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005815 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005816 WriteEvent = (fd_set *)calloc(1,
5817 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005818 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005819 StaticReadEvent = (fd_set *)calloc(1,
5820 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005821 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005822 StaticWriteEvent = (fd_set *)calloc(1,
5823 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005824 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005825
5826 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01005827 sizeof(struct fdtab) * (global.maxsock));
5828 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01005829 fdtab[i].state = FD_STCLOSE;
5830 }
5831}
5832
5833/*
5834 * this function starts all the proxies. It returns 0 if OK, -1 if not.
5835 */
5836int start_proxies() {
5837 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01005838 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01005839 int fd;
5840
5841 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01005842 if (curproxy->state == PR_STDISABLED)
5843 continue;
5844
willy tarreaua41a8b42005-12-17 14:02:24 +01005845 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
5846 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01005847 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005848 Alert("cannot create listening socket for proxy %s. Aborting.\n",
5849 curproxy->id);
5850 return -1;
5851 }
willy tarreau0f7af912005-12-17 12:21:26 +01005852
willy tarreaua41a8b42005-12-17 14:02:24 +01005853 if (fd >= global.maxsock) {
5854 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
5855 curproxy->id);
5856 close(fd);
5857 return -1;
5858 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005859
willy tarreaua41a8b42005-12-17 14:02:24 +01005860 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
5861 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
5862 (char *) &one, sizeof(one)) == -1)) {
5863 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
5864 curproxy->id);
5865 close(fd);
5866 return -1;
5867 }
willy tarreau0f7af912005-12-17 12:21:26 +01005868
willy tarreaua41a8b42005-12-17 14:02:24 +01005869 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
5870 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
5871 curproxy->id);
5872 }
willy tarreau0f7af912005-12-17 12:21:26 +01005873
willy tarreaua41a8b42005-12-17 14:02:24 +01005874 if (bind(fd,
5875 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01005876 listener->addr.ss_family == AF_INET6 ?
5877 sizeof(struct sockaddr_in6) :
5878 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005879 Alert("cannot bind socket for proxy %s. Aborting.\n",
5880 curproxy->id);
5881 close(fd);
5882 return -1;
5883 }
willy tarreau0f7af912005-12-17 12:21:26 +01005884
willy tarreaua41a8b42005-12-17 14:02:24 +01005885 if (listen(fd, curproxy->maxconn) == -1) {
5886 Alert("cannot listen to socket for proxy %s. Aborting.\n",
5887 curproxy->id);
5888 close(fd);
5889 return -1;
5890 }
willy tarreau0f7af912005-12-17 12:21:26 +01005891
willy tarreaua41a8b42005-12-17 14:02:24 +01005892 /* the function for the accept() event */
5893 fdtab[fd].read = &event_accept;
5894 fdtab[fd].write = NULL; /* never called */
5895 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
5896 curproxy->state = PR_STRUN;
5897 fdtab[fd].state = FD_STLISTEN;
5898 FD_SET(fd, StaticReadEvent);
5899 fd_insert(fd);
5900 listeners++;
5901 }
willy tarreaua1598082005-12-17 13:08:06 +01005902 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005903 }
5904 return 0;
5905}
5906
5907
5908int main(int argc, char **argv) {
willy tarreaufe2c5c12005-12-17 14:14:34 +01005909 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01005910 init(argc, argv);
5911
willy tarreau9fe663a2005-12-17 13:02:59 +01005912 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01005913 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005914 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01005915 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01005916 }
5917
5918 signal(SIGQUIT, dump);
5919 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01005920 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005921
5922 /* on very high loads, a sigpipe sometimes happen just between the
5923 * getsockopt() which tells "it's OK to write", and the following write :-(
5924 */
willy tarreau3242e862005-12-17 12:27:53 +01005925#ifndef MSG_NOSIGNAL
5926 signal(SIGPIPE, SIG_IGN);
5927#endif
willy tarreau0f7af912005-12-17 12:21:26 +01005928
5929 if (start_proxies() < 0)
5930 exit(1);
5931
willy tarreaufe2c5c12005-12-17 14:14:34 +01005932 /* open log & pid files before the chroot */
5933 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
5934 int pidfd;
5935 unlink(global.pidfile);
5936 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
5937 if (pidfd < 0) {
5938 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
5939 exit(1);
5940 }
5941 pidfile = fdopen(pidfd, "w");
5942 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005943
5944 /* chroot if needed */
5945 if (global.chroot != NULL) {
5946 if (chroot(global.chroot) == -1) {
5947 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
5948 exit(1);
5949 }
5950 chdir("/");
5951 }
5952
5953 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01005954 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005955 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
5956 exit(1);
5957 }
5958
willy tarreau036e1ce2005-12-17 13:46:33 +01005959 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005960 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
5961 exit(1);
5962 }
5963
5964 if (global.mode & MODE_DAEMON) {
5965 int ret = 0;
5966 int proc;
5967
5968 /* the father launches the required number of processes */
5969 for (proc = 0; proc < global.nbproc; proc++) {
5970 ret = fork();
5971 if (ret < 0) {
5972 Alert("[%s.main()] Cannot fork.\n", argv[0]);
5973 exit(1); /* there has been an error */
5974 }
5975 else if (ret == 0) /* child breaks here */
5976 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01005977 if (pidfile != NULL) {
5978 fprintf(pidfile, "%d\n", ret);
5979 fflush(pidfile);
5980 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005981 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005982 /* close the pidfile both in children and father */
5983 if (pidfile != NULL)
5984 fclose(pidfile);
5985 free(global.pidfile);
5986
willy tarreau9fe663a2005-12-17 13:02:59 +01005987 if (proc == global.nbproc)
5988 exit(0); /* parent must leave */
5989
willy tarreau750a4722005-12-17 13:21:24 +01005990 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
5991 * that we can detach from the TTY. We MUST NOT do it in other cases since
5992 * it would have already be done, and 0-2 would have been affected to listening
5993 * sockets
5994 */
5995 if (!(global.mode & MODE_QUIET)) {
5996 /* detach from the tty */
5997 fclose(stdin); fclose(stdout); fclose(stderr);
5998 close(0); close(1); close(2); /* close all fd's */
5999 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
6000 }
willy tarreaua1598082005-12-17 13:08:06 +01006001 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01006002 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01006003 }
6004
willy tarreau0f7af912005-12-17 12:21:26 +01006005 select_loop();
6006
6007 exit(0);
6008}