blob: ebf28322bf3d400107165ad847e8dd684f9975d4 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau036e1ce2005-12-17 13:46:33 +01003 * 2000-2003 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
11 * RFC2965 for informations about cookies usage.
12 *
13 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010014 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
15 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010016 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010017 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
18 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010019 * - a proxy with an invalid config will prevent the startup even if disabled.
20 *
willy tarreau036e1ce2005-12-17 13:46:33 +010021 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010022 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010023 * TODO:
24 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010025 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010026 * - fix client/server state transition when server is in connect or headers state
27 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
28 * still handle HTTP headers.
willy tarreau0f7af912005-12-17 12:21:26 +010029 *
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <string.h>
36#include <ctype.h>
37#include <sys/time.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <netinet/tcp.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <netdb.h>
44#include <fcntl.h>
45#include <errno.h>
46#include <signal.h>
47#include <stdarg.h>
48#include <sys/resource.h>
49#include <time.h>
50#include <regex.h>
51#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010052#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010053#include <linux/netfilter_ipv4.h>
54#endif
willy tarreau0f7af912005-12-17 12:21:26 +010055
willy tarreau197e8ec2005-12-17 14:10:59 +010056#define HAPROXY_VERSION "1.1.24"
57#define HAPROXY_DATE "2003/09/21"
willy tarreau0f7af912005-12-17 12:21:26 +010058
59/* this is for libc5 for example */
60#ifndef TCP_NODELAY
61#define TCP_NODELAY 1
62#endif
63
64#ifndef SHUT_RD
65#define SHUT_RD 0
66#endif
67
68#ifndef SHUT_WR
69#define SHUT_WR 1
70#endif
71
willy tarreau535ae7a2005-12-17 12:58:00 +010072#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +010073
74// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +010075#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +010076#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +010077#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +010078
willy tarreau5cbea6f2005-12-17 12:48:26 +010079// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +010080#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +010081
willy tarreaue39cd132005-12-17 13:00:18 +010082// max # of added headers per request
83#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +010084
85// max # of matches per regexp
86#define MAX_MATCH 10
87
willy tarreau5cbea6f2005-12-17 12:48:26 +010088/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +010089#define COOKIENAME_LEN 16
90#define SERVERID_LEN 16
91#define CONN_RETRIES 3
92
willy tarreau5cbea6f2005-12-17 12:48:26 +010093#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +010094#define DEF_CHKINTR 2000
95#define DEF_FALLTIME 3
96#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +010097#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +010098
willy tarreau9fe663a2005-12-17 13:02:59 +010099/* default connections limit */
100#define DEFAULT_MAXCONN 2000
101
willy tarreau0f7af912005-12-17 12:21:26 +0100102/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
103#define INTBITS 5
104
105/* show stats this every millisecond, 0 to disable */
106#ifndef STATTIME
107#define STATTIME 2000
108#endif
109
willy tarreau5cbea6f2005-12-17 12:48:26 +0100110/* this reduces the number of calls to select() by choosing appropriate
111 * sheduler precision in milliseconds. It should be near the minimum
112 * time that is needed by select() to collect all events. All timeouts
113 * are rounded up by adding this value prior to pass it to select().
114 */
115#define SCHEDULER_RESOLUTION 9
116
willy tarreau0f7af912005-12-17 12:21:26 +0100117#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
118#define SETNOW(a) (*a=now)
119
willy tarreau9da061b2005-12-17 12:29:56 +0100120/****** string-specific macros and functions ******/
121/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
122#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
123
124/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
125#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
126
willy tarreau9da061b2005-12-17 12:29:56 +0100127/*
128 * copies at most <size-1> chars from <src> to <dst>. Last char is always
129 * set to 0, unless <size> is 0. The number of chars copied is returned
130 * (excluding the terminating zero).
131 * This code has been optimized for size and speed : on x86, it's 45 bytes
132 * long, uses only registers, and consumes only 4 cycles per char.
133 */
willy tarreau750a4722005-12-17 13:21:24 +0100134int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100135 char *orig = dst;
136 if (size) {
137 while (--size && (*dst = *src)) {
138 src++; dst++;
139 }
140 *dst = 0;
141 }
142 return dst - orig;
143}
willy tarreau9da061b2005-12-17 12:29:56 +0100144
willy tarreau0f7af912005-12-17 12:21:26 +0100145#define MEM_OPTIM
146#ifdef MEM_OPTIM
147/*
148 * Returns a pointer to type <type> taken from the
149 * pool <pool_type> or dynamically allocated. In the
150 * first case, <pool_type> is updated to point to the
151 * next element in the list.
152 */
153#define pool_alloc(type) ({ \
154 void *p; \
155 if ((p = pool_##type) == NULL) \
156 p = malloc(sizeof_##type); \
157 else { \
158 pool_##type = *(void **)pool_##type; \
159 } \
160 p; \
161})
162
163/*
164 * Puts a memory area back to the corresponding pool.
165 * Items are chained directly through a pointer that
166 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100167 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100168 * that each memory area is at least as big as one
169 * pointer.
170 */
171#define pool_free(type, ptr) ({ \
172 *(void **)ptr = (void *)pool_##type; \
173 pool_##type = (void *)ptr; \
174})
175
176#else
177#define pool_alloc(type) (calloc(1,sizeof_##type));
178#define pool_free(type, ptr) (free(ptr));
179#endif /* MEM_OPTIM */
180
willy tarreau5cbea6f2005-12-17 12:48:26 +0100181#define sizeof_task sizeof(struct task)
182#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100183#define sizeof_buffer sizeof(struct buffer)
184#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100185#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100186#define sizeof_capture CAPTURE_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100187
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define FD_STCLOSE 0
190#define FD_STLISTEN 1
191#define FD_STCONN 2
192#define FD_STREADY 3
193#define FD_STERROR 4
194
willy tarreau5cbea6f2005-12-17 12:48:26 +0100195/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100196#define TASK_IDLE 0
197#define TASK_RUNNING 1
198
willy tarreau5cbea6f2005-12-17 12:48:26 +0100199/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100200#define PR_STNEW 0
201#define PR_STIDLE 1
202#define PR_STRUN 2
203#define PR_STDISABLED 3
204
willy tarreau5cbea6f2005-12-17 12:48:26 +0100205/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100206#define PR_MODE_TCP 0
207#define PR_MODE_HTTP 1
208#define PR_MODE_HEALTH 2
209
willy tarreau5cbea6f2005-12-17 12:48:26 +0100210/* bits for proxy->options */
211#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
212#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
213#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
214#define PR_O_COOK_IND 8 /* keep only indirect cookies */
215#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
216#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
217#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
218#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100219#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
220#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100221#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
222#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100223#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100224#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100225#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
willy tarreau8337c6b2005-12-17 13:41:01 +0100226#define PR_O_PERSIST 8192 /* server persistence stays effective even when server is down */
willy tarreau9fe663a2005-12-17 13:02:59 +0100227
willy tarreau5cbea6f2005-12-17 12:48:26 +0100228
willy tarreaue39cd132005-12-17 13:00:18 +0100229/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100230#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
231#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
232#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
233#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
234#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
235#define SN_POST 0x00000020 /* the request was an HTTP POST */
236
237#define SN_CK_NONE 0x00000000 /* this session had no cookie */
238#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
239#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
240#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
241#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
242#define SN_CK_SHIFT 6 /* bit shift */
243
244#define SN_ERR_CLITO 0x00000100 /* client time-out */
245#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
246#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
247#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
248#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
249#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
250#define SN_ERR_SHIFT 8 /* bit shift */
251
252#define SN_FINST_R 0x00001000 /* session ended during client request */
253#define SN_FINST_C 0x00002000 /* session ended during server connect */
254#define SN_FINST_H 0x00003000 /* session ended during server headers */
255#define SN_FINST_D 0x00004000 /* session ended during data phase */
256#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
257#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
258#define SN_FINST_SHIFT 12 /* bit shift */
259
260#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
261#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
262#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
263#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
264#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
265#define SN_SCK_SHIFT 16 /* bit shift */
266
willy tarreau5cbea6f2005-12-17 12:48:26 +0100267
268/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100269#define CL_STHEADERS 0
270#define CL_STDATA 1
271#define CL_STSHUTR 2
272#define CL_STSHUTW 3
273#define CL_STCLOSE 4
274
willy tarreau5cbea6f2005-12-17 12:48:26 +0100275/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100276#define SV_STIDLE 0
277#define SV_STCONN 1
278#define SV_STHEADERS 2
279#define SV_STDATA 3
280#define SV_STSHUTR 4
281#define SV_STSHUTW 5
282#define SV_STCLOSE 6
283
284/* result of an I/O event */
285#define RES_SILENT 0 /* didn't happen */
286#define RES_DATA 1 /* data were sent or received */
287#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
288#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
289
willy tarreau9fe663a2005-12-17 13:02:59 +0100290/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100291#define MODE_DEBUG 1
292#define MODE_STATS 2
293#define MODE_LOG 4
294#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295#define MODE_QUIET 16
296
297/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100298#define SRV_RUNNING 1 /* the server is UP */
299#define SRV_BACKUP 2 /* this server is a backup server */
300#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0f7af912005-12-17 12:21:26 +0100301
willy tarreaue39cd132005-12-17 13:00:18 +0100302/* what to do when a header matches a regex */
303#define ACT_ALLOW 0 /* allow the request */
304#define ACT_REPLACE 1 /* replace the matching header */
305#define ACT_REMOVE 2 /* remove the matching header */
306#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100307#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100308
willy tarreau9fe663a2005-12-17 13:02:59 +0100309/* configuration sections */
310#define CFG_NONE 0
311#define CFG_GLOBAL 1
312#define CFG_LISTEN 2
313
willy tarreaua1598082005-12-17 13:08:06 +0100314/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100315#define LW_DATE 1 /* date */
316#define LW_CLIP 2 /* CLient IP */
317#define LW_SVIP 4 /* SerVer IP */
318#define LW_SVID 8 /* server ID */
319#define LW_REQ 16 /* http REQuest */
320#define LW_RESP 32 /* http RESPonse */
321#define LW_PXIP 64 /* proxy IP */
322#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100323#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100324
willy tarreau0f7af912005-12-17 12:21:26 +0100325/*********************************************************************/
326
327#define LIST_HEAD(a) ((void *)(&(a)))
328
329/*********************************************************************/
330
331struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100332 struct hdr_exp *next;
333 regex_t *preg; /* expression to look for */
334 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
335 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100336};
337
338struct buffer {
339 unsigned int l; /* data length */
340 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100341 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100342 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100343 char data[BUFSIZE];
344};
345
346struct server {
347 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100348 int state; /* server state (SRV_*) */
349 int cklen; /* the len of the cookie, to speed up checks */
350 char *cookie; /* the id set in the cookie */
351 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100352 struct sockaddr_in addr; /* the address to connect to */
willy tarreaua41a8b42005-12-17 14:02:24 +0100353 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100355 int rise, fall; /* time in iterations */
356 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100357 int result; /* 0 = connect OK, -1 = connect KO */
358 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100359 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100360};
361
willy tarreau5cbea6f2005-12-17 12:48:26 +0100362/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100363struct task {
364 struct task *next, *prev; /* chaining ... */
365 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100366 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100367 int state; /* task state : IDLE or RUNNING */
368 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100369 int (*process)(struct task *t); /* the function which processes the task */
370 void *context; /* the task's context */
371};
372
373/* WARNING: if new fields are added, they must be initialized in event_accept() */
374struct session {
375 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100376 /* application specific below */
377 struct timeval crexpire; /* expiration date for a client read */
378 struct timeval cwexpire; /* expiration date for a client write */
379 struct timeval srexpire; /* expiration date for a server read */
380 struct timeval swexpire; /* expiration date for a server write */
381 struct timeval cnexpire; /* expiration date for a connect */
382 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
383 struct proxy *proxy; /* the proxy this socket belongs to */
384 int cli_fd; /* the client side fd */
385 int srv_fd; /* the server side fd */
386 int cli_state; /* state of the client side */
387 int srv_state; /* state of the server side */
388 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100389 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100390 struct buffer *req; /* request buffer */
391 struct buffer *rep; /* response buffer */
392 struct sockaddr_in cli_addr; /* the client address */
393 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100394 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100395 struct {
396 int logwait; /* log fields waiting to be collected : LW_* */
397 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
398 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
399 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
400 long t_data; /* delay before the first data byte from the server ... */
401 unsigned long t_close; /* total session duration */
402 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100403 char *cli_cookie; /* cookie presented by the client, in capture mode */
404 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100405 int status; /* HTTP status from the server, negative if from proxy */
406 long long bytes; /* number of bytes transferred from the server */
407 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100408 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100409};
410
willy tarreaua41a8b42005-12-17 14:02:24 +0100411struct listener {
412 int fd; /* the listen socket */
413 struct sockaddr_in addr; /* the address we listen to */
414 struct listener *next; /* next address or NULL */
415};
416
417
willy tarreau0f7af912005-12-17 12:21:26 +0100418struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100419 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100420 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100421 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100422 struct server *srv, *cursrv; /* known servers, current server */
423 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100424 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100425 int cookie_len; /* strlen(cookie_len), computed only once */
426 char *capture_name; /* beginning of the name of the cookie to capture */
427 int capture_namelen; /* length of the cookie name to match */
428 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100429 int clitimeout; /* client I/O timeout (in milliseconds) */
430 int srvtimeout; /* server I/O timeout (in milliseconds) */
431 int contimeout; /* connect timeout (in milliseconds) */
432 char *id; /* proxy id */
433 int nbconn; /* # of active sessions */
434 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100435 int conn_retries; /* maximum number of connect retries */
436 int options; /* PR_O_REDISP, PR_O_TRANSP */
437 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100438 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100439 struct proxy *next;
440 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
441 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100442 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100443 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100444 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100445 int nb_reqadd, nb_rspadd;
446 struct hdr_exp *req_exp; /* regular expressions for request headers */
447 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
448 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100449 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100450 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
451 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100452 struct {
453 char *msg400; /* message for error 400 */
454 int len400; /* message length for error 400 */
455 char *msg403; /* message for error 403 */
456 int len403; /* message length for error 403 */
457 char *msg408; /* message for error 408 */
458 int len408; /* message length for error 408 */
459 char *msg500; /* message for error 500 */
460 int len500; /* message length for error 500 */
461 char *msg502; /* message for error 502 */
462 int len502; /* message length for error 502 */
463 char *msg503; /* message for error 503 */
464 int len503; /* message length for error 503 */
465 char *msg504; /* message for error 504 */
466 int len504; /* message length for error 504 */
467 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100468};
469
470/* info about one given fd */
471struct fdtab {
472 int (*read)(int fd); /* read function */
473 int (*write)(int fd); /* write function */
474 struct task *owner; /* the session (or proxy) associated with this fd */
475 int state; /* the state of this fd */
476};
477
478/*********************************************************************/
479
willy tarreau0f7af912005-12-17 12:21:26 +0100480int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100481char *cfg_cfgfile = NULL; /* configuration file */
482char *progname = NULL; /* program name */
483int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100484
485/* global options */
486static struct {
487 int uid;
488 int gid;
489 int nbproc;
490 int maxconn;
491 int maxsock; /* max # of sockets */
492 int mode;
493 char *chroot;
494 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100495 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100496 struct sockaddr_in logsrv1, logsrv2;
497} global = {
498 logfac1 : -1,
499 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100500 loglev1 : 7, /* max syslog level : debug */
501 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100502 /* others NULL OK */
503};
504
willy tarreau0f7af912005-12-17 12:21:26 +0100505/*********************************************************************/
506
507fd_set *ReadEvent,
508 *WriteEvent,
509 *StaticReadEvent,
510 *StaticWriteEvent;
511
512void **pool_session = NULL,
513 **pool_buffer = NULL,
514 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100515 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100516 **pool_task = NULL,
517 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100518
519struct proxy *proxy = NULL; /* list of all existing proxies */
520struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100521struct task *rq = NULL; /* global run queue */
522struct task wait_queue = { /* global wait queue */
523 prev:LIST_HEAD(wait_queue),
524 next:LIST_HEAD(wait_queue)
525};
willy tarreau0f7af912005-12-17 12:21:26 +0100526
willy tarreau0f7af912005-12-17 12:21:26 +0100527static int totalconn = 0; /* total # of terminated sessions */
528static int actconn = 0; /* # of active sessions */
529static int maxfd = 0; /* # of the highest fd + 1 */
530static int listeners = 0; /* # of listeners */
531static int stopping = 0; /* non zero means stopping in progress */
532static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100533static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100534
535static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100536/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100537static char trash[BUFSIZE];
538
539/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100540 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100541 */
542
543#define MAX_SYSLOG_LEN 1024
544#define NB_LOG_FACILITIES 24
545const char *log_facilities[NB_LOG_FACILITIES] = {
546 "kern", "user", "mail", "daemon",
547 "auth", "syslog", "lpr", "news",
548 "uucp", "cron", "auth2", "ftp",
549 "ntp", "audit", "alert", "cron2",
550 "local0", "local1", "local2", "local3",
551 "local4", "local5", "local6", "local7"
552};
553
554
555#define NB_LOG_LEVELS 8
556const char *log_levels[NB_LOG_LEVELS] = {
557 "emerg", "alert", "crit", "err",
558 "warning", "notice", "info", "debug"
559};
560
561#define SYSLOG_PORT 514
562
563const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
564 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100565
566const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
567const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
568const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
569const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
570 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
571 unknown, Set-cookie Rewritten */
572
willy tarreau0f7af912005-12-17 12:21:26 +0100573#define MAX_HOSTNAME_LEN 32
574static char hostname[MAX_HOSTNAME_LEN] = "";
575
willy tarreau8337c6b2005-12-17 13:41:01 +0100576const char *HTTP_302 =
577 "HTTP/1.0 302 Found\r\n"
578 "Cache-Control: no-cache\r\n"
579 "Connection: close\r\n"
580 "Location: "; /* not terminated since it will be concatenated with the URL */
581
willy tarreaua1598082005-12-17 13:08:06 +0100582const char *HTTP_400 =
583 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100584 "Cache-Control: no-cache\r\n"
585 "Connection: close\r\n"
586 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100587 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100588
willy tarreaua1598082005-12-17 13:08:06 +0100589const char *HTTP_403 =
590 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100591 "Cache-Control: no-cache\r\n"
592 "Connection: close\r\n"
593 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100594 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
595
willy tarreau8337c6b2005-12-17 13:41:01 +0100596const char *HTTP_408 =
597 "HTTP/1.0 408 Request Time-out\r\n"
598 "Cache-Control: no-cache\r\n"
599 "Connection: close\r\n"
600 "\r\n"
601 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
602
willy tarreau750a4722005-12-17 13:21:24 +0100603const char *HTTP_500 =
604 "HTTP/1.0 500 Server Error\r\n"
605 "Cache-Control: no-cache\r\n"
606 "Connection: close\r\n"
607 "\r\n"
608 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100609
610const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100611 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100612 "Cache-Control: no-cache\r\n"
613 "Connection: close\r\n"
614 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100615 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
616
617const char *HTTP_503 =
618 "HTTP/1.0 503 Service Unavailable\r\n"
619 "Cache-Control: no-cache\r\n"
620 "Connection: close\r\n"
621 "\r\n"
622 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
623
624const char *HTTP_504 =
625 "HTTP/1.0 504 Gateway Time-out\r\n"
626 "Cache-Control: no-cache\r\n"
627 "Connection: close\r\n"
628 "\r\n"
629 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100630
willy tarreau0f7af912005-12-17 12:21:26 +0100631/*********************************************************************/
632/* statistics ******************************************************/
633/*********************************************************************/
634
willy tarreau750a4722005-12-17 13:21:24 +0100635#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100636static int stats_tsk_lsrch, stats_tsk_rsrch,
637 stats_tsk_good, stats_tsk_right, stats_tsk_left,
638 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100639#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100640
641
642/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100643/* debugging *******************************************************/
644/*********************************************************************/
645#ifdef DEBUG_FULL
646static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
647static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
648#endif
649
650/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100651/* function prototypes *********************************************/
652/*********************************************************************/
653
654int event_accept(int fd);
655int event_cli_read(int fd);
656int event_cli_write(int fd);
657int event_srv_read(int fd);
658int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100659int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100660
661/*********************************************************************/
662/* general purpose functions ***************************************/
663/*********************************************************************/
664
665void display_version() {
666 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100667 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100668}
669
670/*
671 * This function prints the command line usage and exits
672 */
673void usage(char *name) {
674 display_version();
675 fprintf(stderr,
676 "Usage : %s -f <cfgfile> [ -vd"
677#if STATTIME > 0
678 "sl"
679#endif
680 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
681 " -v displays version\n"
682 " -d enters debug mode\n"
683#if STATTIME > 0
684 " -s enables statistics output\n"
685 " -l enables long statistics format\n"
686#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100687 " -D goes daemon ; implies -q\n"
688 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100689 " -n sets the maximum total # of connections (%d)\n"
690 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100691 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100692 exit(1);
693}
694
695
696/*
697 * Displays the message on stderr with the date and pid.
698 */
699void Alert(char *fmt, ...) {
700 va_list argp;
701 struct timeval tv;
702 struct tm *tm;
703
willy tarreau9fe663a2005-12-17 13:02:59 +0100704 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100705 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100706
willy tarreau5cbea6f2005-12-17 12:48:26 +0100707 gettimeofday(&tv, NULL);
708 tm=localtime(&tv.tv_sec);
709 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100710 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100711 vfprintf(stderr, fmt, argp);
712 fflush(stderr);
713 va_end(argp);
714 }
willy tarreau0f7af912005-12-17 12:21:26 +0100715}
716
717
718/*
719 * Displays the message on stderr with the date and pid.
720 */
721void Warning(char *fmt, ...) {
722 va_list argp;
723 struct timeval tv;
724 struct tm *tm;
725
willy tarreau9fe663a2005-12-17 13:02:59 +0100726 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100727 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100728
willy tarreau5cbea6f2005-12-17 12:48:26 +0100729 gettimeofday(&tv, NULL);
730 tm=localtime(&tv.tv_sec);
731 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100732 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100733 vfprintf(stderr, fmt, argp);
734 fflush(stderr);
735 va_end(argp);
736 }
737}
738
739/*
740 * Displays the message on <out> only if quiet mode is not set.
741 */
742void qfprintf(FILE *out, char *fmt, ...) {
743 va_list argp;
744
willy tarreau9fe663a2005-12-17 13:02:59 +0100745 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100746 va_start(argp, fmt);
747 vfprintf(out, fmt, argp);
748 fflush(out);
749 va_end(argp);
750 }
willy tarreau0f7af912005-12-17 12:21:26 +0100751}
752
753
754/*
755 * converts <str> to a struct sockaddr_in* which is locally allocated.
756 * The format is "addr:port", where "addr" can be empty or "*" to indicate
757 * INADDR_ANY.
758 */
759struct sockaddr_in *str2sa(char *str) {
760 static struct sockaddr_in sa;
761 char *c;
762 int port;
763
willy tarreaua1598082005-12-17 13:08:06 +0100764 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100765 str=strdup(str);
766
767 if ((c=strrchr(str,':')) != NULL) {
768 *c++=0;
769 port=atol(c);
770 }
771 else
772 port=0;
773
774 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
775 sa.sin_addr.s_addr = INADDR_ANY;
776 }
777 else if (
778#ifndef SOLARIS
779 !inet_aton(str, &sa.sin_addr)
780#else
781 !inet_pton(AF_INET, str, &sa.sin_addr)
782#endif
783 ) {
784 struct hostent *he;
785
786 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100787 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100788 }
789 else
790 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
791 }
792 sa.sin_port=htons(port);
793 sa.sin_family=AF_INET;
794
795 free(str);
796 return &sa;
797}
798
willy tarreau9fe663a2005-12-17 13:02:59 +0100799
800/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100801 * converts <str> to a list of listeners which are dynamically allocated.
802 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
803 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
804 * - <port> is a numerical port from 1 to 65535 ;
805 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
806 * This can be repeated as many times as necessary, separated by a coma.
807 * The <tail> argument is a pointer to a current list which should be appended
808 * to the tail of the new list. The pointer to the new list is returned.
809 */
810struct listener *str2listener(char *str, struct listener *tail) {
811 struct listener *l;
812 char *c, *next, *range, *dupstr;
813 int port, end;
814
815 next = dupstr = strdup(str);
816
817 while (next && *next) {
818 str = next;
819 /* 1) look for the end of the first address */
820 if ((next = strrchr(str, ',')) != NULL) {
821 *next++ = 0;
822 }
823
824 /* 2) look for the addr/port delimiter */
825 if ((range = strrchr(str, ':')) != NULL) {
826 *range++ = 0;
827 }
828 else {
829 Alert("Missing port number: '%s'\n", str);
830 }
831
832 /* 3) look for the port-end delimiter */
833 if ((c = strchr(range, '-')) != NULL) {
834 *c++ = 0;
835 end = atol(c);
836 }
837 else {
838 end = atol(range);
839 }
840
841 for (port = atol(range); port <= end; port++) {
842 l = (struct listener *)calloc(1, sizeof(struct listener));
843 l->next = tail;
844 tail = l;
845
846 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
847 l->addr.sin_addr.s_addr = INADDR_ANY;
848 }
849 else if (
850#ifndef SOLARIS
851 !inet_aton(str, &l->addr.sin_addr)
852#else
853 !inet_pton(AF_INET, str, &l->addr.sin_addr)
854#endif
855 ) {
856 struct hostent *he;
857
858 if ((he = gethostbyname(str)) == NULL) {
859 Alert("Invalid server name: '%s'\n", str);
860 }
861 else
862 l->addr.sin_addr = *(struct in_addr *) *(he->h_addr_list);
863 }
864 l->addr.sin_port=htons(port);
865 l->addr.sin_family=AF_INET;
866 } /* end for(port) */
867 } /* end while(next) */
868 free(dupstr);
869 return tail;
870}
871
872
873/*
willy tarreau9fe663a2005-12-17 13:02:59 +0100874 * This function sends a syslog message to both log servers of a proxy,
875 * or to global log servers if the proxy is NULL.
876 * It also tries not to waste too much time computing the message header.
877 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100878 */
879void send_log(struct proxy *p, int level, char *message, ...) {
880 static int logfd = -1; /* syslog UDP socket */
881 static long tvsec = -1; /* to force the string to be initialized */
882 struct timeval tv;
883 va_list argp;
884 static char logmsg[MAX_SYSLOG_LEN];
885 static char *dataptr = NULL;
886 int fac_level;
887 int hdr_len, data_len;
888 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +0100889 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +0100890 int nbloggers = 0;
891 char *log_ptr;
892
893 if (logfd < 0) {
894 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
895 return;
896 }
897
898 if (level < 0 || progname == NULL || message == NULL)
899 return;
900
901 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100902 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100903 /* this string is rebuild only once a second */
904 struct tm *tm = localtime(&tv.tv_sec);
905 tvsec = tv.tv_sec;
906
willy tarreauc29948c2005-12-17 13:10:27 +0100907 hdr_len = snprintf(logmsg, sizeof(logmsg),
908 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
909 monthname[tm->tm_mon],
910 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
911 progname, pid);
912 /* WARNING: depending upon implementations, snprintf may return
913 * either -1 or the number of bytes that would be needed to store
914 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100915 */
willy tarreauc29948c2005-12-17 13:10:27 +0100916 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
917 hdr_len = sizeof(logmsg);
918
919 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100920 }
921
922 va_start(argp, message);
923 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100924 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
925 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100926 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100927 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100928
929 if (p == NULL) {
930 if (global.logfac1 >= 0) {
931 sa[nbloggers] = &global.logsrv1;
932 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100933 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100934 nbloggers++;
935 }
936 if (global.logfac2 >= 0) {
937 sa[nbloggers] = &global.logsrv2;
938 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100939 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100940 nbloggers++;
941 }
942 } else {
943 if (p->logfac1 >= 0) {
944 sa[nbloggers] = &p->logsrv1;
945 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100946 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100947 nbloggers++;
948 }
949 if (p->logfac2 >= 0) {
950 sa[nbloggers] = &p->logsrv2;
951 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100952 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100953 nbloggers++;
954 }
955 }
956
957 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +0100958 /* we can filter the level of the messages that are sent to each logger */
959 if (level > loglevel[nbloggers])
960 continue;
961
willy tarreauc29948c2005-12-17 13:10:27 +0100962 /* For each target, we may have a different facility.
963 * We can also have a different log level for each message.
964 * This induces variations in the message header length.
965 * Since we don't want to recompute it each time, nor copy it every
966 * time, we only change the facility in the pre-computed header,
967 * and we change the pointer to the header accordingly.
968 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100969 fac_level = (facilities[nbloggers] << 3) + level;
970 log_ptr = logmsg + 3; /* last digit of the log level */
971 do {
972 *log_ptr = '0' + fac_level % 10;
973 fac_level /= 10;
974 log_ptr--;
975 } while (fac_level && log_ptr > logmsg);
976 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100977
willy tarreauc29948c2005-12-17 13:10:27 +0100978 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100979
980#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100981 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100982 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
983#else
willy tarreauc29948c2005-12-17 13:10:27 +0100984 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100985 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
986#endif
987 }
willy tarreau0f7af912005-12-17 12:21:26 +0100988}
989
990
991/* sets <tv> to the current time */
992static inline struct timeval *tv_now(struct timeval *tv) {
993 if (tv)
994 gettimeofday(tv, NULL);
995 return tv;
996}
997
998/*
999 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1000 */
1001static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1002 if (!tv || !from)
1003 return NULL;
1004 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1005 tv->tv_sec = from->tv_sec + (ms/1000);
1006 while (tv->tv_usec >= 1000000) {
1007 tv->tv_usec -= 1000000;
1008 tv->tv_sec++;
1009 }
1010 return tv;
1011}
1012
1013/*
1014 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1015 */
1016static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001017 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001018 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001019 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001020 return 1;
1021 else if (tv1->tv_usec < tv2->tv_usec)
1022 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001023 else if (tv1->tv_usec > tv2->tv_usec)
1024 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001025 else
1026 return 0;
1027}
1028
1029/*
1030 * returns the absolute difference, in ms, between tv1 and tv2
1031 */
1032unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1033 int cmp;
1034 unsigned long ret;
1035
1036
willy tarreauef900ab2005-12-17 12:52:52 +01001037 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001038 if (!cmp)
1039 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001040 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001041 struct timeval *tmp = tv1;
1042 tv1 = tv2;
1043 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001044 }
willy tarreauef900ab2005-12-17 12:52:52 +01001045 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001046 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001047 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001048 else
willy tarreauef900ab2005-12-17 12:52:52 +01001049 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001050 return (unsigned long) ret;
1051}
1052
1053/*
willy tarreau750a4722005-12-17 13:21:24 +01001054 * returns the difference, in ms, between tv1 and tv2
1055 */
1056static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1057 unsigned long ret;
1058
willy tarreau6e682ce2005-12-17 13:26:49 +01001059 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1060 if (tv2->tv_usec > tv1->tv_usec)
1061 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001062 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001063 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001064 return (unsigned long) ret;
1065}
1066
1067/*
willy tarreau0f7af912005-12-17 12:21:26 +01001068 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1069 */
1070static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001071 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001072 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001073 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001074 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1075 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001076 else
1077 return 0;
1078 }
willy tarreau0f7af912005-12-17 12:21:26 +01001079 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001080 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001081 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001082 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1083 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1084 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001085 else
1086 return 0;
1087}
1088
1089/*
1090 * returns the remaining time between tv1=now and event=tv2
1091 * if tv2 is passed, 0 is returned.
1092 */
1093static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1094 unsigned long ret;
1095
willy tarreau0f7af912005-12-17 12:21:26 +01001096 if (tv_cmp_ms(tv1, tv2) >= 0)
1097 return 0; /* event elapsed */
1098
willy tarreauef900ab2005-12-17 12:52:52 +01001099 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001100 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001101 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001102 else
willy tarreauef900ab2005-12-17 12:52:52 +01001103 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001104 return (unsigned long) ret;
1105}
1106
1107
1108/*
1109 * zeroes a struct timeval
1110 */
1111
1112static inline struct timeval *tv_eternity(struct timeval *tv) {
1113 tv->tv_sec = tv->tv_usec = 0;
1114 return tv;
1115}
1116
1117/*
1118 * returns 1 if tv is null, else 0
1119 */
1120static inline int tv_iseternity(struct timeval *tv) {
1121 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1122 return 1;
1123 else
1124 return 0;
1125}
1126
1127/*
1128 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1129 * considering that 0 is the eternity.
1130 */
1131static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1132 if (tv_iseternity(tv1))
1133 if (tv_iseternity(tv2))
1134 return 0; /* same */
1135 else
1136 return 1; /* tv1 later than tv2 */
1137 else if (tv_iseternity(tv2))
1138 return -1; /* tv2 later than tv1 */
1139
1140 if (tv1->tv_sec > tv2->tv_sec)
1141 return 1;
1142 else if (tv1->tv_sec < tv2->tv_sec)
1143 return -1;
1144 else if (tv1->tv_usec > tv2->tv_usec)
1145 return 1;
1146 else if (tv1->tv_usec < tv2->tv_usec)
1147 return -1;
1148 else
1149 return 0;
1150}
1151
1152/*
1153 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1154 * considering that 0 is the eternity.
1155 */
1156static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1157 if (tv_iseternity(tv1))
1158 if (tv_iseternity(tv2))
1159 return 0; /* same */
1160 else
1161 return 1; /* tv1 later than tv2 */
1162 else if (tv_iseternity(tv2))
1163 return -1; /* tv2 later than tv1 */
1164
willy tarreauefae1842005-12-17 12:51:03 +01001165 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001166 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001167 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001168 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001169 return -1;
1170 else
1171 return 0;
1172 }
1173 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001174 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001175 return 1;
1176 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001177 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001178 return -1;
1179 else
1180 return 0;
1181}
1182
1183/*
1184 * returns the first event between tv1 and tv2 into tvmin.
1185 * a zero tv is ignored. tvmin is returned.
1186 */
1187static inline struct timeval *tv_min(struct timeval *tvmin,
1188 struct timeval *tv1, struct timeval *tv2) {
1189
1190 if (tv_cmp2(tv1, tv2) <= 0)
1191 *tvmin = *tv1;
1192 else
1193 *tvmin = *tv2;
1194
1195 return tvmin;
1196}
1197
1198
1199
1200/***********************************************************/
1201/* fd management ***************************************/
1202/***********************************************************/
1203
1204
1205
willy tarreau5cbea6f2005-12-17 12:48:26 +01001206/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1207 * The file descriptor is also closed.
1208 */
willy tarreau0f7af912005-12-17 12:21:26 +01001209static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001210 FD_CLR(fd, StaticReadEvent);
1211 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001212 close(fd);
1213 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001214
1215 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1216 maxfd--;
1217}
1218
1219/* recomputes the maxfd limit from the fd */
1220static inline void fd_insert(int fd) {
1221 if (fd+1 > maxfd)
1222 maxfd = fd+1;
1223}
1224
1225/*************************************************************/
1226/* task management ***************************************/
1227/*************************************************************/
1228
willy tarreau5cbea6f2005-12-17 12:48:26 +01001229/* puts the task <t> in run queue <q>, and returns <t> */
1230static inline struct task *task_wakeup(struct task **q, struct task *t) {
1231 if (t->state == TASK_RUNNING)
1232 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001233 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001234 t->rqnext = *q;
1235 t->state = TASK_RUNNING;
1236 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001237 }
1238}
1239
willy tarreau5cbea6f2005-12-17 12:48:26 +01001240/* removes the task <t> from the queue <q>
1241 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001242 * set the run queue to point to the next one, and return it
1243 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001244static inline struct task *task_sleep(struct task **q, struct task *t) {
1245 if (t->state == TASK_RUNNING) {
1246 *q = t->rqnext;
1247 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001248 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001249 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001250}
1251
1252/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001253 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001254 * from the run queue. A pointer to the task itself is returned.
1255 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001256static inline struct task *task_delete(struct task *t) {
1257 t->prev->next = t->next;
1258 t->next->prev = t->prev;
1259 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001260}
1261
1262/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001263 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001264 */
1265static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001266 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001267}
1268
willy tarreau5cbea6f2005-12-17 12:48:26 +01001269/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001270 * may be only moved or left where it was, depending on its timing requirements.
1271 * <task> is returned.
1272 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001273struct task *task_queue(struct task *task) {
1274 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001275 struct task *start_from;
1276
1277 /* first, test if the task was already in a list */
1278 if (task->prev == NULL) {
1279 // start_from = list;
1280 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001281#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001282 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001283#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001284 /* insert the unlinked <task> into the list, searching back from the last entry */
1285 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1286 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001287#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001288 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001289#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001290 }
1291
1292 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1293 // start_from = start_from->next;
1294 // stats_tsk_nsrch++;
1295 // }
1296 }
1297 else if (task->prev == list ||
1298 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1299 start_from = task->next;
1300 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001301#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001302 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001303#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001304 return task; /* it's already in the right place */
1305 }
1306
willy tarreau750a4722005-12-17 13:21:24 +01001307#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001308 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001309#endif
1310
1311 /* if the task is not at the right place, there's little chance that
1312 * it has only shifted a bit, and it will nearly always be queued
1313 * at the end of the list because of constant timeouts
1314 * (observed in real case).
1315 */
1316#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1317 start_from = list->prev; /* assume we'll queue to the end of the list */
1318 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1319 start_from = start_from->prev;
1320#if STATTIME > 0
1321 stats_tsk_lsrch++;
1322#endif
1323 }
1324#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001325 /* insert the unlinked <task> into the list, searching after position <start_from> */
1326 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1327 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001328#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001329 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001330#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001331 }
willy tarreau750a4722005-12-17 13:21:24 +01001332#endif /* WE_REALLY_... */
1333
willy tarreau0f7af912005-12-17 12:21:26 +01001334 /* we need to unlink it now */
1335 task_delete(task);
1336 }
1337 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001338#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001339 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001340#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001341#ifdef LEFT_TO_TOP /* not very good */
1342 start_from = list;
1343 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1344 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001345#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001346 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001347#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001348 }
1349#else
1350 start_from = task->prev->prev; /* valid because of the previous test above */
1351 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1352 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001353#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001354 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001355#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001356 }
1357#endif
1358 /* we need to unlink it now */
1359 task_delete(task);
1360 }
1361 task->prev = start_from;
1362 task->next = start_from->next;
1363 task->next->prev = task;
1364 start_from->next = task;
1365 return task;
1366}
1367
1368
1369/*********************************************************************/
1370/* more specific functions ***************************************/
1371/*********************************************************************/
1372
1373/* some prototypes */
1374static int maintain_proxies(void);
1375
willy tarreau5cbea6f2005-12-17 12:48:26 +01001376/* this either returns the sockname or the original destination address. Code
1377 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1378 */
1379static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001380#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001381 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1382#else
willy tarreaua1598082005-12-17 13:08:06 +01001383#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001384 return getsockname(fd, (struct sockaddr *)sa, salen);
1385#else
1386 return -1;
1387#endif
1388#endif
1389}
1390
1391/*
1392 * frees the context associated to a session. It must have been removed first.
1393 */
1394static inline void session_free(struct session *s) {
1395 if (s->req)
1396 pool_free(buffer, s->req);
1397 if (s->rep)
1398 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001399 if (s->logs.uri)
1400 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001401 if (s->logs.cli_cookie)
1402 pool_free(capture, s->logs.cli_cookie);
1403 if (s->logs.srv_cookie)
1404 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001405
willy tarreau5cbea6f2005-12-17 12:48:26 +01001406 pool_free(session, s);
1407}
1408
willy tarreau0f7af912005-12-17 12:21:26 +01001409
1410/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001411 * This function tries to find a running server for the proxy <px>. A first
1412 * pass looks for active servers, and if none is found, a second pass also
1413 * looks for backup servers.
1414 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1415 */
1416static inline struct server *find_server(struct proxy *px) {
1417 struct server *srv = px->cursrv;
1418 int ignore_backup = 1;
1419
1420 do {
1421 do {
1422 if (srv == NULL)
1423 srv = px->srv;
1424 if (srv->state & SRV_RUNNING
1425 && !((srv->state & SRV_BACKUP) && ignore_backup))
1426 return srv;
1427 srv = srv->next;
1428 } while (srv != px->cursrv);
1429 } while (ignore_backup--);
1430 return NULL;
1431}
1432
1433/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001434 * This function initiates a connection to the current server (s->srv) if (s->direct)
1435 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001436 * it's OK, -1 if it's impossible.
1437 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001438int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001439 int one = 1;
1440 int fd;
1441
1442 // fprintf(stderr,"connect_server : s=%p\n",s);
1443
willy tarreaue39cd132005-12-17 13:00:18 +01001444 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001445 s->srv_addr = s->srv->addr;
1446 }
1447 else if (s->proxy->options & PR_O_BALANCE) {
1448 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001449 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001450
willy tarreau8337c6b2005-12-17 13:41:01 +01001451 srv = find_server(s->proxy);
1452
1453 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001454 return -1;
1455
willy tarreau8337c6b2005-12-17 13:41:01 +01001456 s->srv_addr = srv->addr;
1457 s->srv = srv;
1458 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001459 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001460 else /* unknown balancing algorithm */
1461 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001462 }
willy tarreaua1598082005-12-17 13:08:06 +01001463 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001464 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001465 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001466 }
1467 else if (s->proxy->options & PR_O_TRANSP) {
1468 /* in transparent mode, use the original dest addr if no dispatch specified */
1469 int salen = sizeof(struct sockaddr_in);
1470 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1471 qfprintf(stderr, "Cannot get original server address.\n");
1472 return -1;
1473 }
1474 }
willy tarreau0f7af912005-12-17 12:21:26 +01001475
willy tarreaua41a8b42005-12-17 14:02:24 +01001476 /* if this server remaps proxied ports, we'll use
1477 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001478 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001479 struct sockaddr_in sockname;
1480 int namelen;
1481
1482 namelen = sizeof(sockname);
1483 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1484 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1485 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1486 }
1487
willy tarreau0f7af912005-12-17 12:21:26 +01001488 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001489 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001490 return -1;
1491 }
1492
willy tarreau9fe663a2005-12-17 13:02:59 +01001493 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001494 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1495 close(fd);
1496 return -1;
1497 }
1498
willy tarreau0f7af912005-12-17 12:21:26 +01001499 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1500 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001501 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001502 close(fd);
1503 return -1;
1504 }
1505
willy tarreaua1598082005-12-17 13:08:06 +01001506 /* allow specific binding */
1507 if (s->proxy->options & PR_O_BIND_SRC &&
1508 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1509 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1510 close(fd);
1511 return -1;
1512 }
1513
willy tarreau0f7af912005-12-17 12:21:26 +01001514 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1515 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001516 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001517 close(fd);
1518 return -1;
1519 }
1520 else if (errno != EALREADY && errno != EISCONN) {
1521 close(fd);
1522 return -1;
1523 }
1524 }
1525
willy tarreau5cbea6f2005-12-17 12:48:26 +01001526 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001527 fdtab[fd].read = &event_srv_read;
1528 fdtab[fd].write = &event_srv_write;
1529 fdtab[fd].state = FD_STCONN; /* connection in progress */
1530
1531 FD_SET(fd, StaticWriteEvent); /* for connect status */
1532
1533 fd_insert(fd);
1534
1535 if (s->proxy->contimeout)
1536 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1537 else
1538 tv_eternity(&s->cnexpire);
1539 return 0;
1540}
1541
1542/*
1543 * this function is called on a read event from a client socket.
1544 * It returns 0.
1545 */
1546int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001547 struct task *t = fdtab[fd].owner;
1548 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001549 struct buffer *b = s->req;
1550 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001551
1552 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1553
willy tarreau0f7af912005-12-17 12:21:26 +01001554 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001555 while (1) {
1556 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1557 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001558 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001559 }
1560 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001561 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562 }
1563 else {
1564 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001565 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1566 * since it means that the rewrite protection has been removed. This
1567 * implies that the if statement can be removed.
1568 */
1569 if (max > b->rlim - b->data)
1570 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001571 }
1572
1573 if (max == 0) { /* not anymore room to store data */
1574 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001575 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001576 }
1577
willy tarreau3242e862005-12-17 12:27:53 +01001578#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001579 {
1580 int skerr, lskerr;
1581
1582 lskerr = sizeof(skerr);
1583 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1584 if (skerr)
1585 ret = -1;
1586 else
1587 ret = recv(fd, b->r, max, 0);
1588 }
willy tarreau3242e862005-12-17 12:27:53 +01001589#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001590 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001591#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001592 if (ret > 0) {
1593 b->r += ret;
1594 b->l += ret;
1595 s->res_cr = RES_DATA;
1596
1597 if (b->r == b->data + BUFSIZE) {
1598 b->r = b->data; /* wrap around the buffer */
1599 }
willy tarreaua1598082005-12-17 13:08:06 +01001600
1601 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001602 /* we hope to read more data or to get a close on next round */
1603 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001604 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001605 else if (ret == 0) {
1606 s->res_cr = RES_NULL;
1607 break;
1608 }
1609 else if (errno == EAGAIN) {/* ignore EAGAIN */
1610 break;
1611 }
1612 else {
1613 s->res_cr = RES_ERROR;
1614 fdtab[fd].state = FD_STERROR;
1615 break;
1616 }
1617 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001618 }
1619 else {
1620 s->res_cr = RES_ERROR;
1621 fdtab[fd].state = FD_STERROR;
1622 }
1623
willy tarreau5cbea6f2005-12-17 12:48:26 +01001624 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001625 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001626 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1627 else
1628 tv_eternity(&s->crexpire);
1629
1630 task_wakeup(&rq, t);
1631 }
willy tarreau0f7af912005-12-17 12:21:26 +01001632
willy tarreau0f7af912005-12-17 12:21:26 +01001633 return 0;
1634}
1635
1636
1637/*
1638 * this function is called on a read event from a server socket.
1639 * It returns 0.
1640 */
1641int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001642 struct task *t = fdtab[fd].owner;
1643 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001644 struct buffer *b = s->rep;
1645 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001646
1647 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1648
willy tarreau0f7af912005-12-17 12:21:26 +01001649 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001650 while (1) {
1651 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1652 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001653 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001654 }
1655 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001656 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001657 }
1658 else {
1659 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001660 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1661 * since it means that the rewrite protection has been removed. This
1662 * implies that the if statement can be removed.
1663 */
1664 if (max > b->rlim - b->data)
1665 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001666 }
1667
1668 if (max == 0) { /* not anymore room to store data */
1669 FD_CLR(fd, StaticReadEvent);
1670 break;
1671 }
1672
willy tarreau3242e862005-12-17 12:27:53 +01001673#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001674 {
1675 int skerr, lskerr;
1676
1677 lskerr = sizeof(skerr);
1678 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1679 if (skerr)
1680 ret = -1;
1681 else
1682 ret = recv(fd, b->r, max, 0);
1683 }
willy tarreau3242e862005-12-17 12:27:53 +01001684#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001685 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001686#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001687 if (ret > 0) {
1688 b->r += ret;
1689 b->l += ret;
1690 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001691
willy tarreau5cbea6f2005-12-17 12:48:26 +01001692 if (b->r == b->data + BUFSIZE) {
1693 b->r = b->data; /* wrap around the buffer */
1694 }
willy tarreaua1598082005-12-17 13:08:06 +01001695
1696 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 /* we hope to read more data or to get a close on next round */
1698 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001699 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700 else if (ret == 0) {
1701 s->res_sr = RES_NULL;
1702 break;
1703 }
1704 else if (errno == EAGAIN) {/* ignore EAGAIN */
1705 break;
1706 }
1707 else {
1708 s->res_sr = RES_ERROR;
1709 fdtab[fd].state = FD_STERROR;
1710 break;
1711 }
1712 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001713 }
1714 else {
1715 s->res_sr = RES_ERROR;
1716 fdtab[fd].state = FD_STERROR;
1717 }
1718
willy tarreau5cbea6f2005-12-17 12:48:26 +01001719 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001720 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001721 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1722 else
1723 tv_eternity(&s->srexpire);
1724
1725 task_wakeup(&rq, t);
1726 }
willy tarreau0f7af912005-12-17 12:21:26 +01001727
willy tarreau0f7af912005-12-17 12:21:26 +01001728 return 0;
1729}
1730
1731/*
1732 * this function is called on a write event from a client socket.
1733 * It returns 0.
1734 */
1735int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001736 struct task *t = fdtab[fd].owner;
1737 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001738 struct buffer *b = s->rep;
1739 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001740
1741 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1742
1743 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001744 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001745 // max = BUFSIZE; BUG !!!!
1746 max = 0;
1747 }
1748 else if (b->r > b->w) {
1749 max = b->r - b->w;
1750 }
1751 else
1752 max = b->data + BUFSIZE - b->w;
1753
willy tarreau0f7af912005-12-17 12:21:26 +01001754 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001755#ifndef MSG_NOSIGNAL
1756 int skerr, lskerr;
1757#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001758
1759 if (max == 0) {
1760 s->res_cw = RES_NULL;
1761 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001762 tv_eternity(&s->cwexpire);
1763 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001764 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001765 }
1766
willy tarreau3242e862005-12-17 12:27:53 +01001767#ifndef MSG_NOSIGNAL
1768 lskerr=sizeof(skerr);
1769 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1770 if (skerr)
1771 ret = -1;
1772 else
1773 ret = send(fd, b->w, max, MSG_DONTWAIT);
1774#else
willy tarreau0f7af912005-12-17 12:21:26 +01001775 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001776#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001777
1778 if (ret > 0) {
1779 b->l -= ret;
1780 b->w += ret;
1781
1782 s->res_cw = RES_DATA;
1783
1784 if (b->w == b->data + BUFSIZE) {
1785 b->w = b->data; /* wrap around the buffer */
1786 }
1787 }
1788 else if (ret == 0) {
1789 /* nothing written, just make as if we were never called */
1790// s->res_cw = RES_NULL;
1791 return 0;
1792 }
1793 else if (errno == EAGAIN) /* ignore EAGAIN */
1794 return 0;
1795 else {
1796 s->res_cw = RES_ERROR;
1797 fdtab[fd].state = FD_STERROR;
1798 }
1799 }
1800 else {
1801 s->res_cw = RES_ERROR;
1802 fdtab[fd].state = FD_STERROR;
1803 }
1804
willy tarreaub1ff9db2005-12-17 13:51:03 +01001805 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001806 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001807 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
1808 s->crexpire = s->cwexpire;
1809 }
willy tarreau0f7af912005-12-17 12:21:26 +01001810 else
1811 tv_eternity(&s->cwexpire);
1812
willy tarreau5cbea6f2005-12-17 12:48:26 +01001813 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001814 return 0;
1815}
1816
1817
1818/*
1819 * this function is called on a write event from a server socket.
1820 * It returns 0.
1821 */
1822int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001823 struct task *t = fdtab[fd].owner;
1824 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001825 struct buffer *b = s->req;
1826 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001827
1828 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1829
1830 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001831 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001832 // max = BUFSIZE; BUG !!!!
1833 max = 0;
1834 }
1835 else if (b->r > b->w) {
1836 max = b->r - b->w;
1837 }
1838 else
1839 max = b->data + BUFSIZE - b->w;
1840
willy tarreau0f7af912005-12-17 12:21:26 +01001841 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001842#ifndef MSG_NOSIGNAL
1843 int skerr, lskerr;
1844#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001845 if (max == 0) {
1846 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001847 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001848 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001849 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01001850 tv_eternity(&s->swexpire);
1851 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01001852 return 0;
1853 }
1854
willy tarreauef900ab2005-12-17 12:52:52 +01001855
willy tarreau3242e862005-12-17 12:27:53 +01001856#ifndef MSG_NOSIGNAL
1857 lskerr=sizeof(skerr);
1858 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1859 if (skerr)
1860 ret = -1;
1861 else
1862 ret = send(fd, b->w, max, MSG_DONTWAIT);
1863#else
willy tarreau0f7af912005-12-17 12:21:26 +01001864 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001865#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001866 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001867 if (ret > 0) {
1868 b->l -= ret;
1869 b->w += ret;
1870
1871 s->res_sw = RES_DATA;
1872
1873 if (b->w == b->data + BUFSIZE) {
1874 b->w = b->data; /* wrap around the buffer */
1875 }
1876 }
1877 else if (ret == 0) {
1878 /* nothing written, just make as if we were never called */
1879 // s->res_sw = RES_NULL;
1880 return 0;
1881 }
1882 else if (errno == EAGAIN) /* ignore EAGAIN */
1883 return 0;
1884 else {
1885 s->res_sw = RES_ERROR;
1886 fdtab[fd].state = FD_STERROR;
1887 }
1888 }
1889 else {
1890 s->res_sw = RES_ERROR;
1891 fdtab[fd].state = FD_STERROR;
1892 }
1893
willy tarreaub1ff9db2005-12-17 13:51:03 +01001894 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001895 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001896 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
1897 s->srexpire = s->swexpire;
1898 }
willy tarreau0f7af912005-12-17 12:21:26 +01001899 else
1900 tv_eternity(&s->swexpire);
1901
willy tarreau5cbea6f2005-12-17 12:48:26 +01001902 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001903 return 0;
1904}
1905
1906
1907/*
willy tarreaue39cd132005-12-17 13:00:18 +01001908 * returns a message to the client ; the connection is shut down for read,
1909 * and the request is cleared so that no server connection can be initiated.
1910 * The client must be in a valid state for this (HEADER, DATA ...).
1911 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01001912 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001913 */
1914void client_retnclose(struct session *s, int len, const char *msg) {
1915 FD_CLR(s->cli_fd, StaticReadEvent);
1916 FD_SET(s->cli_fd, StaticWriteEvent);
1917 tv_eternity(&s->crexpire);
1918 shutdown(s->cli_fd, SHUT_RD);
1919 s->cli_state = CL_STSHUTR;
1920 strcpy(s->rep->data, msg);
1921 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001922 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001923 s->rep->r += len;
1924 s->req->l = 0;
1925}
1926
1927
1928/*
1929 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01001930 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001931 */
1932void client_return(struct session *s, int len, const char *msg) {
1933 strcpy(s->rep->data, msg);
1934 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001935 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001936 s->rep->r += len;
1937 s->req->l = 0;
1938}
1939
willy tarreau9fe663a2005-12-17 13:02:59 +01001940/*
1941 * send a log for the session when we have enough info about it
1942 */
1943void sess_log(struct session *s) {
1944 unsigned char *pn;
1945 struct proxy *p = s->proxy;
1946 int log;
1947 char *uri;
1948 char *pxid;
1949 char *srv;
1950
1951 /* This is a first attempt at a better logging system.
1952 * For now, we rely on send_log() to provide the date, although it obviously
1953 * is the date of the log and not of the request, and most fields are not
1954 * computed.
1955 */
1956
willy tarreaua1598082005-12-17 13:08:06 +01001957 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001958
1959 pn = (log & LW_CLIP) ?
1960 (unsigned char *)&s->cli_addr.sin_addr :
1961 (unsigned char *)"\0\0\0\0";
1962
willy tarreaua1598082005-12-17 13:08:06 +01001963 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001964 pxid = p->id;
1965 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001966 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1967
1968 if (p->to_log & LW_DATE) {
1969 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1970
willy tarreau036e1ce2005-12-17 13:46:33 +01001971 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
willy tarreaua1598082005-12-17 13:08:06 +01001972 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1973 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1974 tm->tm_hour, tm->tm_min, tm->tm_sec,
1975 pxid, srv,
1976 s->logs.t_request,
1977 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1978 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1979 s->logs.t_close,
1980 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001981 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1982 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01001983 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
1984 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
1985 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
1986 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01001987 uri);
1988 }
1989 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01001990 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
willy tarreaua1598082005-12-17 13:08:06 +01001991 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1992 pxid, srv,
1993 s->logs.t_request,
1994 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1995 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1996 s->logs.t_close,
1997 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001998 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1999 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002000 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2001 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2002 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2003 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01002004 uri);
2005 }
2006
2007 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002008}
2009
willy tarreaue39cd132005-12-17 13:00:18 +01002010
2011/*
willy tarreau0f7af912005-12-17 12:21:26 +01002012 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002013 * to an accept. It tries to accept as many connections as possible.
2014 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002015 */
2016int event_accept(int fd) {
2017 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002018 struct session *s;
2019 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002020 int cfd;
2021 int one = 1;
2022
willy tarreau5cbea6f2005-12-17 12:48:26 +01002023 while (p->nbconn < p->maxconn) {
2024 struct sockaddr_in addr;
2025 int laddr = sizeof(addr);
2026 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2027 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002028
willy tarreau5cbea6f2005-12-17 12:48:26 +01002029 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2030 Alert("out of memory in event_accept().\n");
2031 FD_CLR(fd, StaticReadEvent);
2032 p->state = PR_STIDLE;
2033 close(cfd);
2034 return 0;
2035 }
willy tarreau0f7af912005-12-17 12:21:26 +01002036
willy tarreau5cbea6f2005-12-17 12:48:26 +01002037 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2038 Alert("out of memory in event_accept().\n");
2039 FD_CLR(fd, StaticReadEvent);
2040 p->state = PR_STIDLE;
2041 close(cfd);
2042 pool_free(session, s);
2043 return 0;
2044 }
willy tarreau0f7af912005-12-17 12:21:26 +01002045
willy tarreau5cbea6f2005-12-17 12:48:26 +01002046 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002047 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002048 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2049 close(cfd);
2050 pool_free(task, t);
2051 pool_free(session, s);
2052 return 0;
2053 }
willy tarreau0f7af912005-12-17 12:21:26 +01002054
willy tarreau5cbea6f2005-12-17 12:48:26 +01002055 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2056 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2057 (char *) &one, sizeof(one)) == -1)) {
2058 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2059 close(cfd);
2060 pool_free(task, t);
2061 pool_free(session, s);
2062 return 0;
2063 }
willy tarreau0f7af912005-12-17 12:21:26 +01002064
willy tarreau9fe663a2005-12-17 13:02:59 +01002065 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2066 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2067 t->state = TASK_IDLE;
2068 t->process = process_session;
2069 t->context = s;
2070
2071 s->task = t;
2072 s->proxy = p;
2073 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2074 s->srv_state = SV_STIDLE;
2075 s->req = s->rep = NULL; /* will be allocated later */
2076 s->flags = 0;
2077 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2078 s->cli_fd = cfd;
2079 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002080 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002081 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002082
2083 s->logs.logwait = p->to_log;
2084 s->logs.tv_accept = now;
2085 s->logs.t_request = -1;
2086 s->logs.t_connect = -1;
2087 s->logs.t_data = -1;
2088 s->logs.t_close = 0;
2089 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002090 s->logs.cli_cookie = NULL;
2091 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002092 s->logs.status = -1;
2093 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002094
willy tarreau2f6ba652005-12-17 13:57:42 +01002095 s->uniq_id = totalconn;
2096
willy tarreau5cbea6f2005-12-17 12:48:26 +01002097 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2098 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01002099 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002100 unsigned char *pn, *sn;
2101 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002102
willy tarreau5cbea6f2005-12-17 12:48:26 +01002103 namelen = sizeof(sockname);
2104 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2105 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
2106 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01002107 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01002108
willy tarreau9fe663a2005-12-17 13:02:59 +01002109 if (p->to_log) {
2110 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002111 if (s->logs.logwait & LW_CLIP)
2112 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002113 sess_log(s);
2114 }
2115 else
2116 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
2117 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
2118 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
2119 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01002120 }
willy tarreau0f7af912005-12-17 12:21:26 +01002121
willy tarreau9fe663a2005-12-17 13:02:59 +01002122 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002123 struct sockaddr_in sockname;
2124 unsigned char *pn, *sn;
2125 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002126 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002127
2128 namelen = sizeof(sockname);
2129 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2130 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
2131 sn = (unsigned char *)&sockname.sin_addr;
2132 pn = (unsigned char *)&s->cli_addr.sin_addr;
2133
2134 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%d.%d.%d.%d:%d]\n",
2135 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2136 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port));
willy tarreauef900ab2005-12-17 12:52:52 +01002137 write(1, trash, len);
2138 }
willy tarreau0f7af912005-12-17 12:21:26 +01002139
willy tarreau5cbea6f2005-12-17 12:48:26 +01002140 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2141 close(cfd); /* nothing can be done for this fd without memory */
2142 pool_free(task, t);
2143 pool_free(session, s);
2144 return 0;
2145 }
2146 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002147 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002148 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2149 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002150 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002151 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002152
willy tarreau5cbea6f2005-12-17 12:48:26 +01002153 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2154 pool_free(buffer, s->req);
2155 close(cfd); /* nothing can be done for this fd without memory */
2156 pool_free(task, t);
2157 pool_free(session, s);
2158 return 0;
2159 }
2160 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002161 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002162 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 +01002163
willy tarreau5cbea6f2005-12-17 12:48:26 +01002164 fdtab[cfd].read = &event_cli_read;
2165 fdtab[cfd].write = &event_cli_write;
2166 fdtab[cfd].owner = t;
2167 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002168
willy tarreau5cbea6f2005-12-17 12:48:26 +01002169 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002170 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2171 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2172 else
2173 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002174 }
2175 else {
2176 FD_SET(cfd, StaticReadEvent);
2177 }
2178
2179 fd_insert(cfd);
2180
2181 tv_eternity(&s->cnexpire);
2182 tv_eternity(&s->srexpire);
2183 tv_eternity(&s->swexpire);
2184 tv_eternity(&s->cwexpire);
2185
2186 if (s->proxy->clitimeout)
2187 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2188 else
2189 tv_eternity(&s->crexpire);
2190
2191 t->expire = s->crexpire;
2192
2193 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002194
2195 if (p->mode != PR_MODE_HEALTH)
2196 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002197
2198 p->nbconn++;
2199 actconn++;
2200 totalconn++;
2201
2202 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2203 } /* end of while (p->nbconn < p->maxconn) */
2204 return 0;
2205}
willy tarreau0f7af912005-12-17 12:21:26 +01002206
willy tarreau0f7af912005-12-17 12:21:26 +01002207
willy tarreau5cbea6f2005-12-17 12:48:26 +01002208/*
2209 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002210 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2211 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002212 * or -1 if an error occured.
2213 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002214int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002215 struct task *t = fdtab[fd].owner;
2216 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002217
willy tarreau5cbea6f2005-12-17 12:48:26 +01002218 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002219 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002220 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002221 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002222 if (skerr)
2223 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002224 else {
2225 if (s->proxy->options & PR_O_HTTP_CHK) {
2226 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002227 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002228 * so we'll send the request, and won't wake the checker up now.
2229 */
2230#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002231 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002232#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002233 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002234#endif
2235 if (ret == 22) {
2236 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2237 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2238 return 0;
2239 }
2240 else
2241 s->result = -1;
2242 }
2243 else {
2244 /* good TCP connection is enough */
2245 s->result = 1;
2246 }
2247 }
2248
2249 task_wakeup(&rq, t);
2250 return 0;
2251}
2252
willy tarreau0f7af912005-12-17 12:21:26 +01002253
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002254/*
2255 * This function is used only for server health-checks. It handles
2256 * the server's reply to an HTTP request. It returns 1 if the server replies
2257 * 2xx or 3xx (valid responses), or -1 in other cases.
2258 */
2259int event_srv_chk_r(int fd) {
2260 char reply[64];
2261 int len;
2262 struct task *t = fdtab[fd].owner;
2263 struct server *s = t->context;
2264
2265 int skerr, lskerr;
2266 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002267
2268 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002269#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002270 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2271 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002272 len = recv(fd, reply, sizeof(reply), 0);
2273#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002274 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2275 * but the connection was closed on the remote end. Fortunately, recv still
2276 * works correctly and we don't need to do the getsockopt() on linux.
2277 */
2278 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002279#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002280 if ((len >= sizeof("HTTP/1.0 000")) &&
2281 !memcmp(reply, "HTTP/1.", 7) &&
2282 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2283 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002284
2285 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002286 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002287 return 0;
2288}
2289
2290
2291/*
2292 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2293 * and moves <end> just after the end of <str>.
2294 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2295 * the shift value (positive or negative) is returned.
2296 * If there's no space left, the move is not done.
2297 *
2298 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002299int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002300 int delta;
2301 int len;
2302
2303 len = strlen(str);
2304 delta = len - (end - pos);
2305
2306 if (delta + b->r >= b->data + BUFSIZE)
2307 return 0; /* no space left */
2308
2309 /* first, protect the end of the buffer */
2310 memmove(end + delta, end, b->data + b->l - end);
2311
2312 /* now, copy str over pos */
2313 memcpy(pos, str,len);
2314
willy tarreau5cbea6f2005-12-17 12:48:26 +01002315 /* we only move data after the displaced zone */
2316 if (b->r > pos) b->r += delta;
2317 if (b->w > pos) b->w += delta;
2318 if (b->h > pos) b->h += delta;
2319 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002320 b->l += delta;
2321
2322 return delta;
2323}
2324
willy tarreau8337c6b2005-12-17 13:41:01 +01002325/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002326 * len is 0.
2327 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002328int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002329 int delta;
2330
2331 delta = len - (end - pos);
2332
2333 if (delta + b->r >= b->data + BUFSIZE)
2334 return 0; /* no space left */
2335
2336 /* first, protect the end of the buffer */
2337 memmove(end + delta, end, b->data + b->l - end);
2338
2339 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002340 if (len)
2341 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002342
willy tarreau5cbea6f2005-12-17 12:48:26 +01002343 /* we only move data after the displaced zone */
2344 if (b->r > pos) b->r += delta;
2345 if (b->w > pos) b->w += delta;
2346 if (b->h > pos) b->h += delta;
2347 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002348 b->l += delta;
2349
2350 return delta;
2351}
2352
2353
2354int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2355 char *old_dst = dst;
2356
2357 while (*str) {
2358 if (*str == '\\') {
2359 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002360 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002361 int len, num;
2362
2363 num = *str - '0';
2364 str++;
2365
2366 if (matches[num].rm_so > -1) {
2367 len = matches[num].rm_eo - matches[num].rm_so;
2368 memcpy(dst, src + matches[num].rm_so, len);
2369 dst += len;
2370 }
2371
2372 }
2373 else if (*str == 'x') {
2374 unsigned char hex1, hex2;
2375 str++;
2376
2377 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2378
2379 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2380 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2381 *dst++ = (hex1<<4) + hex2;
2382 }
2383 else
2384 *dst++ = *str++;
2385 }
2386 else
2387 *dst++ = *str++;
2388 }
2389 *dst = 0;
2390 return dst - old_dst;
2391}
2392
willy tarreau9fe663a2005-12-17 13:02:59 +01002393
willy tarreau0f7af912005-12-17 12:21:26 +01002394/*
2395 * manages the client FSM and its socket. BTW, it also tries to handle the
2396 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2397 * 0 else.
2398 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002399int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002400 int s = t->srv_state;
2401 int c = t->cli_state;
2402 struct buffer *req = t->req;
2403 struct buffer *rep = t->rep;
2404
willy tarreau750a4722005-12-17 13:21:24 +01002405#ifdef DEBUG_FULL
2406 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2407#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002408 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2409 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2410 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2411 //);
2412 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002413 /* now parse the partial (or complete) headers */
2414 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2415 char *ptr;
2416 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002417
willy tarreau5cbea6f2005-12-17 12:48:26 +01002418 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002419
willy tarreau0f7af912005-12-17 12:21:26 +01002420 /* look for the end of the current header */
2421 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2422 ptr++;
2423
willy tarreau5cbea6f2005-12-17 12:48:26 +01002424 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002425 int line, len;
2426 /* we can only get here after an end of headers */
2427 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002428
willy tarreaue39cd132005-12-17 13:00:18 +01002429 if (t->flags & SN_CLDENY) {
2430 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002431 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002432 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002433 if (!(t->flags & SN_ERR_MASK))
2434 t->flags |= SN_ERR_PRXCOND;
2435 if (!(t->flags & SN_FINST_MASK))
2436 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002437 return 1;
2438 }
2439
willy tarreau5cbea6f2005-12-17 12:48:26 +01002440 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002441 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2442 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002443 }
willy tarreau0f7af912005-12-17 12:21:26 +01002444
willy tarreau9fe663a2005-12-17 13:02:59 +01002445 if (t->proxy->options & PR_O_FWDFOR) {
2446 /* insert an X-Forwarded-For header */
2447 unsigned char *pn;
2448 pn = (unsigned char *)&t->cli_addr.sin_addr;
willy tarreau750a4722005-12-17 13:21:24 +01002449 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01002450 pn[0], pn[1], pn[2], pn[3]);
willy tarreau750a4722005-12-17 13:21:24 +01002451 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau9fe663a2005-12-17 13:02:59 +01002452 }
2453
willy tarreaucd878942005-12-17 13:27:43 +01002454 if (!memcmp(req->data, "POST ", 5))
2455 t->flags |= SN_POST; /* this is a POST request */
2456
willy tarreau5cbea6f2005-12-17 12:48:26 +01002457 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002458 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002459
willy tarreau750a4722005-12-17 13:21:24 +01002460 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002461 /* FIXME: we'll set the client in a wait state while we try to
2462 * connect to the server. Is this really needed ? wouldn't it be
2463 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002464 //FD_CLR(t->cli_fd, StaticReadEvent);
2465 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002466
2467 /* FIXME: if we break here (as up to 1.1.23), having the client
2468 * shutdown its connection can lead to an abort further.
2469 * it's better to either return 1 or even jump directly to the
2470 * data state which will save one schedule.
2471 */
2472 //break;
2473 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002474 }
willy tarreau0f7af912005-12-17 12:21:26 +01002475
willy tarreau5cbea6f2005-12-17 12:48:26 +01002476 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2477 if (ptr > req->r - 2) {
2478 /* this is a partial header, let's wait for more to come */
2479 req->lr = ptr;
2480 break;
2481 }
willy tarreau0f7af912005-12-17 12:21:26 +01002482
willy tarreau5cbea6f2005-12-17 12:48:26 +01002483 /* now we know that *ptr is either \r or \n,
2484 * and that there are at least 1 char after it.
2485 */
2486 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2487 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2488 else
2489 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002490
willy tarreau5cbea6f2005-12-17 12:48:26 +01002491 /*
2492 * now we know that we have a full header ; we can do whatever
2493 * we want with these pointers :
2494 * req->h = beginning of header
2495 * ptr = end of header (first \r or \n)
2496 * req->lr = beginning of next line (next rep->h)
2497 * req->r = end of data (not used at this stage)
2498 */
willy tarreau0f7af912005-12-17 12:21:26 +01002499
willy tarreau8337c6b2005-12-17 13:41:01 +01002500 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002501 /* we have a complete HTTP request that we must log */
2502 int urilen;
2503
willy tarreaua1598082005-12-17 13:08:06 +01002504 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002505 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002506 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002507 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002508 if (!(t->flags & SN_ERR_MASK))
2509 t->flags |= SN_ERR_PRXCOND;
2510 if (!(t->flags & SN_FINST_MASK))
2511 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002512 return 1;
2513 }
2514
2515 urilen = ptr - req->h;
2516 if (urilen >= REQURI_LEN)
2517 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002518 memcpy(t->logs.uri, req->h, urilen);
2519 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002520
willy tarreaua1598082005-12-17 13:08:06 +01002521 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002522 sess_log(t);
2523 }
2524
willy tarreau5cbea6f2005-12-17 12:48:26 +01002525 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002526
willy tarreau9fe663a2005-12-17 13:02:59 +01002527 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002528 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002529 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 +01002530 max = ptr - req->h;
2531 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002532 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002533 trash[len++] = '\n';
2534 write(1, trash, len);
2535 }
willy tarreau0f7af912005-12-17 12:21:26 +01002536
willy tarreau5cbea6f2005-12-17 12:48:26 +01002537 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002538 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2539 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002540 char term;
2541
2542 term = *ptr;
2543 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002544 exp = t->proxy->req_exp;
2545 do {
2546 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2547 switch (exp->action) {
2548 case ACT_ALLOW:
2549 if (!(t->flags & SN_CLDENY))
2550 t->flags |= SN_CLALLOW;
2551 break;
2552 case ACT_REPLACE:
2553 if (!(t->flags & SN_CLDENY)) {
2554 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2555 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2556 }
2557 break;
2558 case ACT_REMOVE:
2559 if (!(t->flags & SN_CLDENY))
2560 delete_header = 1;
2561 break;
2562 case ACT_DENY:
2563 if (!(t->flags & SN_CLALLOW))
2564 t->flags |= SN_CLDENY;
2565 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002566 case ACT_PASS: /* we simply don't deny this one */
2567 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002568 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002569 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002570 }
willy tarreaue39cd132005-12-17 13:00:18 +01002571 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002572 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002573 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002574
willy tarreau240afa62005-12-17 13:14:35 +01002575 /* Now look for cookies. Conforming to RFC2109, we have to support
2576 * attributes whose name begin with a '$', and associate them with
2577 * the right cookie, if we want to delete this cookie.
2578 * So there are 3 cases for each cookie read :
2579 * 1) it's a special attribute, beginning with a '$' : ignore it.
2580 * 2) it's a server id cookie that we *MAY* want to delete : save
2581 * some pointers on it (last semi-colon, beginning of cookie...)
2582 * 3) it's an application cookie : we *MAY* have to delete a previous
2583 * "special" cookie.
2584 * At the end of loop, if a "special" cookie remains, we may have to
2585 * remove it. If no application cookie persists in the header, we
2586 * *MUST* delete it
2587 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002588 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002589 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01002590 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002591 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002592 char *del_colon, *del_cookie, *colon;
2593 int app_cookies;
2594
willy tarreau5cbea6f2005-12-17 12:48:26 +01002595 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002596 colon = p1;
2597 /* del_cookie == NULL => nothing to be deleted */
2598 del_colon = del_cookie = NULL;
2599 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002600
2601 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002602 /* skip spaces and colons, but keep an eye on these ones */
2603 while (p1 < ptr) {
2604 if (*p1 == ';' || *p1 == ',')
2605 colon = p1;
2606 else if (!isspace((int)*p1))
2607 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002609 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002610
2611 if (p1 == ptr)
2612 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002613
2614 /* p1 is at the beginning of the cookie name */
2615 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002616 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002617 p2++;
2618
2619 if (p2 == ptr)
2620 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002621
2622 p3 = p2 + 1; /* skips the '=' sign */
2623 if (p3 == ptr)
2624 break;
2625
willy tarreau240afa62005-12-17 13:14:35 +01002626 p4 = p3;
2627 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002628 p4++;
2629
2630 /* here, we have the cookie name between p1 and p2,
2631 * and its value between p3 and p4.
2632 * we can process it.
2633 */
2634
willy tarreau240afa62005-12-17 13:14:35 +01002635 if (*p1 == '$') {
2636 /* skip this one */
2637 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002638 else {
2639 /* first, let's see if we want to capture it */
2640 if (t->proxy->capture_name != NULL &&
2641 t->logs.cli_cookie == NULL &&
2642 (p4 - p1 >= t->proxy->capture_namelen) &&
2643 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2644 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002645
willy tarreau8337c6b2005-12-17 13:41:01 +01002646 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2647 Alert("HTTP logging : out of memory.\n");
2648 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002649
willy tarreau8337c6b2005-12-17 13:41:01 +01002650 if (log_len > t->proxy->capture_len)
2651 log_len = t->proxy->capture_len;
2652 memcpy(t->logs.cli_cookie, p1, log_len);
2653 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002654 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002655
2656 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2657 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2658 /* Cool... it's the right one */
2659 struct server *srv = t->proxy->srv;
2660
2661 while (srv &&
2662 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2663 srv = srv->next;
2664 }
2665
willy tarreau036e1ce2005-12-17 13:46:33 +01002666 if (!srv) {
2667 t->flags &= ~SN_CK_MASK;
2668 t->flags |= SN_CK_INVALID;
2669 }
2670 else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002671 /* we found the server and it's usable */
willy tarreau036e1ce2005-12-17 13:46:33 +01002672 t->flags &= ~SN_CK_MASK;
2673 t->flags |= SN_CK_VALID | SN_DIRECT;
willy tarreau8337c6b2005-12-17 13:41:01 +01002674 t->srv = srv;
2675 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002676 else {
2677 t->flags &= ~SN_CK_MASK;
2678 t->flags |= SN_CK_DOWN;
2679 }
2680
willy tarreau8337c6b2005-12-17 13:41:01 +01002681 /* if this cookie was set in insert+indirect mode, then it's better that the
2682 * server never sees it.
2683 */
2684 if (del_cookie == NULL &&
2685 (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 +01002686 del_cookie = p1;
2687 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002688 }
willy tarreau240afa62005-12-17 13:14:35 +01002689 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002690 else {
2691 /* now we know that we must keep this cookie since it's
2692 * not ours. But if we wanted to delete our cookie
2693 * earlier, we cannot remove the complete header, but we
2694 * can remove the previous block itself.
2695 */
2696 app_cookies++;
2697
2698 if (del_cookie != NULL) {
2699 buffer_replace2(req, del_cookie, p1, NULL, 0);
2700 p4 -= (p1 - del_cookie);
2701 ptr -= (p1 - del_cookie);
2702 del_cookie = del_colon = NULL;
2703 }
willy tarreau240afa62005-12-17 13:14:35 +01002704 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002705 }
willy tarreau240afa62005-12-17 13:14:35 +01002706
willy tarreau5cbea6f2005-12-17 12:48:26 +01002707 /* we'll have to look for another cookie ... */
2708 p1 = p4;
2709 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002710
2711 /* There's no more cookie on this line.
2712 * We may have marked the last one(s) for deletion.
2713 * We must do this now in two ways :
2714 * - if there is no app cookie, we simply delete the header ;
2715 * - if there are app cookies, we must delete the end of the
2716 * string properly, including the colon/semi-colon before
2717 * the cookie name.
2718 */
2719 if (del_cookie != NULL) {
2720 if (app_cookies) {
2721 buffer_replace2(req, del_colon, ptr, NULL, 0);
2722 /* WARNING! <ptr> becomes invalid for now. If some code
2723 * below needs to rely on it before the end of the global
2724 * header loop, we need to correct it with this code :
2725 * ptr = del_colon;
2726 */
2727 }
2728 else
2729 delete_header = 1;
2730 }
2731 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002732
2733 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002734 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002735 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002736 }
willy tarreau240afa62005-12-17 13:14:35 +01002737 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2738
willy tarreau5cbea6f2005-12-17 12:48:26 +01002739 req->h = req->lr;
2740 } /* while (req->lr < req->r) */
2741
2742 /* end of header processing (even if incomplete) */
2743
willy tarreauef900ab2005-12-17 12:52:52 +01002744 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2745 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2746 * full. We cannot loop here since event_cli_read will disable it only if
2747 * req->l == rlim-data
2748 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002749 FD_SET(t->cli_fd, StaticReadEvent);
2750 if (t->proxy->clitimeout)
2751 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2752 else
2753 tv_eternity(&t->crexpire);
2754 }
2755
willy tarreaue39cd132005-12-17 13:00:18 +01002756 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002757 * won't be able to free more later, so the session will never terminate.
2758 */
willy tarreaue39cd132005-12-17 13:00:18 +01002759 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002760 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01002761 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01002762 if (!(t->flags & SN_ERR_MASK))
2763 t->flags |= SN_ERR_PRXCOND;
2764 if (!(t->flags & SN_FINST_MASK))
2765 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002766 return 1;
2767 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002768 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002769 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002770 tv_eternity(&t->crexpire);
2771 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002772 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002773 if (!(t->flags & SN_ERR_MASK))
2774 t->flags |= SN_ERR_CLICL;
2775 if (!(t->flags & SN_FINST_MASK))
2776 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002777 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002778 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002779 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2780
2781 /* read timeout : give up with an error message.
2782 */
2783 t->logs.status = 408;
2784 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01002785 if (!(t->flags & SN_ERR_MASK))
2786 t->flags |= SN_ERR_CLITO;
2787 if (!(t->flags & SN_FINST_MASK))
2788 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01002789 return 1;
2790 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002791
2792 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002793 }
2794 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01002795 process_data:
willy tarreau0f7af912005-12-17 12:21:26 +01002796 /* read or write error */
2797 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002798 tv_eternity(&t->crexpire);
2799 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002800 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002801 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002802 if (!(t->flags & SN_ERR_MASK))
2803 t->flags |= SN_ERR_CLICL;
2804 if (!(t->flags & SN_FINST_MASK))
2805 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002806 return 1;
2807 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002808 /* last read, or end of server write */
2809 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002810 FD_CLR(t->cli_fd, StaticReadEvent);
2811 // if (req->l == 0) /* nothing to write on the server side */
2812 // FD_CLR(t->srv_fd, StaticWriteEvent);
2813 tv_eternity(&t->crexpire);
2814 shutdown(t->cli_fd, SHUT_RD);
2815 t->cli_state = CL_STSHUTR;
2816 return 1;
2817 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002818 /* last server read and buffer empty */
2819 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002820 FD_CLR(t->cli_fd, StaticWriteEvent);
2821 tv_eternity(&t->cwexpire);
2822 shutdown(t->cli_fd, SHUT_WR);
2823 t->cli_state = CL_STSHUTW;
2824 return 1;
2825 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002826 /* read timeout */
2827 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2828 FD_CLR(t->cli_fd, StaticReadEvent);
2829 // if (req->l == 0) /* nothing to write on the server side */
2830 // FD_CLR(t->srv_fd, StaticWriteEvent);
2831 tv_eternity(&t->crexpire);
2832 shutdown(t->cli_fd, SHUT_RD);
2833 t->cli_state = CL_STSHUTR;
2834 if (!(t->flags & SN_ERR_MASK))
2835 t->flags |= SN_ERR_CLITO;
2836 if (!(t->flags & SN_FINST_MASK))
2837 t->flags |= SN_FINST_D;
2838 return 1;
2839 }
2840 /* write timeout */
2841 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2842 FD_CLR(t->cli_fd, StaticWriteEvent);
2843 tv_eternity(&t->cwexpire);
2844 shutdown(t->cli_fd, SHUT_WR);
2845 t->cli_state = CL_STSHUTW;
2846 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01002847 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01002848 if (!(t->flags & SN_FINST_MASK))
2849 t->flags |= SN_FINST_D;
2850 return 1;
2851 }
willy tarreau0f7af912005-12-17 12:21:26 +01002852
willy tarreauef900ab2005-12-17 12:52:52 +01002853 if (req->l >= req->rlim - req->data) {
2854 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002855 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002856 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002857 FD_CLR(t->cli_fd, StaticReadEvent);
2858 tv_eternity(&t->crexpire);
2859 }
2860 }
2861 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002862 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002863 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2864 FD_SET(t->cli_fd, StaticReadEvent);
2865 if (t->proxy->clitimeout)
2866 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2867 else
2868 tv_eternity(&t->crexpire);
2869 }
2870 }
2871
2872 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002873 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002874 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2875 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2876 tv_eternity(&t->cwexpire);
2877 }
2878 }
2879 else { /* buffer not empty */
2880 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2881 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002882 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002883 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002884 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2885 t->crexpire = t->cwexpire;
2886 }
willy tarreau0f7af912005-12-17 12:21:26 +01002887 else
2888 tv_eternity(&t->cwexpire);
2889 }
2890 }
2891 return 0; /* other cases change nothing */
2892 }
2893 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002894 if (t->res_cw == RES_ERROR) {
2895 tv_eternity(&t->cwexpire);
2896 fd_delete(t->cli_fd);
2897 t->cli_state = CL_STCLOSE;
2898 if (!(t->flags & SN_ERR_MASK))
2899 t->flags |= SN_ERR_CLICL;
2900 if (!(t->flags & SN_FINST_MASK))
2901 t->flags |= SN_FINST_D;
2902 return 1;
2903 }
2904 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002905 tv_eternity(&t->cwexpire);
2906 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002907 t->cli_state = CL_STCLOSE;
2908 return 1;
2909 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002910 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2911 tv_eternity(&t->cwexpire);
2912 fd_delete(t->cli_fd);
2913 t->cli_state = CL_STCLOSE;
2914 if (!(t->flags & SN_ERR_MASK))
2915 t->flags |= SN_ERR_CLITO;
2916 if (!(t->flags & SN_FINST_MASK))
2917 t->flags |= SN_FINST_D;
2918 return 1;
2919 }
willy tarreau0f7af912005-12-17 12:21:26 +01002920 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002921 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002922 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2923 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2924 tv_eternity(&t->cwexpire);
2925 }
2926 }
2927 else { /* buffer not empty */
2928 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2929 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002930 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002931 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002932 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2933 t->crexpire = t->cwexpire;
2934 }
willy tarreau0f7af912005-12-17 12:21:26 +01002935 else
2936 tv_eternity(&t->cwexpire);
2937 }
2938 }
2939 return 0;
2940 }
2941 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002942 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002943 tv_eternity(&t->crexpire);
2944 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002945 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002946 if (!(t->flags & SN_ERR_MASK))
2947 t->flags |= SN_ERR_CLICL;
2948 if (!(t->flags & SN_FINST_MASK))
2949 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002950 return 1;
2951 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002952 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
2953 tv_eternity(&t->crexpire);
2954 fd_delete(t->cli_fd);
2955 t->cli_state = CL_STCLOSE;
2956 return 1;
2957 }
2958 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2959 tv_eternity(&t->crexpire);
2960 fd_delete(t->cli_fd);
2961 t->cli_state = CL_STCLOSE;
2962 if (!(t->flags & SN_ERR_MASK))
2963 t->flags |= SN_ERR_CLITO;
2964 if (!(t->flags & SN_FINST_MASK))
2965 t->flags |= SN_FINST_D;
2966 return 1;
2967 }
willy tarreauef900ab2005-12-17 12:52:52 +01002968 else if (req->l >= req->rlim - req->data) {
2969 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002970 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002971 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002972 FD_CLR(t->cli_fd, StaticReadEvent);
2973 tv_eternity(&t->crexpire);
2974 }
2975 }
2976 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002977 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002978 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2979 FD_SET(t->cli_fd, StaticReadEvent);
2980 if (t->proxy->clitimeout)
2981 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2982 else
2983 tv_eternity(&t->crexpire);
2984 }
2985 }
2986 return 0;
2987 }
2988 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002989 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002990 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002991 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 +01002992 write(1, trash, len);
2993 }
2994 return 0;
2995 }
2996 return 0;
2997}
2998
2999
3000/*
3001 * manages the server FSM and its socket. It returns 1 if a state has changed
3002 * (and a resync may be needed), 0 else.
3003 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003004int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003005 int s = t->srv_state;
3006 int c = t->cli_state;
3007 struct buffer *req = t->req;
3008 struct buffer *rep = t->rep;
3009
willy tarreau750a4722005-12-17 13:21:24 +01003010#ifdef DEBUG_FULL
3011 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3012#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003013 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3014 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3015 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3016 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003017 if (s == SV_STIDLE) {
3018 if (c == CL_STHEADERS)
3019 return 0; /* stay in idle, waiting for data to reach the client side */
3020 else if (c == CL_STCLOSE ||
3021 c == CL_STSHUTW ||
3022 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3023 tv_eternity(&t->cnexpire);
3024 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003025 if (!(t->flags & SN_ERR_MASK))
3026 t->flags |= SN_ERR_CLICL;
3027 if (!(t->flags & SN_FINST_MASK))
3028 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003029 return 1;
3030 }
3031 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003032 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003033 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3034 t->srv_state = SV_STCONN;
3035 }
3036 else { /* try again */
3037 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003038 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003039 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003040 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003041 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3042 t->flags &= ~SN_CK_MASK;
3043 t->flags |= SN_CK_DOWN;
3044 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003045 }
3046
3047 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003048 t->srv_state = SV_STCONN;
3049 break;
3050 }
3051 }
3052 if (t->conn_retries < 0) {
3053 /* if conn_retries < 0 or other error, let's abort */
3054 tv_eternity(&t->cnexpire);
3055 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003056 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003057 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003058 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003059 if (!(t->flags & SN_ERR_MASK))
3060 t->flags |= SN_ERR_SRVCL;
3061 if (!(t->flags & SN_FINST_MASK))
3062 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003063 }
3064 }
3065 return 1;
3066 }
3067 }
3068 else if (s == SV_STCONN) { /* connection in progress */
3069 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3070 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3071 return 0; /* nothing changed */
3072 }
3073 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3074 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3075 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003076 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003077 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003078 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003079 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003080 if (t->conn_retries >= 0) {
3081 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003082 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003083 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003084 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3085 t->flags &= ~SN_CK_MASK;
3086 t->flags |= SN_CK_DOWN;
3087 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003088 }
3089 if (connect_server(t) == 0)
3090 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003091 }
3092 /* if conn_retries < 0 or other error, let's abort */
3093 tv_eternity(&t->cnexpire);
3094 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003095 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003096 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003097 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003098 if (!(t->flags & SN_ERR_MASK))
3099 t->flags |= SN_ERR_SRVCL;
3100 if (!(t->flags & SN_FINST_MASK))
3101 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003102 return 1;
3103 }
3104 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003105 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003106
willy tarreau0f7af912005-12-17 12:21:26 +01003107 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003108 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003109 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003110 tv_eternity(&t->swexpire);
3111 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003112 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003113 if (t->proxy->srvtimeout) {
3114 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3115 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3116 t->srexpire = t->swexpire;
3117 }
3118 else
3119 tv_eternity(&t->swexpire);
3120 }
willy tarreau0f7af912005-12-17 12:21:26 +01003121
3122 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3123 FD_SET(t->srv_fd, StaticReadEvent);
3124 if (t->proxy->srvtimeout)
3125 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3126 else
3127 tv_eternity(&t->srexpire);
3128
3129 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003130 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003131 }
willy tarreauef900ab2005-12-17 12:52:52 +01003132 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003133 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003134 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3135 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003136 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003137 return 1;
3138 }
3139 }
3140 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003141 /* now parse the partial (or complete) headers */
3142 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3143 char *ptr;
3144 int delete_header;
3145
3146 ptr = rep->lr;
3147
3148 /* look for the end of the current header */
3149 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3150 ptr++;
3151
3152 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003153 int line, len;
3154
3155 /* we can only get here after an end of headers */
3156 /* we'll have something else to do here : add new headers ... */
3157
willy tarreaucd878942005-12-17 13:27:43 +01003158 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3159 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003160 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003161 * insert a set-cookie here, except if we want to insert only on POST
3162 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003163 */
willy tarreau750a4722005-12-17 13:21:24 +01003164 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003165 t->proxy->cookie_name,
3166 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003167
willy tarreau036e1ce2005-12-17 13:46:33 +01003168 t->flags |= SN_SCK_INSERTED;
3169
willy tarreau750a4722005-12-17 13:21:24 +01003170 /* Here, we will tell an eventual cache on the client side that we don't
3171 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3172 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3173 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3174 */
willy tarreau240afa62005-12-17 13:14:35 +01003175 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003176 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3177 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003178
willy tarreau750a4722005-12-17 13:21:24 +01003179 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003180 }
3181
3182 /* headers to be added */
3183 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003184 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3185 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003186 }
3187
3188 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003189 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003190 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003191 break;
3192 }
3193
3194 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3195 if (ptr > rep->r - 2) {
3196 /* this is a partial header, let's wait for more to come */
3197 rep->lr = ptr;
3198 break;
3199 }
3200
3201 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3202 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3203
3204 /* now we know that *ptr is either \r or \n,
3205 * and that there are at least 1 char after it.
3206 */
3207 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3208 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3209 else
3210 rep->lr = ptr + 2; /* \r\n or \n\r */
3211
3212 /*
3213 * now we know that we have a full header ; we can do whatever
3214 * we want with these pointers :
3215 * rep->h = beginning of header
3216 * ptr = end of header (first \r or \n)
3217 * rep->lr = beginning of next line (next rep->h)
3218 * rep->r = end of data (not used at this stage)
3219 */
3220
willy tarreaua1598082005-12-17 13:08:06 +01003221
3222 if (t->logs.logwait & LW_RESP) {
3223 t->logs.logwait &= ~LW_RESP;
3224 t->logs.status = atoi(rep->h + 9);
3225 }
3226
willy tarreau5cbea6f2005-12-17 12:48:26 +01003227 delete_header = 0;
3228
willy tarreau9fe663a2005-12-17 13:02:59 +01003229 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003230 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003231 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 +01003232 max = ptr - rep->h;
3233 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003234 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003235 trash[len++] = '\n';
3236 write(1, trash, len);
3237 }
3238
3239 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01003240 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
3241 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003242 char term;
3243
3244 term = *ptr;
3245 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003246 exp = t->proxy->rsp_exp;
3247 do {
3248 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3249 switch (exp->action) {
3250 case ACT_ALLOW:
3251 if (!(t->flags & SN_SVDENY))
3252 t->flags |= SN_SVALLOW;
3253 break;
3254 case ACT_REPLACE:
3255 if (!(t->flags & SN_SVDENY)) {
3256 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3257 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3258 }
3259 break;
3260 case ACT_REMOVE:
3261 if (!(t->flags & SN_SVDENY))
3262 delete_header = 1;
3263 break;
3264 case ACT_DENY:
3265 if (!(t->flags & SN_SVALLOW))
3266 t->flags |= SN_SVDENY;
3267 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003268 case ACT_PASS: /* we simply don't deny this one */
3269 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003270 }
3271 break;
3272 }
willy tarreaue39cd132005-12-17 13:00:18 +01003273 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003274 *ptr = term; /* restore the string terminator */
3275 }
3276
3277 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003278 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3279 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
3280 && (ptr >= rep->h + 12)
willy tarreau906b2682005-12-17 13:49:52 +01003281 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003282 char *p1, *p2, *p3, *p4;
3283
3284 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3285
3286 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003287 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003288 p1++;
3289
3290 if (p1 == ptr || *p1 == ';') /* end of cookie */
3291 break;
3292
3293 /* p1 is at the beginning of the cookie name */
3294 p2 = p1;
3295
3296 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3297 p2++;
3298
3299 if (p2 == ptr || *p2 == ';') /* next cookie */
3300 break;
3301
3302 p3 = p2 + 1; /* skips the '=' sign */
3303 if (p3 == ptr)
3304 break;
3305
3306 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003307 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003308 p4++;
3309
3310 /* here, we have the cookie name between p1 and p2,
3311 * and its value between p3 and p4.
3312 * we can process it.
3313 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003314
3315 /* first, let's see if we want to capture it */
3316 if (t->proxy->capture_name != NULL &&
3317 t->logs.srv_cookie == NULL &&
3318 (p4 - p1 >= t->proxy->capture_namelen) &&
3319 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3320 int log_len = p4 - p1;
3321
3322 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3323 Alert("HTTP logging : out of memory.\n");
3324 }
3325
3326 if (log_len > t->proxy->capture_len)
3327 log_len = t->proxy->capture_len;
3328 memcpy(t->logs.srv_cookie, p1, log_len);
3329 t->logs.srv_cookie[log_len] = 0;
3330 }
3331
3332 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3333 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003334 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003335 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003336
3337 /* If the cookie is in insert mode on a known server, we'll delete
3338 * this occurrence because we'll insert another one later.
3339 * We'll delete it too if the "indirect" option is set and we're in
3340 * a direct access. */
3341 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003342 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003343 /* this header must be deleted */
3344 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003345 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003346 }
3347 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3348 /* replace bytes p3->p4 with the cookie name associated
3349 * with this server since we know it.
3350 */
3351 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003352 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003353 }
3354 break;
3355 }
3356 else {
3357 // fprintf(stderr,"Ignoring unknown cookie : ");
3358 // write(2, p1, p2-p1);
3359 // fprintf(stderr," = ");
3360 // write(2, p3, p4-p3);
3361 // fprintf(stderr,"\n");
3362 }
3363 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3364 } /* we're now at the end of the cookie value */
3365 } /* end of cookie processing */
3366
3367 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003368 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003369 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003370
willy tarreau5cbea6f2005-12-17 12:48:26 +01003371 rep->h = rep->lr;
3372 } /* while (rep->lr < rep->r) */
3373
3374 /* end of header processing (even if incomplete) */
3375
willy tarreauef900ab2005-12-17 12:52:52 +01003376 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3377 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3378 * full. We cannot loop here since event_srv_read will disable it only if
3379 * rep->l == rlim-data
3380 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003381 FD_SET(t->srv_fd, StaticReadEvent);
3382 if (t->proxy->srvtimeout)
3383 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3384 else
3385 tv_eternity(&t->srexpire);
3386 }
willy tarreau0f7af912005-12-17 12:21:26 +01003387
willy tarreau8337c6b2005-12-17 13:41:01 +01003388 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003389 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003390 tv_eternity(&t->srexpire);
3391 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003392 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003393 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003394 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003395 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003396 if (!(t->flags & SN_ERR_MASK))
3397 t->flags |= SN_ERR_SRVCL;
3398 if (!(t->flags & SN_FINST_MASK))
3399 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003400 return 1;
3401 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003402 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003403 * since we are in header mode, if there's no space left for headers, we
3404 * won't be able to free more later, so the session will never terminate.
3405 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003406 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 +01003407 FD_CLR(t->srv_fd, StaticReadEvent);
3408 tv_eternity(&t->srexpire);
3409 shutdown(t->srv_fd, SHUT_RD);
3410 t->srv_state = SV_STSHUTR;
3411 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003412 }
3413 /* read timeout : return a 504 to the client.
3414 */
3415 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3416 tv_eternity(&t->srexpire);
3417 tv_eternity(&t->swexpire);
3418 fd_delete(t->srv_fd);
3419 t->srv_state = SV_STCLOSE;
3420 t->logs.status = 504;
3421 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003422 if (!(t->flags & SN_ERR_MASK))
3423 t->flags |= SN_ERR_SRVTO;
3424 if (!(t->flags & SN_FINST_MASK))
3425 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003426 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003427
3428 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003429 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003430 /* FIXME!!! here, we don't want to switch to SHUTW if the
3431 * client shuts read too early, because we may still have
3432 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01003433 * The side-effect is that if the client completely closes its
3434 * connection during SV_STHEADER, the connection to the server
3435 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01003436 */
willy tarreau036e1ce2005-12-17 13:46:33 +01003437 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003438 FD_CLR(t->srv_fd, StaticWriteEvent);
3439 tv_eternity(&t->swexpire);
3440 shutdown(t->srv_fd, SHUT_WR);
3441 t->srv_state = SV_STSHUTW;
3442 return 1;
3443 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003444 /* write timeout */
3445 /* FIXME!!! here, we don't want to switch to SHUTW if the
3446 * client shuts read too early, because we may still have
3447 * some work to do on the headers.
3448 */
3449 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3450 FD_CLR(t->srv_fd, StaticWriteEvent);
3451 tv_eternity(&t->swexpire);
3452 shutdown(t->srv_fd, SHUT_WR);
3453 t->srv_state = SV_STSHUTW;
3454 if (!(t->flags & SN_ERR_MASK))
3455 t->flags |= SN_ERR_SRVTO;
3456 if (!(t->flags & SN_FINST_MASK))
3457 t->flags |= SN_FINST_H;
3458 return 1;
3459 }
willy tarreau0f7af912005-12-17 12:21:26 +01003460
3461 if (req->l == 0) {
3462 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3463 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3464 tv_eternity(&t->swexpire);
3465 }
3466 }
3467 else { /* client buffer not empty */
3468 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3469 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003470 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003471 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003472 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3473 t->srexpire = t->swexpire;
3474 }
willy tarreau0f7af912005-12-17 12:21:26 +01003475 else
3476 tv_eternity(&t->swexpire);
3477 }
3478 }
3479
willy tarreau5cbea6f2005-12-17 12:48:26 +01003480 /* be nice with the client side which would like to send a complete header
3481 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3482 * would read all remaining data at once ! The client should not write past rep->lr
3483 * when the server is in header state.
3484 */
3485 //return header_processed;
3486 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003487 }
3488 else if (s == SV_STDATA) {
3489 /* read or write error */
3490 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003491 tv_eternity(&t->srexpire);
3492 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003493 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003494 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003495 if (!(t->flags & SN_ERR_MASK))
3496 t->flags |= SN_ERR_SRVCL;
3497 if (!(t->flags & SN_FINST_MASK))
3498 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003499 return 1;
3500 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003501 /* last read, or end of client write */
3502 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003503 FD_CLR(t->srv_fd, StaticReadEvent);
3504 tv_eternity(&t->srexpire);
3505 shutdown(t->srv_fd, SHUT_RD);
3506 t->srv_state = SV_STSHUTR;
3507 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01003508 }
3509 /* end of client read and no more data to send */
3510 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
3511 FD_CLR(t->srv_fd, StaticWriteEvent);
3512 tv_eternity(&t->swexpire);
3513 shutdown(t->srv_fd, SHUT_WR);
3514 t->srv_state = SV_STSHUTW;
3515 return 1;
3516 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003517 /* read timeout */
3518 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3519 FD_CLR(t->srv_fd, StaticReadEvent);
3520 tv_eternity(&t->srexpire);
3521 shutdown(t->srv_fd, SHUT_RD);
3522 t->srv_state = SV_STSHUTR;
3523 if (!(t->flags & SN_ERR_MASK))
3524 t->flags |= SN_ERR_SRVTO;
3525 if (!(t->flags & SN_FINST_MASK))
3526 t->flags |= SN_FINST_D;
3527 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003528 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003529 /* write timeout */
3530 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003531 FD_CLR(t->srv_fd, StaticWriteEvent);
3532 tv_eternity(&t->swexpire);
3533 shutdown(t->srv_fd, SHUT_WR);
3534 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01003535 if (!(t->flags & SN_ERR_MASK))
3536 t->flags |= SN_ERR_SRVTO;
3537 if (!(t->flags & SN_FINST_MASK))
3538 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003539 return 1;
3540 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003541
3542 /* recompute request time-outs */
3543 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003544 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3545 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3546 tv_eternity(&t->swexpire);
3547 }
3548 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003549 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01003550 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3551 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003552 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003553 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003554 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3555 t->srexpire = t->swexpire;
3556 }
willy tarreau0f7af912005-12-17 12:21:26 +01003557 else
3558 tv_eternity(&t->swexpire);
3559 }
3560 }
3561
willy tarreaub1ff9db2005-12-17 13:51:03 +01003562 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01003563 if (rep->l == BUFSIZE) { /* no room to read more data */
3564 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3565 FD_CLR(t->srv_fd, StaticReadEvent);
3566 tv_eternity(&t->srexpire);
3567 }
3568 }
3569 else {
3570 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3571 FD_SET(t->srv_fd, StaticReadEvent);
3572 if (t->proxy->srvtimeout)
3573 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3574 else
3575 tv_eternity(&t->srexpire);
3576 }
3577 }
3578
3579 return 0; /* other cases change nothing */
3580 }
3581 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003582 if (t->res_sw == RES_ERROR) {
3583 //FD_CLR(t->srv_fd, StaticWriteEvent);
3584 tv_eternity(&t->swexpire);
3585 fd_delete(t->srv_fd);
3586 //close(t->srv_fd);
3587 t->srv_state = SV_STCLOSE;
3588 if (!(t->flags & SN_ERR_MASK))
3589 t->flags |= SN_ERR_SRVCL;
3590 if (!(t->flags & SN_FINST_MASK))
3591 t->flags |= SN_FINST_D;
3592 return 1;
3593 }
3594 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003595 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003596 tv_eternity(&t->swexpire);
3597 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003598 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003599 t->srv_state = SV_STCLOSE;
3600 return 1;
3601 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003602 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3603 //FD_CLR(t->srv_fd, StaticWriteEvent);
3604 tv_eternity(&t->swexpire);
3605 fd_delete(t->srv_fd);
3606 //close(t->srv_fd);
3607 t->srv_state = SV_STCLOSE;
3608 if (!(t->flags & SN_ERR_MASK))
3609 t->flags |= SN_ERR_SRVTO;
3610 if (!(t->flags & SN_FINST_MASK))
3611 t->flags |= SN_FINST_D;
3612 return 1;
3613 }
willy tarreau0f7af912005-12-17 12:21:26 +01003614 else if (req->l == 0) {
3615 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3616 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3617 tv_eternity(&t->swexpire);
3618 }
3619 }
3620 else { /* buffer not empty */
3621 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3622 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003623 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003624 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003625 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3626 t->srexpire = t->swexpire;
3627 }
willy tarreau0f7af912005-12-17 12:21:26 +01003628 else
3629 tv_eternity(&t->swexpire);
3630 }
3631 }
3632 return 0;
3633 }
3634 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003635 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003636 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003637 tv_eternity(&t->srexpire);
3638 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003639 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003640 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003641 if (!(t->flags & SN_ERR_MASK))
3642 t->flags |= SN_ERR_SRVCL;
3643 if (!(t->flags & SN_FINST_MASK))
3644 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003645 return 1;
3646 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003647 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
3648 //FD_CLR(t->srv_fd, StaticReadEvent);
3649 tv_eternity(&t->srexpire);
3650 fd_delete(t->srv_fd);
3651 //close(t->srv_fd);
3652 t->srv_state = SV_STCLOSE;
3653 return 1;
3654 }
3655 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3656 //FD_CLR(t->srv_fd, StaticReadEvent);
3657 tv_eternity(&t->srexpire);
3658 fd_delete(t->srv_fd);
3659 //close(t->srv_fd);
3660 t->srv_state = SV_STCLOSE;
3661 if (!(t->flags & SN_ERR_MASK))
3662 t->flags |= SN_ERR_SRVTO;
3663 if (!(t->flags & SN_FINST_MASK))
3664 t->flags |= SN_FINST_D;
3665 return 1;
3666 }
willy tarreau0f7af912005-12-17 12:21:26 +01003667 else if (rep->l == BUFSIZE) { /* no room to read more data */
3668 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3669 FD_CLR(t->srv_fd, StaticReadEvent);
3670 tv_eternity(&t->srexpire);
3671 }
3672 }
3673 else {
3674 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3675 FD_SET(t->srv_fd, StaticReadEvent);
3676 if (t->proxy->srvtimeout)
3677 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3678 else
3679 tv_eternity(&t->srexpire);
3680 }
3681 }
3682 return 0;
3683 }
3684 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003685 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003686 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003687 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 +01003688 write(1, trash, len);
3689 }
3690 return 0;
3691 }
3692 return 0;
3693}
3694
3695
willy tarreau5cbea6f2005-12-17 12:48:26 +01003696/* Processes the client and server jobs of a session task, then
3697 * puts it back to the wait queue in a clean state, or
3698 * cleans up its resources if it must be deleted. Returns
3699 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003700 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003701int process_session(struct task *t) {
3702 struct session *s = t->context;
3703 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003704
willy tarreau5cbea6f2005-12-17 12:48:26 +01003705 do {
3706 fsm_resync = 0;
3707 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3708 fsm_resync |= process_cli(s);
3709 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3710 fsm_resync |= process_srv(s);
3711 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3712 } while (fsm_resync);
3713
3714 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003715 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003716 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003717
willy tarreau5cbea6f2005-12-17 12:48:26 +01003718 tv_min(&min1, &s->crexpire, &s->cwexpire);
3719 tv_min(&min2, &s->srexpire, &s->swexpire);
3720 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003721 tv_min(&t->expire, &min1, &min2);
3722
3723 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003724 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003725
willy tarreau5cbea6f2005-12-17 12:48:26 +01003726 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003727 }
3728
willy tarreau5cbea6f2005-12-17 12:48:26 +01003729 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003730 actconn--;
3731
willy tarreau9fe663a2005-12-17 13:02:59 +01003732 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003733 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003734 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 +01003735 write(1, trash, len);
3736 }
3737
willy tarreau750a4722005-12-17 13:21:24 +01003738 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003739 if (s->rep != NULL)
3740 s->logs.bytes = s->rep->total;
3741
willy tarreau9fe663a2005-12-17 13:02:59 +01003742 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003743 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003744 sess_log(s);
3745
willy tarreau0f7af912005-12-17 12:21:26 +01003746 /* the task MUST not be in the run queue anymore */
3747 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003748 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003749 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003750 return -1; /* rest in peace for eternity */
3751}
3752
3753
3754
3755/*
3756 * manages a server health-check. Returns
3757 * the time the task accepts to wait, or -1 for infinity.
3758 */
3759int process_chk(struct task *t) {
3760 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01003761 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003762 int fd = s->curfd;
3763 int one = 1;
3764
willy tarreauef900ab2005-12-17 12:52:52 +01003765 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003766
3767 if (fd < 0) { /* no check currently running */
3768 //fprintf(stderr, "process_chk: 2\n");
3769 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3770 task_queue(t); /* restore t to its place in the task list */
3771 return tv_remain(&now, &t->expire);
3772 }
3773
3774 /* we'll initiate a new check */
3775 s->result = 0; /* no result yet */
3776 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003777 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003778 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3779 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3780 //fprintf(stderr, "process_chk: 3\n");
3781
willy tarreaua41a8b42005-12-17 14:02:24 +01003782 /* we'll connect to the check port on the server */
3783 sa = s->addr;
3784 sa.sin_port = htons(s->check_port);
3785
willy tarreau036e1ce2005-12-17 13:46:33 +01003786 /* allow specific binding */
3787 if (s->proxy->options & PR_O_BIND_SRC &&
3788 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
3789 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
3790 close(fd);
3791 s->result = -1;
3792 }
willy tarreaua41a8b42005-12-17 14:02:24 +01003793 else if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003794 /* OK, connection in progress or established */
3795
3796 //fprintf(stderr, "process_chk: 4\n");
3797
3798 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3799 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003800 fdtab[fd].read = &event_srv_chk_r;
3801 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003802 fdtab[fd].state = FD_STCONN; /* connection in progress */
3803 FD_SET(fd, StaticWriteEvent); /* for connect status */
3804 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003805 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3806 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003807 task_queue(t); /* restore t to its place in the task list */
3808 return tv_remain(&now, &t->expire);
3809 }
3810 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3811 s->result = -1; /* a real error */
3812 }
3813 }
3814 //fprintf(stderr, "process_chk: 5\n");
3815 close(fd);
3816 }
3817
3818 if (!s->result) { /* nothing done */
3819 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003820 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003821 task_queue(t); /* restore t to its place in the task list */
3822 return tv_remain(&now, &t->expire);
3823 }
3824
3825 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003826 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003827 s->health--; /* still good */
3828 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003829 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003830 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003831 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003832
willy tarreau9fe663a2005-12-17 13:02:59 +01003833 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003834 }
willy tarreauef900ab2005-12-17 12:52:52 +01003835
willy tarreau5cbea6f2005-12-17 12:48:26 +01003836 s->health = 0; /* failure */
3837 s->state &= ~SRV_RUNNING;
3838 }
3839
3840 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003841 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3842 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003843 }
3844 else {
3845 //fprintf(stderr, "process_chk: 8\n");
3846 /* there was a test running */
3847 if (s->result > 0) { /* good server detected */
3848 //fprintf(stderr, "process_chk: 9\n");
3849 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003850 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003851 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003852 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003853 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003854 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003855 }
willy tarreauef900ab2005-12-17 12:52:52 +01003856
willy tarreaue47c8d72005-12-17 12:55:52 +01003857 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003858 s->state |= SRV_RUNNING;
3859 }
willy tarreauef900ab2005-12-17 12:52:52 +01003860 s->curfd = -1; /* no check running anymore */
3861 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003862 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003863 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003864 }
3865 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3866 //fprintf(stderr, "process_chk: 10\n");
3867 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003868 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003869 s->health--; /* still good */
3870 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003871 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003872 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003873 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003874
3875 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003876 }
willy tarreauef900ab2005-12-17 12:52:52 +01003877
willy tarreau5cbea6f2005-12-17 12:48:26 +01003878 s->health = 0; /* failure */
3879 s->state &= ~SRV_RUNNING;
3880 }
3881 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003882 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003883 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003884 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003885 }
3886 /* if result is 0 and there's no timeout, we have to wait again */
3887 }
3888 //fprintf(stderr, "process_chk: 11\n");
3889 s->result = 0;
3890 task_queue(t); /* restore t to its place in the task list */
3891 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003892}
3893
3894
willy tarreau5cbea6f2005-12-17 12:48:26 +01003895
willy tarreau0f7af912005-12-17 12:21:26 +01003896#if STATTIME > 0
3897int stats(void);
3898#endif
3899
3900/*
3901 * Main select() loop.
3902 */
3903
3904void select_loop() {
3905 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003906 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003907 int status;
3908 int fd,i;
3909 struct timeval delta;
3910 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003911 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003912
willy tarreau5cbea6f2005-12-17 12:48:26 +01003913 tv_now(&now);
3914
3915 while (1) {
3916 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003917
willy tarreau5cbea6f2005-12-17 12:48:26 +01003918 /* look for expired tasks and add them to the run queue.
3919 */
3920 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3921 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3922 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003923 if (t->state & TASK_RUNNING)
3924 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003925
3926 /* wakeup expired entries. It doesn't matter if they are
3927 * already running because of a previous event
3928 */
3929 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003930 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003931 task_wakeup(&rq, t);
3932 }
3933 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003934 /* first non-runnable task. Use its expiration date as an upper bound */
3935 int temp_time = tv_remain(&now, &t->expire);
3936 if (temp_time)
3937 next_time = temp_time;
3938 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003939 break;
3940 }
3941 }
3942
3943 /* process each task in the run queue now. Each task may be deleted
3944 * since we only use tnext.
3945 */
3946 tnext = rq;
3947 while ((t = tnext) != NULL) {
3948 int temp_time;
3949
3950 tnext = t->rqnext;
3951 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003952 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003953 temp_time = t->process(t);
3954 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003955 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003956 }
3957
willy tarreauef900ab2005-12-17 12:52:52 +01003958 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003959
3960 /* maintain all proxies in a consistent state. This should quickly become a task */
3961 time2 = maintain_proxies();
3962 next_time = MINTIME(time2, next_time);
3963
3964 /* stop when there's no connection left and we don't allow them anymore */
3965 if (!actconn && listeners == 0)
3966 break;
3967
willy tarreau0f7af912005-12-17 12:21:26 +01003968
3969#if STATTIME > 0
3970 time2 = stats();
3971 // fprintf(stderr," stats = %d\n", time2);
3972 next_time = MINTIME(time2, next_time);
3973#endif
3974
willy tarreau5cbea6f2005-12-17 12:48:26 +01003975 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003976 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003977 /* to avoid eventual select loops due to timer precision */
3978 next_time += SCHEDULER_RESOLUTION;
3979 delta.tv_sec = next_time / 1000;
3980 delta.tv_usec = (next_time % 1000) * 1000;
3981 }
3982 else if (next_time == 0) { /* allow select to return immediately when needed */
3983 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003984 }
3985
3986
3987 /* let's restore fdset state */
3988
3989 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003990 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003991 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3992 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3993 }
3994
3995// /* just a verification code, needs to be removed for performance */
3996// for (i=0; i<maxfd; i++) {
3997// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3998// abort();
3999// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
4000// abort();
4001//
4002// }
4003
willy tarreau197e8ec2005-12-17 14:10:59 +01004004 status = select(maxfd,
4005 readnotnull ? ReadEvent : NULL,
4006 writenotnull ? WriteEvent : NULL,
4007 NULL,
4008 (next_time >= 0) ? &delta : NULL);
willy tarreau0f7af912005-12-17 12:21:26 +01004009
willy tarreau5cbea6f2005-12-17 12:48:26 +01004010 /* this is an experiment on the separation of the select work */
4011 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4012 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4013
willy tarreau0f7af912005-12-17 12:21:26 +01004014 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004015
willy tarreau0f7af912005-12-17 12:21:26 +01004016 if (status > 0) { /* must proceed with events */
4017
4018 int fds;
4019 char count;
4020
4021 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
4022 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
4023 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
4024
willy tarreau5cbea6f2005-12-17 12:48:26 +01004025 /* if we specify read first, the accepts and zero reads will be
4026 * seen first. Moreover, system buffers will be flushed faster.
4027 */
willy tarreau0f7af912005-12-17 12:21:26 +01004028 if (fdtab[fd].state == FD_STCLOSE)
4029 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01004030
4031 if (FD_ISSET(fd, ReadEvent))
4032 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004033
willy tarreau5cbea6f2005-12-17 12:48:26 +01004034 if (FD_ISSET(fd, WriteEvent))
4035 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004036 }
4037 }
4038 else {
4039 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
4040 }
willy tarreau0f7af912005-12-17 12:21:26 +01004041 }
4042}
4043
4044
4045#if STATTIME > 0
4046/*
4047 * Display proxy statistics regularly. It is designed to be called from the
4048 * select_loop().
4049 */
4050int stats(void) {
4051 static int lines;
4052 static struct timeval nextevt;
4053 static struct timeval lastevt;
4054 static struct timeval starttime = {0,0};
4055 unsigned long totaltime, deltatime;
4056 int ret;
4057
willy tarreau750a4722005-12-17 13:21:24 +01004058 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01004059 deltatime = (tv_diff(&lastevt, &now)?:1);
4060 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01004061
willy tarreau9fe663a2005-12-17 13:02:59 +01004062 if (global.mode & MODE_STATS) {
4063 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004064 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004065 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
4066 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004067 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004068 actconn, totalconn,
4069 stats_tsk_new, stats_tsk_good,
4070 stats_tsk_left, stats_tsk_right,
4071 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
4072 }
4073 }
4074
4075 tv_delayfrom(&nextevt, &now, STATTIME);
4076
4077 lastevt=now;
4078 }
4079 ret = tv_remain(&now, &nextevt);
4080 return ret;
4081}
4082#endif
4083
4084
4085/*
4086 * this function enables proxies when there are enough free sessions,
4087 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01004088 * select_loop(). It returns the time left before next expiration event
4089 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01004090 */
4091static int maintain_proxies(void) {
4092 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01004093 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004094 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01004095
4096 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004097 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01004098
4099 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01004100 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01004101 while (p) {
4102 if (p->nbconn < p->maxconn) {
4103 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004104 for (l = p->listen; l != NULL; l = l->next) {
4105 FD_SET(l->fd, StaticReadEvent);
4106 }
willy tarreau0f7af912005-12-17 12:21:26 +01004107 p->state = PR_STRUN;
4108 }
4109 }
4110 else {
4111 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004112 for (l = p->listen; l != NULL; l = l->next) {
4113 FD_CLR(l->fd, StaticReadEvent);
4114 }
willy tarreau0f7af912005-12-17 12:21:26 +01004115 p->state = PR_STIDLE;
4116 }
4117 }
4118 p = p->next;
4119 }
4120 }
4121 else { /* block all proxies */
4122 while (p) {
4123 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004124 for (l = p->listen; l != NULL; l = l->next) {
4125 FD_CLR(l->fd, StaticReadEvent);
4126 }
willy tarreau0f7af912005-12-17 12:21:26 +01004127 p->state = PR_STIDLE;
4128 }
4129 p = p->next;
4130 }
4131 }
4132
willy tarreau5cbea6f2005-12-17 12:48:26 +01004133 if (stopping) {
4134 p = proxy;
4135 while (p) {
4136 if (p->state != PR_STDISABLED) {
4137 int t;
4138 t = tv_remain(&now, &p->stop_time);
4139 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004140 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004141 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004142
willy tarreaua41a8b42005-12-17 14:02:24 +01004143 for (l = p->listen; l != NULL; l = l->next) {
4144 fd_delete(l->fd);
4145 listeners--;
4146 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004147 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004148 }
4149 else {
4150 tleft = MINTIME(t, tleft);
4151 }
4152 }
4153 p = p->next;
4154 }
4155 }
4156 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004157}
4158
4159/*
4160 * this function disables health-check servers so that the process will quickly be ignored
4161 * by load balancers.
4162 */
4163static void soft_stop(void) {
4164 struct proxy *p;
4165
4166 stopping = 1;
4167 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004168 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004169 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004170 if (p->state != PR_STDISABLED) {
4171 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004172 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004173 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004174 }
willy tarreau0f7af912005-12-17 12:21:26 +01004175 p = p->next;
4176 }
4177}
4178
4179/*
4180 * upon SIGUSR1, let's have a soft stop.
4181 */
4182void sig_soft_stop(int sig) {
4183 soft_stop();
4184 signal(sig, SIG_IGN);
4185}
4186
4187
willy tarreau8337c6b2005-12-17 13:41:01 +01004188/*
4189 * this function dumps every server's state when the process receives SIGHUP.
4190 */
4191void sig_dump_state(int sig) {
4192 struct proxy *p = proxy;
4193
4194 Warning("SIGHUP received, dumping servers states.\n");
4195 while (p) {
4196 struct server *s = p->srv;
4197
4198 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4199 while (s) {
4200 if (s->state & SRV_RUNNING) {
4201 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4202 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4203 }
4204 else {
4205 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4206 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4207 }
4208 s = s->next;
4209 }
4210 p = p->next;
4211 }
4212 signal(sig, sig_dump_state);
4213}
4214
willy tarreau0f7af912005-12-17 12:21:26 +01004215void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004216 struct task *t, *tnext;
4217 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004218
willy tarreau5cbea6f2005-12-17 12:48:26 +01004219 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4220 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4221 tnext = t->next;
4222 s = t->context;
4223 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4224 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4225 "req=%d, rep=%d, clifd=%d\n",
4226 s, tv_remain(&now, &t->expire),
4227 s->cli_state,
4228 s->srv_state,
4229 FD_ISSET(s->cli_fd, StaticReadEvent),
4230 FD_ISSET(s->cli_fd, StaticWriteEvent),
4231 FD_ISSET(s->srv_fd, StaticReadEvent),
4232 FD_ISSET(s->srv_fd, StaticWriteEvent),
4233 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4234 );
willy tarreau0f7af912005-12-17 12:21:26 +01004235 }
4236}
4237
willy tarreaue39cd132005-12-17 13:00:18 +01004238void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4239 struct hdr_exp *exp;
4240
4241 while (*head != NULL)
4242 head = &(*head)->next;
4243
4244 exp = calloc(1, sizeof(struct hdr_exp));
4245
4246 exp->preg = preg;
4247 exp->replace = replace;
4248 exp->action = action;
4249 *head = exp;
4250}
4251
willy tarreau9fe663a2005-12-17 13:02:59 +01004252
willy tarreau0f7af912005-12-17 12:21:26 +01004253/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004254 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004255 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004256int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004257
willy tarreau9fe663a2005-12-17 13:02:59 +01004258 if (!strcmp(args[0], "global")) { /* new section */
4259 /* no option, nothing special to do */
4260 return 0;
4261 }
4262 else if (!strcmp(args[0], "daemon")) {
4263 global.mode |= MODE_DAEMON;
4264 }
4265 else if (!strcmp(args[0], "debug")) {
4266 global.mode |= MODE_DEBUG;
4267 }
4268 else if (!strcmp(args[0], "quiet")) {
4269 global.mode |= MODE_QUIET;
4270 }
4271 else if (!strcmp(args[0], "stats")) {
4272 global.mode |= MODE_STATS;
4273 }
4274 else if (!strcmp(args[0], "uid")) {
4275 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004276 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004277 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004278 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004279 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004280 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004281 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004282 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004283 global.uid = atol(args[1]);
4284 }
4285 else if (!strcmp(args[0], "gid")) {
4286 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004287 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004288 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004289 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004290 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004291 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004292 return -1;
4293 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004294 global.gid = atol(args[1]);
4295 }
4296 else if (!strcmp(args[0], "nbproc")) {
4297 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004298 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004299 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004300 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004301 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004302 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004303 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004304 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004305 global.nbproc = atol(args[1]);
4306 }
4307 else if (!strcmp(args[0], "maxconn")) {
4308 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004309 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004310 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004311 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004312 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004313 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004314 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004315 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004316 global.maxconn = atol(args[1]);
4317 }
4318 else if (!strcmp(args[0], "chroot")) {
4319 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004320 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004321 return 0;
4322 }
4323 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004324 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004325 return -1;
4326 }
4327 global.chroot = strdup(args[1]);
4328 }
4329 else if (!strcmp(args[0], "log")) { /* syslog server address */
4330 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004331 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004332
4333 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004334 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004335 return -1;
4336 }
4337
4338 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4339 if (!strcmp(log_facilities[facility], args[2]))
4340 break;
4341
4342 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004343 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004344 exit(1);
4345 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004346
4347 level = 7; /* max syslog level = debug */
4348 if (*(args[3])) {
4349 while (level >= 0 && strcmp(log_levels[level], args[3]))
4350 level--;
4351 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004352 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004353 exit(1);
4354 }
4355 }
4356
willy tarreau9fe663a2005-12-17 13:02:59 +01004357 sa = str2sa(args[1]);
4358 if (!sa->sin_port)
4359 sa->sin_port = htons(SYSLOG_PORT);
4360
4361 if (global.logfac1 == -1) {
4362 global.logsrv1 = *sa;
4363 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004364 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004365 }
4366 else if (global.logfac2 == -1) {
4367 global.logsrv2 = *sa;
4368 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004369 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004370 }
4371 else {
4372 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4373 return -1;
4374 }
4375
4376 }
4377 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004378 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004379 return -1;
4380 }
4381 return 0;
4382}
4383
4384
willy tarreaua41a8b42005-12-17 14:02:24 +01004385void init_default_instance() {
4386 memset(&defproxy, 0, sizeof(defproxy));
4387 defproxy.mode = PR_MODE_TCP;
4388 defproxy.state = PR_STNEW;
4389 defproxy.maxconn = cfg_maxpconn;
4390 defproxy.conn_retries = CONN_RETRIES;
4391 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
4392}
4393
willy tarreau9fe663a2005-12-17 13:02:59 +01004394/*
4395 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4396 */
4397int cfg_parse_listen(char *file, int linenum, char **args) {
4398 static struct proxy *curproxy = NULL;
4399 struct server *newsrv = NULL;
4400
4401 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01004402 if (!*args[1]) {
4403 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
4404 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004405 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004406 return -1;
4407 }
4408
4409 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004410 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004411 return -1;
4412 }
4413 curproxy->next = proxy;
4414 proxy = curproxy;
4415 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01004416 if (strchr(args[2], ':') != NULL)
4417 curproxy->listen = str2listener(args[2], curproxy->listen);
4418
willy tarreau9fe663a2005-12-17 13:02:59 +01004419 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01004420 curproxy->state = defproxy.state;
4421 curproxy->maxconn = defproxy.maxconn;
4422 curproxy->conn_retries = defproxy.conn_retries;
4423 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004424
4425 if (defproxy.check_req)
4426 curproxy->check_req = strdup(defproxy.check_req);
4427 curproxy->check_len = defproxy.check_len;
4428
4429 if (defproxy.cookie_name)
4430 curproxy->cookie_name = strdup(defproxy.cookie_name);
4431 curproxy->cookie_len = defproxy.cookie_len;
4432
4433 if (defproxy.capture_name)
4434 curproxy->capture_name = strdup(defproxy.capture_name);
4435 curproxy->capture_namelen = defproxy.capture_namelen;
4436 curproxy->capture_len = defproxy.capture_len;
4437
4438 if (defproxy.errmsg.msg400)
4439 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
4440 curproxy->errmsg.len400 = defproxy.errmsg.len400;
4441
4442 if (defproxy.errmsg.msg403)
4443 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
4444 curproxy->errmsg.len403 = defproxy.errmsg.len403;
4445
4446 if (defproxy.errmsg.msg408)
4447 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
4448 curproxy->errmsg.len408 = defproxy.errmsg.len408;
4449
4450 if (defproxy.errmsg.msg500)
4451 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
4452 curproxy->errmsg.len500 = defproxy.errmsg.len500;
4453
4454 if (defproxy.errmsg.msg502)
4455 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
4456 curproxy->errmsg.len502 = defproxy.errmsg.len502;
4457
4458 if (defproxy.errmsg.msg503)
4459 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
4460 curproxy->errmsg.len503 = defproxy.errmsg.len503;
4461
4462 if (defproxy.errmsg.msg504)
4463 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
4464 curproxy->errmsg.len504 = defproxy.errmsg.len504;
4465
willy tarreaua41a8b42005-12-17 14:02:24 +01004466 curproxy->clitimeout = defproxy.clitimeout;
4467 curproxy->contimeout = defproxy.contimeout;
4468 curproxy->srvtimeout = defproxy.srvtimeout;
4469 curproxy->mode = defproxy.mode;
4470 curproxy->logfac1 = defproxy.logfac1;
4471 curproxy->logsrv1 = defproxy.logsrv1;
4472 curproxy->loglev1 = defproxy.loglev1;
4473 curproxy->logfac2 = defproxy.logfac2;
4474 curproxy->logsrv2 = defproxy.logsrv2;
4475 curproxy->loglev2 = defproxy.loglev2;
4476 curproxy->to_log = defproxy.to_log;
4477 curproxy->grace = defproxy.grace;
4478 curproxy->source_addr = defproxy.source_addr;
4479 return 0;
4480 }
4481 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004482 /* some variables may have already been initialized earlier */
4483 if (defproxy.check_req) free(defproxy.check_req);
4484 if (defproxy.cookie_name) free(defproxy.cookie_name);
4485 if (defproxy.capture_name) free(defproxy.capture_name);
4486 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
4487 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
4488 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
4489 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
4490 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
4491 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
4492 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
4493
4494 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01004495 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01004496 return 0;
4497 }
4498 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004499 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004500 return -1;
4501 }
4502
willy tarreaua41a8b42005-12-17 14:02:24 +01004503 if (!strcmp(args[0], "bind")) { /* new listen addresses */
4504 if (curproxy == &defproxy) {
4505 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4506 return -1;
4507 }
4508
4509 if (strchr(args[1], ':') == NULL) {
4510 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
4511 file, linenum, args[0]);
4512 return -1;
4513 }
4514 curproxy->listen = str2listener(args[1], curproxy->listen);
4515 return 0;
4516 }
4517 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01004518 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
4519 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
4520 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
4521 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004522 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004523 return -1;
4524 }
4525 }
4526 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
4527 curproxy->state = PR_STDISABLED;
4528 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004529 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
4530 curproxy->state = PR_STNEW;
4531 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004532 else if (!strcmp(args[0], "cookie")) { /* cookie name */
4533 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004534// if (curproxy == &defproxy) {
4535// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4536// return -1;
4537// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004538
willy tarreau9fe663a2005-12-17 13:02:59 +01004539 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004540// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
4541// file, linenum);
4542// return 0;
4543 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004544 }
4545
4546 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004547 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
4548 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004549 return -1;
4550 }
4551 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004552 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004553
4554 cur_arg = 2;
4555 while (*(args[cur_arg])) {
4556 if (!strcmp(args[cur_arg], "rewrite")) {
4557 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01004558 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004559 else if (!strcmp(args[cur_arg], "indirect")) {
4560 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01004561 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004562 else if (!strcmp(args[cur_arg], "insert")) {
4563 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01004564 }
willy tarreau240afa62005-12-17 13:14:35 +01004565 else if (!strcmp(args[cur_arg], "nocache")) {
4566 curproxy->options |= PR_O_COOK_NOC;
4567 }
willy tarreaucd878942005-12-17 13:27:43 +01004568 else if (!strcmp(args[cur_arg], "postonly")) {
4569 curproxy->options |= PR_O_COOK_POST;
4570 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004571 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004572 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
4573 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004574 return -1;
4575 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004576 cur_arg++;
4577 }
4578 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 +01004579 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004580 file, linenum);
4581 return -1;
4582 }
4583 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004584 else if (!strcmp(args[0], "capture")) { /* name of a cookie to capture */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004585// if (curproxy == &defproxy) {
4586// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4587// return -1;
4588// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004589
willy tarreau8337c6b2005-12-17 13:41:01 +01004590 if (curproxy->capture_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004591// Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4592// file, linenum, args[0]);
4593// return 0;
4594 free(curproxy->capture_name);
willy tarreau8337c6b2005-12-17 13:41:01 +01004595 }
4596
4597 if (*(args[4]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004598 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
4599 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004600 return -1;
4601 }
4602 curproxy->capture_name = strdup(args[2]);
4603 curproxy->capture_namelen = strlen(curproxy->capture_name);
4604 curproxy->capture_len = atol(args[4]);
4605 if (curproxy->capture_len >= CAPTURE_LEN) {
4606 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
4607 file, linenum, CAPTURE_LEN - 1);
4608 curproxy->capture_len = CAPTURE_LEN - 1;
4609 }
4610 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004611 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004612 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004613 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004614 return 0;
4615 }
4616 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004617 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4618 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004619 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004620 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004621 curproxy->contimeout = atol(args[1]);
4622 }
4623 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004624 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004625 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4626 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004627 return 0;
4628 }
4629 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004630 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4631 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004632 return -1;
4633 }
4634 curproxy->clitimeout = atol(args[1]);
4635 }
4636 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004637 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004638 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004639 return 0;
4640 }
4641 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004642 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4643 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004644 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004645 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004646 curproxy->srvtimeout = atol(args[1]);
4647 }
4648 else if (!strcmp(args[0], "retries")) { /* connection retries */
4649 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004650 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
4651 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004652 return -1;
4653 }
4654 curproxy->conn_retries = atol(args[1]);
4655 }
4656 else if (!strcmp(args[0], "option")) {
4657 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004658 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004659 return -1;
4660 }
4661 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004662 /* enable reconnections to dispatch */
4663 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004664#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004665 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004666 /* enable transparent proxy connections */
4667 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004668#endif
4669 else if (!strcmp(args[1], "keepalive"))
4670 /* enable keep-alive */
4671 curproxy->options |= PR_O_KEEPALIVE;
4672 else if (!strcmp(args[1], "forwardfor"))
4673 /* insert x-forwarded-for field */
4674 curproxy->options |= PR_O_FWDFOR;
4675 else if (!strcmp(args[1], "httplog")) {
4676 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01004677 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
4678 }
4679 else if (!strcmp(args[1], "dontlognull")) {
4680 /* don't log empty requests */
4681 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004682 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004683 else if (!strcmp(args[1], "httpchk")) {
4684 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004685 if (curproxy->check_req != NULL) {
4686 free(curproxy->check_req);
4687 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004688 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004689 if (!*args[2]) { /* no argument */
4690 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
4691 curproxy->check_len = strlen(DEF_CHECK_REQ);
4692 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01004693 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
4694 curproxy->check_req = (char *)malloc(reqlen);
4695 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4696 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004697 } else { /* more arguments : METHOD URI [HTTP_VER] */
4698 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
4699 if (*args[4])
4700 reqlen += strlen(args[4]);
4701 else
4702 reqlen += strlen("HTTP/1.0");
4703
4704 curproxy->check_req = (char *)malloc(reqlen);
4705 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4706 "%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 +01004707 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004708 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004709 else if (!strcmp(args[1], "persist")) {
4710 /* persist on using the server specified by the cookie, even when it's down */
4711 curproxy->options |= PR_O_PERSIST;
4712 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004713 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004714 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004715 return -1;
4716 }
4717 return 0;
4718 }
4719 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4720 /* enable reconnections to dispatch */
4721 curproxy->options |= PR_O_REDISP;
4722 }
willy tarreaua1598082005-12-17 13:08:06 +01004723#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004724 else if (!strcmp(args[0], "transparent")) {
4725 /* enable transparent proxy connections */
4726 curproxy->options |= PR_O_TRANSP;
4727 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004728#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004729 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4730 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004731 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004732 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004733 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004734 curproxy->maxconn = atol(args[1]);
4735 }
4736 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4737 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004738 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004739 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004740 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004741 curproxy->grace = atol(args[1]);
4742 }
4743 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01004744 if (curproxy == &defproxy) {
4745 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4746 return -1;
4747 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004748 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004749 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004750 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004751 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004752 curproxy->dispatch_addr = *str2sa(args[1]);
4753 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004754 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01004755 if (*(args[1])) {
4756 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004757 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004758 }
4759 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004760 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004761 return -1;
4762 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004763 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004764 else /* if no option is set, use round-robin by default */
4765 curproxy->options |= PR_O_BALANCE_RR;
4766 }
4767 else if (!strcmp(args[0], "server")) { /* server address */
4768 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004769 char *rport;
4770 char *raddr;
4771 short realport;
4772 int do_check;
4773
4774 if (curproxy == &defproxy) {
4775 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4776 return -1;
4777 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004778
willy tarreaua41a8b42005-12-17 14:02:24 +01004779 if (!*args[2]) {
4780 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004781 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004782 return -1;
4783 }
4784 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4785 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4786 return -1;
4787 }
4788 newsrv->next = curproxy->srv;
4789 curproxy->srv = newsrv;
4790 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01004791
4792 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004793 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01004794 newsrv->id = strdup(args[1]);
4795
4796 /* several ways to check the port component :
4797 * - IP => port=+0, relative
4798 * - IP: => port=+0, relative
4799 * - IP:N => port=N, absolute
4800 * - IP:+N => port=+N, relative
4801 * - IP:-N => port=-N, relative
4802 */
4803 raddr = strdup(args[2]);
4804 rport = strchr(raddr, ':');
4805 if (rport) {
4806 *rport++ = 0;
4807 realport = atol(rport);
4808 if (!isdigit((int)*rport))
4809 newsrv->state |= SRV_MAPPORTS;
4810 } else {
4811 realport = 0;
4812 newsrv->state |= SRV_MAPPORTS;
4813 }
4814
4815 newsrv->addr = *str2sa(raddr);
4816 newsrv->addr.sin_port = htons(realport);
4817 free(raddr);
4818
willy tarreau9fe663a2005-12-17 13:02:59 +01004819 newsrv->curfd = -1; /* no health-check in progress */
4820 newsrv->inter = DEF_CHKINTR;
4821 newsrv->rise = DEF_RISETIME;
4822 newsrv->fall = DEF_FALLTIME;
4823 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4824 cur_arg = 3;
4825 while (*args[cur_arg]) {
4826 if (!strcmp(args[cur_arg], "cookie")) {
4827 newsrv->cookie = strdup(args[cur_arg + 1]);
4828 newsrv->cklen = strlen(args[cur_arg + 1]);
4829 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004830 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004831 else if (!strcmp(args[cur_arg], "rise")) {
4832 newsrv->rise = atol(args[cur_arg + 1]);
4833 newsrv->health = newsrv->rise;
4834 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004835 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004836 else if (!strcmp(args[cur_arg], "fall")) {
4837 newsrv->fall = atol(args[cur_arg + 1]);
4838 cur_arg += 2;
4839 }
4840 else if (!strcmp(args[cur_arg], "inter")) {
4841 newsrv->inter = atol(args[cur_arg + 1]);
4842 cur_arg += 2;
4843 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004844 else if (!strcmp(args[cur_arg], "port")) {
4845 newsrv->check_port = atol(args[cur_arg + 1]);
4846 cur_arg += 2;
4847 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004848 else if (!strcmp(args[cur_arg], "backup")) {
4849 newsrv->state |= SRV_BACKUP;
4850 cur_arg ++;
4851 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004852 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004853 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004854 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004855 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004856 else {
willy tarreaua41a8b42005-12-17 14:02:24 +01004857 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
4858 file, linenum, newsrv->id);
4859 return -1;
4860 }
4861 }
4862
4863 if (do_check) {
4864 struct task *t;
4865
4866 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
4867 newsrv->check_port = realport; /* by default */
4868 if (!newsrv->check_port) {
4869 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 +01004870 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004871 return -1;
4872 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004873
4874 if ((t = pool_alloc(task)) == NULL) {
4875 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4876 return -1;
4877 }
4878
4879 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4880 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4881 t->state = TASK_IDLE;
4882 t->process = process_chk;
4883 t->context = newsrv;
4884
4885 if (curproxy->state != PR_STDISABLED) {
4886 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4887 task_queue(t);
4888 task_wakeup(&rq, t);
4889 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004890 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004891
willy tarreau9fe663a2005-12-17 13:02:59 +01004892 curproxy->nbservers++;
4893 }
4894 else if (!strcmp(args[0], "log")) { /* syslog server address */
4895 struct sockaddr_in *sa;
4896 int facility;
4897
4898 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4899 curproxy->logfac1 = global.logfac1;
4900 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004901 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004902 curproxy->logfac2 = global.logfac2;
4903 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01004904 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01004905 }
4906 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01004907 int level;
4908
willy tarreau0f7af912005-12-17 12:21:26 +01004909 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4910 if (!strcmp(log_facilities[facility], args[2]))
4911 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004912
willy tarreau0f7af912005-12-17 12:21:26 +01004913 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004914 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01004915 exit(1);
4916 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004917
willy tarreau8337c6b2005-12-17 13:41:01 +01004918 level = 7; /* max syslog level = debug */
4919 if (*(args[3])) {
4920 while (level >= 0 && strcmp(log_levels[level], args[3]))
4921 level--;
4922 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004923 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004924 exit(1);
4925 }
4926 }
4927
willy tarreau0f7af912005-12-17 12:21:26 +01004928 sa = str2sa(args[1]);
4929 if (!sa->sin_port)
4930 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004931
willy tarreau0f7af912005-12-17 12:21:26 +01004932 if (curproxy->logfac1 == -1) {
4933 curproxy->logsrv1 = *sa;
4934 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004935 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004936 }
4937 else if (curproxy->logfac2 == -1) {
4938 curproxy->logsrv2 = *sa;
4939 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004940 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004941 }
4942 else {
4943 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004944 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004945 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004946 }
4947 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004948 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004949 file, linenum);
4950 return -1;
4951 }
4952 }
willy tarreaua1598082005-12-17 13:08:06 +01004953 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01004954 if (!*args[1]) {
4955 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004956 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01004957 return -1;
4958 }
4959
4960 curproxy->source_addr = *str2sa(args[1]);
4961 curproxy->options |= PR_O_BIND_SRC;
4962 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004963 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4964 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004965 if (curproxy == &defproxy) {
4966 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4967 return -1;
4968 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004969
4970 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004971 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4972 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004973 return -1;
4974 }
4975
4976 preg = calloc(1, sizeof(regex_t));
4977 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004978 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004979 return -1;
4980 }
4981
4982 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4983 }
4984 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4985 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004986 if (curproxy == &defproxy) {
4987 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4988 return -1;
4989 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004990
4991 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004992 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004993 return -1;
4994 }
4995
4996 preg = calloc(1, sizeof(regex_t));
4997 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004998 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004999 return -1;
5000 }
5001
5002 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5003 }
5004 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
5005 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005006 if (curproxy == &defproxy) {
5007 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5008 return -1;
5009 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005010
5011 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005012 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005013 return -1;
5014 }
5015
5016 preg = calloc(1, sizeof(regex_t));
5017 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005018 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005019 return -1;
5020 }
5021
5022 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5023 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005024 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
5025 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005026 if (curproxy == &defproxy) {
5027 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5028 return -1;
5029 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005030
5031 if (*(args[1]) == 0) {
5032 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5033 return -1;
5034 }
5035
5036 preg = calloc(1, sizeof(regex_t));
5037 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5038 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5039 return -1;
5040 }
5041
5042 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5043 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005044 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
5045 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005046 if (curproxy == &defproxy) {
5047 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5048 return -1;
5049 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005050
5051 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005052 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005053 return -1;
5054 }
5055
5056 preg = calloc(1, sizeof(regex_t));
5057 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005058 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005059 return -1;
5060 }
5061
5062 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5063 }
5064 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
5065 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005066 if (curproxy == &defproxy) {
5067 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5068 return -1;
5069 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005070
5071 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005072 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5073 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005074 return -1;
5075 }
5076
5077 preg = calloc(1, sizeof(regex_t));
5078 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005079 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005080 return -1;
5081 }
5082
5083 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5084 }
5085 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
5086 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005087 if (curproxy == &defproxy) {
5088 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5089 return -1;
5090 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005091
5092 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005093 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005094 return -1;
5095 }
5096
5097 preg = calloc(1, sizeof(regex_t));
5098 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005099 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005100 return -1;
5101 }
5102
5103 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5104 }
5105 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
5106 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005107 if (curproxy == &defproxy) {
5108 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5109 return -1;
5110 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005111
5112 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005113 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005114 return -1;
5115 }
5116
5117 preg = calloc(1, sizeof(regex_t));
5118 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005119 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005120 return -1;
5121 }
5122
5123 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5124 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005125 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
5126 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005127 if (curproxy == &defproxy) {
5128 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5129 return -1;
5130 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005131
5132 if (*(args[1]) == 0) {
5133 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5134 return -1;
5135 }
5136
5137 preg = calloc(1, sizeof(regex_t));
5138 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5139 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5140 return -1;
5141 }
5142
5143 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5144 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005145 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
5146 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005147 if (curproxy == &defproxy) {
5148 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5149 return -1;
5150 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005151
5152 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005153 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005154 return -1;
5155 }
5156
5157 preg = calloc(1, sizeof(regex_t));
5158 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005159 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005160 return -1;
5161 }
5162
5163 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5164 }
5165 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005166 if (curproxy == &defproxy) {
5167 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5168 return -1;
5169 }
5170
willy tarreau9fe663a2005-12-17 13:02:59 +01005171 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005172 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005173 return 0;
5174 }
5175
5176 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005177 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005178 return -1;
5179 }
5180
5181 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005182 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005183 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01005184 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01005185
5186 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005187 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5188 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005189 return -1;
5190 }
5191
5192 preg = calloc(1, sizeof(regex_t));
5193 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005194 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005195 return -1;
5196 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005197
5198 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5199 }
5200 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
5201 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005202 if (curproxy == &defproxy) {
5203 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5204 return -1;
5205 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005206
5207 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005208 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005209 return -1;
5210 }
willy tarreaue39cd132005-12-17 13:00:18 +01005211
willy tarreau9fe663a2005-12-17 13:02:59 +01005212 preg = calloc(1, sizeof(regex_t));
5213 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005214 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005215 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005216 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005217
5218 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5219 }
5220 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01005221 regex_t *preg;
5222 if (curproxy == &defproxy) {
5223 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5224 return -1;
5225 }
willy tarreaue39cd132005-12-17 13:00:18 +01005226
willy tarreaua41a8b42005-12-17 14:02:24 +01005227 if (*(args[1]) == 0 || *(args[2]) == 0) {
5228 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5229 file, linenum, args[0]);
5230 return -1;
5231 }
willy tarreaue39cd132005-12-17 13:00:18 +01005232
willy tarreaua41a8b42005-12-17 14:02:24 +01005233 preg = calloc(1, sizeof(regex_t));
5234 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5235 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5236 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005237 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005238
5239 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5240 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005241 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
5242 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005243 if (curproxy == &defproxy) {
5244 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5245 return -1;
5246 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005247
5248 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005249 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005250 return -1;
5251 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005252
willy tarreau9fe663a2005-12-17 13:02:59 +01005253 preg = calloc(1, sizeof(regex_t));
5254 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005255 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005256 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005257 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005258
5259 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5260 }
5261 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005262 if (curproxy == &defproxy) {
5263 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5264 return -1;
5265 }
5266
willy tarreau9fe663a2005-12-17 13:02:59 +01005267 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005268 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005269 return 0;
5270 }
5271
5272 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005273 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005274 return -1;
5275 }
5276
5277 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
5278 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005279 else if (!strcmp(args[0], "errorloc")) { /* error location */
5280 int errnum;
5281 char *err;
5282
willy tarreaueedaa9f2005-12-17 14:08:03 +01005283 // if (curproxy == &defproxy) {
5284 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5285 // return -1;
5286 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005287
willy tarreau8337c6b2005-12-17 13:41:01 +01005288 if (*(args[2]) == 0) {
5289 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
5290 return -1;
5291 }
5292
5293 errnum = atol(args[1]);
5294 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
5295 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
5296
5297 if (errnum == 400) {
5298 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005299 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005300 free(curproxy->errmsg.msg400);
5301 }
5302 curproxy->errmsg.msg400 = err;
5303 curproxy->errmsg.len400 = strlen(err);
5304 }
5305 else if (errnum == 403) {
5306 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005307 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005308 free(curproxy->errmsg.msg403);
5309 }
5310 curproxy->errmsg.msg403 = err;
5311 curproxy->errmsg.len403 = strlen(err);
5312 }
5313 else if (errnum == 408) {
5314 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005315 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005316 free(curproxy->errmsg.msg408);
5317 }
5318 curproxy->errmsg.msg408 = err;
5319 curproxy->errmsg.len408 = strlen(err);
5320 }
5321 else if (errnum == 500) {
5322 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005323 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005324 free(curproxy->errmsg.msg500);
5325 }
5326 curproxy->errmsg.msg500 = err;
5327 curproxy->errmsg.len500 = strlen(err);
5328 }
5329 else if (errnum == 502) {
5330 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005331 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005332 free(curproxy->errmsg.msg502);
5333 }
5334 curproxy->errmsg.msg502 = err;
5335 curproxy->errmsg.len502 = strlen(err);
5336 }
5337 else if (errnum == 503) {
5338 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005339 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005340 free(curproxy->errmsg.msg503);
5341 }
5342 curproxy->errmsg.msg503 = err;
5343 curproxy->errmsg.len503 = strlen(err);
5344 }
5345 else if (errnum == 504) {
5346 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005347 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005348 free(curproxy->errmsg.msg504);
5349 }
5350 curproxy->errmsg.msg504 = err;
5351 curproxy->errmsg.len504 = strlen(err);
5352 }
5353 else {
5354 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
5355 free(err);
5356 }
5357 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005358 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005359 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01005360 return -1;
5361 }
5362 return 0;
5363}
willy tarreaue39cd132005-12-17 13:00:18 +01005364
willy tarreau5cbea6f2005-12-17 12:48:26 +01005365
willy tarreau9fe663a2005-12-17 13:02:59 +01005366/*
5367 * This function reads and parses the configuration file given in the argument.
5368 * returns 0 if OK, -1 if error.
5369 */
5370int readcfgfile(char *file) {
5371 char thisline[256];
5372 char *line;
5373 FILE *f;
5374 int linenum = 0;
5375 char *end;
5376 char *args[MAX_LINE_ARGS];
5377 int arg;
5378 int cfgerr = 0;
5379 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01005380
willy tarreau9fe663a2005-12-17 13:02:59 +01005381 struct proxy *curproxy = NULL;
5382 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005383
willy tarreau9fe663a2005-12-17 13:02:59 +01005384 if ((f=fopen(file,"r")) == NULL)
5385 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005386
willy tarreaueedaa9f2005-12-17 14:08:03 +01005387 init_default_instance();
5388
willy tarreau9fe663a2005-12-17 13:02:59 +01005389 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
5390 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005391
willy tarreau9fe663a2005-12-17 13:02:59 +01005392 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005393
willy tarreau9fe663a2005-12-17 13:02:59 +01005394 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01005395 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01005396 line++;
5397
5398 arg = 0;
5399 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01005400
willy tarreau9fe663a2005-12-17 13:02:59 +01005401 while (*line && arg < MAX_LINE_ARGS) {
5402 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
5403 * C equivalent value. Other combinations left unchanged (eg: \1).
5404 */
5405 if (*line == '\\') {
5406 int skip = 0;
5407 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
5408 *line = line[1];
5409 skip = 1;
5410 }
5411 else if (line[1] == 'r') {
5412 *line = '\r';
5413 skip = 1;
5414 }
5415 else if (line[1] == 'n') {
5416 *line = '\n';
5417 skip = 1;
5418 }
5419 else if (line[1] == 't') {
5420 *line = '\t';
5421 skip = 1;
5422 }
5423 else if (line[1] == 'x' && (line + 3 < end )) {
5424 unsigned char hex1, hex2;
5425 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
5426 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
5427 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
5428 *line = (hex1<<4) + hex2;
5429 skip = 3;
5430 }
5431 if (skip) {
5432 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
5433 end -= skip;
5434 }
5435 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005436 }
willy tarreaua1598082005-12-17 13:08:06 +01005437 else if (*line == '#' || *line == '\n' || *line == '\r') {
5438 /* end of string, end of loop */
5439 *line = 0;
5440 break;
5441 }
willy tarreauc29948c2005-12-17 13:10:27 +01005442 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005443 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01005444 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01005445 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01005446 line++;
5447 args[++arg] = line;
5448 }
5449 else {
5450 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005451 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005452 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005453
willy tarreau9fe663a2005-12-17 13:02:59 +01005454 /* empty line */
5455 if (!**args)
5456 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01005457
willy tarreau9fe663a2005-12-17 13:02:59 +01005458 /* zero out remaining args */
5459 while (++arg < MAX_LINE_ARGS) {
5460 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005461 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005462
willy tarreaua41a8b42005-12-17 14:02:24 +01005463 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01005464 confsect = CFG_LISTEN;
5465 else if (!strcmp(args[0], "global")) /* global config */
5466 confsect = CFG_GLOBAL;
5467 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005468
willy tarreau9fe663a2005-12-17 13:02:59 +01005469 switch (confsect) {
5470 case CFG_LISTEN:
5471 if (cfg_parse_listen(file, linenum, args) < 0)
5472 return -1;
5473 break;
5474 case CFG_GLOBAL:
5475 if (cfg_parse_global(file, linenum, args) < 0)
5476 return -1;
5477 break;
5478 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01005479 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005480 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005481 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005482
5483
willy tarreau0f7af912005-12-17 12:21:26 +01005484 }
5485 fclose(f);
5486
5487 /*
5488 * Now, check for the integrity of all that we have collected.
5489 */
5490
5491 if ((curproxy = proxy) == NULL) {
5492 Alert("parsing %s : no <listen> line. Nothing to do !\n",
5493 file);
5494 return -1;
5495 }
5496
5497 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01005498 if (curproxy->state == PR_STDISABLED) {
5499 curproxy = curproxy->next;
5500 continue;
5501 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005502 if ((curproxy->mode != PR_MODE_HEALTH) &&
5503 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01005504 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005505 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
5506 file, curproxy->id);
5507 cfgerr++;
5508 }
5509 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
5510 if (curproxy->options & PR_O_TRANSP) {
5511 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
5512 file, curproxy->id);
5513 cfgerr++;
5514 }
5515 else if (curproxy->srv == NULL) {
5516 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
5517 file, curproxy->id);
5518 cfgerr++;
5519 }
willy tarreaua1598082005-12-17 13:08:06 +01005520 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005521 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
5522 file, curproxy->id);
5523 }
5524 }
5525 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01005526 if (curproxy->cookie_name != NULL) {
5527 Warning("parsing %s : cookie will be ignored for listener %s.\n",
5528 file, curproxy->id);
5529 }
5530 if ((newsrv = curproxy->srv) != NULL) {
5531 Warning("parsing %s : servers will be ignored for listener %s.\n",
5532 file, curproxy->id);
5533 }
willy tarreaue39cd132005-12-17 13:00:18 +01005534 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005535 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
5536 file, curproxy->id);
5537 }
willy tarreaue39cd132005-12-17 13:00:18 +01005538 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005539 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
5540 file, curproxy->id);
5541 }
5542 }
5543 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
5544 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
5545 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
5546 file, curproxy->id);
5547 cfgerr++;
5548 }
5549 else {
5550 while (newsrv != NULL) {
5551 /* nothing to check for now */
5552 newsrv = newsrv->next;
5553 }
5554 }
5555 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005556 if (curproxy->errmsg.msg400 == NULL) {
5557 curproxy->errmsg.msg400 = (char *)HTTP_400;
5558 curproxy->errmsg.len400 = strlen(HTTP_400);
5559 }
5560 if (curproxy->errmsg.msg403 == NULL) {
5561 curproxy->errmsg.msg403 = (char *)HTTP_403;
5562 curproxy->errmsg.len403 = strlen(HTTP_403);
5563 }
5564 if (curproxy->errmsg.msg408 == NULL) {
5565 curproxy->errmsg.msg408 = (char *)HTTP_408;
5566 curproxy->errmsg.len408 = strlen(HTTP_408);
5567 }
5568 if (curproxy->errmsg.msg500 == NULL) {
5569 curproxy->errmsg.msg500 = (char *)HTTP_500;
5570 curproxy->errmsg.len500 = strlen(HTTP_500);
5571 }
5572 if (curproxy->errmsg.msg502 == NULL) {
5573 curproxy->errmsg.msg502 = (char *)HTTP_502;
5574 curproxy->errmsg.len502 = strlen(HTTP_502);
5575 }
5576 if (curproxy->errmsg.msg503 == NULL) {
5577 curproxy->errmsg.msg503 = (char *)HTTP_503;
5578 curproxy->errmsg.len503 = strlen(HTTP_503);
5579 }
5580 if (curproxy->errmsg.msg504 == NULL) {
5581 curproxy->errmsg.msg504 = (char *)HTTP_504;
5582 curproxy->errmsg.len504 = strlen(HTTP_504);
5583 }
willy tarreau0f7af912005-12-17 12:21:26 +01005584 curproxy = curproxy->next;
5585 }
5586 if (cfgerr > 0) {
5587 Alert("Errors found in configuration file, aborting.\n");
5588 return -1;
5589 }
5590 else
5591 return 0;
5592}
5593
5594
5595/*
5596 * This function initializes all the necessary variables. It only returns
5597 * if everything is OK. If something fails, it exits.
5598 */
5599void init(int argc, char **argv) {
5600 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01005601 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01005602 char *old_argv = *argv;
5603 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01005604 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01005605
5606 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005607 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005608 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
5609 sizeof(int)*8);
5610 exit(1);
5611 }
5612
5613 pid = getpid();
5614 progname = *argv;
5615 while ((tmp = strchr(progname, '/')) != NULL)
5616 progname = tmp + 1;
5617
5618 argc--; argv++;
5619 while (argc > 0) {
5620 char *flag;
5621
5622 if (**argv == '-') {
5623 flag = *argv+1;
5624
5625 /* 1 arg */
5626 if (*flag == 'v') {
5627 display_version();
5628 exit(0);
5629 }
5630 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01005631 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01005632 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01005633 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005634 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01005635 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01005636#if STATTIME > 0
5637 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01005638 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01005639 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01005640 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01005641#endif
5642 else { /* >=2 args */
5643 argv++; argc--;
5644 if (argc == 0)
5645 usage(old_argv);
5646
5647 switch (*flag) {
5648 case 'n' : cfg_maxconn = atol(*argv); break;
5649 case 'N' : cfg_maxpconn = atol(*argv); break;
5650 case 'f' : cfg_cfgfile = *argv; break;
5651 default: usage(old_argv);
5652 }
5653 }
5654 }
5655 else
5656 usage(old_argv);
5657 argv++; argc--;
5658 }
5659
willy tarreau0f7af912005-12-17 12:21:26 +01005660 if (!cfg_cfgfile)
5661 usage(old_argv);
5662
5663 gethostname(hostname, MAX_HOSTNAME_LEN);
5664
5665 if (readcfgfile(cfg_cfgfile) < 0) {
5666 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
5667 exit(1);
5668 }
5669
willy tarreau9fe663a2005-12-17 13:02:59 +01005670 if (cfg_maxconn > 0)
5671 global.maxconn = cfg_maxconn;
5672
5673 if (global.maxconn == 0)
5674 global.maxconn = DEFAULT_MAXCONN;
5675
5676 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
5677
5678 if (arg_mode & MODE_DEBUG) {
5679 /* command line debug mode inhibits configuration mode */
5680 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5681 }
willy tarreau750a4722005-12-17 13:21:24 +01005682 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01005683
5684 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
5685 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
5686 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5687 }
5688
5689 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
5690 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
5691 global.nbproc = 1;
5692 }
5693
5694 if (global.nbproc < 1)
5695 global.nbproc = 1;
5696
willy tarreau0f7af912005-12-17 12:21:26 +01005697 ReadEvent = (fd_set *)calloc(1,
5698 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005699 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005700 WriteEvent = (fd_set *)calloc(1,
5701 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005702 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005703 StaticReadEvent = (fd_set *)calloc(1,
5704 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005705 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005706 StaticWriteEvent = (fd_set *)calloc(1,
5707 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005708 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005709
5710 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01005711 sizeof(struct fdtab) * (global.maxsock));
5712 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01005713 fdtab[i].state = FD_STCLOSE;
5714 }
5715}
5716
5717/*
5718 * this function starts all the proxies. It returns 0 if OK, -1 if not.
5719 */
5720int start_proxies() {
5721 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01005722 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01005723 int one = 1;
5724 int fd;
5725
5726 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01005727 if (curproxy->state == PR_STDISABLED)
5728 continue;
5729
willy tarreaua41a8b42005-12-17 14:02:24 +01005730 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
5731 if ((fd = listener->fd =
5732 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
5733 Alert("cannot create listening socket for proxy %s. Aborting.\n",
5734 curproxy->id);
5735 return -1;
5736 }
willy tarreau0f7af912005-12-17 12:21:26 +01005737
willy tarreaua41a8b42005-12-17 14:02:24 +01005738 if (fd >= global.maxsock) {
5739 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
5740 curproxy->id);
5741 close(fd);
5742 return -1;
5743 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005744
willy tarreaua41a8b42005-12-17 14:02:24 +01005745 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
5746 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
5747 (char *) &one, sizeof(one)) == -1)) {
5748 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
5749 curproxy->id);
5750 close(fd);
5751 return -1;
5752 }
willy tarreau0f7af912005-12-17 12:21:26 +01005753
willy tarreaua41a8b42005-12-17 14:02:24 +01005754 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
5755 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
5756 curproxy->id);
5757 }
willy tarreau0f7af912005-12-17 12:21:26 +01005758
willy tarreaua41a8b42005-12-17 14:02:24 +01005759 if (bind(fd,
5760 (struct sockaddr *)&listener->addr,
5761 sizeof(listener->addr)) == -1) {
5762 Alert("cannot bind socket for proxy %s. Aborting.\n",
5763 curproxy->id);
5764 close(fd);
5765 return -1;
5766 }
willy tarreau0f7af912005-12-17 12:21:26 +01005767
willy tarreaua41a8b42005-12-17 14:02:24 +01005768 if (listen(fd, curproxy->maxconn) == -1) {
5769 Alert("cannot listen to socket for proxy %s. Aborting.\n",
5770 curproxy->id);
5771 close(fd);
5772 return -1;
5773 }
willy tarreau0f7af912005-12-17 12:21:26 +01005774
willy tarreaua41a8b42005-12-17 14:02:24 +01005775 /* the function for the accept() event */
5776 fdtab[fd].read = &event_accept;
5777 fdtab[fd].write = NULL; /* never called */
5778 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
5779 curproxy->state = PR_STRUN;
5780 fdtab[fd].state = FD_STLISTEN;
5781 FD_SET(fd, StaticReadEvent);
5782 fd_insert(fd);
5783 listeners++;
5784 }
willy tarreaua1598082005-12-17 13:08:06 +01005785 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005786 }
5787 return 0;
5788}
5789
5790
5791int main(int argc, char **argv) {
5792 init(argc, argv);
5793
willy tarreau9fe663a2005-12-17 13:02:59 +01005794 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01005795 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005796 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01005797 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01005798 }
5799
5800 signal(SIGQUIT, dump);
5801 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01005802 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005803
5804 /* on very high loads, a sigpipe sometimes happen just between the
5805 * getsockopt() which tells "it's OK to write", and the following write :-(
5806 */
willy tarreau3242e862005-12-17 12:27:53 +01005807#ifndef MSG_NOSIGNAL
5808 signal(SIGPIPE, SIG_IGN);
5809#endif
willy tarreau0f7af912005-12-17 12:21:26 +01005810
5811 if (start_proxies() < 0)
5812 exit(1);
5813
willy tarreau9fe663a2005-12-17 13:02:59 +01005814 /* open log files */
5815
5816 /* chroot if needed */
5817 if (global.chroot != NULL) {
5818 if (chroot(global.chroot) == -1) {
5819 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
5820 exit(1);
5821 }
5822 chdir("/");
5823 }
5824
5825 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01005826 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005827 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
5828 exit(1);
5829 }
5830
willy tarreau036e1ce2005-12-17 13:46:33 +01005831 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005832 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
5833 exit(1);
5834 }
5835
5836 if (global.mode & MODE_DAEMON) {
5837 int ret = 0;
5838 int proc;
5839
5840 /* the father launches the required number of processes */
5841 for (proc = 0; proc < global.nbproc; proc++) {
5842 ret = fork();
5843 if (ret < 0) {
5844 Alert("[%s.main()] Cannot fork.\n", argv[0]);
5845 exit(1); /* there has been an error */
5846 }
5847 else if (ret == 0) /* child breaks here */
5848 break;
5849 }
5850 if (proc == global.nbproc)
5851 exit(0); /* parent must leave */
5852
willy tarreau750a4722005-12-17 13:21:24 +01005853 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
5854 * that we can detach from the TTY. We MUST NOT do it in other cases since
5855 * it would have already be done, and 0-2 would have been affected to listening
5856 * sockets
5857 */
5858 if (!(global.mode & MODE_QUIET)) {
5859 /* detach from the tty */
5860 fclose(stdin); fclose(stdout); fclose(stderr);
5861 close(0); close(1); close(2); /* close all fd's */
5862 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
5863 }
willy tarreaua1598082005-12-17 13:08:06 +01005864 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01005865 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01005866 }
5867
willy tarreau0f7af912005-12-17 12:21:26 +01005868 select_loop();
5869
5870 exit(0);
5871}