blob: 42e9e87a0bd94ff33c6b69c6e8dff8f39de42281 [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 tarreau750a4722005-12-17 13:21:24 +010010 * Pending bugs (may be not fixed because not reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010011 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
12 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010013 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010014 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
15 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010016 * - a proxy with an invalid config will prevent the startup even if disabled.
17 *
willy tarreau036e1ce2005-12-17 13:46:33 +010018 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010019 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010020 * TODO:
21 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010022 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +010023 *
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <string.h>
30#include <ctype.h>
31#include <sys/time.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <netinet/tcp.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <netdb.h>
38#include <fcntl.h>
39#include <errno.h>
40#include <signal.h>
41#include <stdarg.h>
42#include <sys/resource.h>
43#include <time.h>
44#include <regex.h>
45#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010046#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010047#include <linux/netfilter_ipv4.h>
48#endif
willy tarreau0f7af912005-12-17 12:21:26 +010049
willy tarreau036e1ce2005-12-17 13:46:33 +010050#define HAPROXY_VERSION "1.1.18"
51#define HAPROXY_DATE "2003/04/02"
willy tarreau0f7af912005-12-17 12:21:26 +010052
53/* this is for libc5 for example */
54#ifndef TCP_NODELAY
55#define TCP_NODELAY 1
56#endif
57
58#ifndef SHUT_RD
59#define SHUT_RD 0
60#endif
61
62#ifndef SHUT_WR
63#define SHUT_WR 1
64#endif
65
willy tarreau535ae7a2005-12-17 12:58:00 +010066#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +010067
68// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +010069#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +010070#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +010071#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +010072
willy tarreau5cbea6f2005-12-17 12:48:26 +010073// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +010074#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +010075
willy tarreaue39cd132005-12-17 13:00:18 +010076// max # of added headers per request
77#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +010078
79// max # of matches per regexp
80#define MAX_MATCH 10
81
willy tarreau5cbea6f2005-12-17 12:48:26 +010082/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +010083#define COOKIENAME_LEN 16
84#define SERVERID_LEN 16
85#define CONN_RETRIES 3
86
willy tarreau5cbea6f2005-12-17 12:48:26 +010087#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +010088#define DEF_CHKINTR 2000
89#define DEF_FALLTIME 3
90#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +010091
willy tarreau9fe663a2005-12-17 13:02:59 +010092/* default connections limit */
93#define DEFAULT_MAXCONN 2000
94
willy tarreau0f7af912005-12-17 12:21:26 +010095/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
96#define INTBITS 5
97
98/* show stats this every millisecond, 0 to disable */
99#ifndef STATTIME
100#define STATTIME 2000
101#endif
102
willy tarreau5cbea6f2005-12-17 12:48:26 +0100103/* this reduces the number of calls to select() by choosing appropriate
104 * sheduler precision in milliseconds. It should be near the minimum
105 * time that is needed by select() to collect all events. All timeouts
106 * are rounded up by adding this value prior to pass it to select().
107 */
108#define SCHEDULER_RESOLUTION 9
109
willy tarreau0f7af912005-12-17 12:21:26 +0100110#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
111#define SETNOW(a) (*a=now)
112
willy tarreau9da061b2005-12-17 12:29:56 +0100113/****** string-specific macros and functions ******/
114/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
115#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
116
117/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
118#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
119
willy tarreau9da061b2005-12-17 12:29:56 +0100120/*
121 * copies at most <size-1> chars from <src> to <dst>. Last char is always
122 * set to 0, unless <size> is 0. The number of chars copied is returned
123 * (excluding the terminating zero).
124 * This code has been optimized for size and speed : on x86, it's 45 bytes
125 * long, uses only registers, and consumes only 4 cycles per char.
126 */
willy tarreau750a4722005-12-17 13:21:24 +0100127int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100128 char *orig = dst;
129 if (size) {
130 while (--size && (*dst = *src)) {
131 src++; dst++;
132 }
133 *dst = 0;
134 }
135 return dst - orig;
136}
willy tarreau9da061b2005-12-17 12:29:56 +0100137
willy tarreau0f7af912005-12-17 12:21:26 +0100138#define MEM_OPTIM
139#ifdef MEM_OPTIM
140/*
141 * Returns a pointer to type <type> taken from the
142 * pool <pool_type> or dynamically allocated. In the
143 * first case, <pool_type> is updated to point to the
144 * next element in the list.
145 */
146#define pool_alloc(type) ({ \
147 void *p; \
148 if ((p = pool_##type) == NULL) \
149 p = malloc(sizeof_##type); \
150 else { \
151 pool_##type = *(void **)pool_##type; \
152 } \
153 p; \
154})
155
156/*
157 * Puts a memory area back to the corresponding pool.
158 * Items are chained directly through a pointer that
159 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100160 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100161 * that each memory area is at least as big as one
162 * pointer.
163 */
164#define pool_free(type, ptr) ({ \
165 *(void **)ptr = (void *)pool_##type; \
166 pool_##type = (void *)ptr; \
167})
168
169#else
170#define pool_alloc(type) (calloc(1,sizeof_##type));
171#define pool_free(type, ptr) (free(ptr));
172#endif /* MEM_OPTIM */
173
willy tarreau5cbea6f2005-12-17 12:48:26 +0100174#define sizeof_task sizeof(struct task)
175#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100176#define sizeof_buffer sizeof(struct buffer)
177#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100178#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100179#define sizeof_capture CAPTURE_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100180
willy tarreau5cbea6f2005-12-17 12:48:26 +0100181/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100182#define FD_STCLOSE 0
183#define FD_STLISTEN 1
184#define FD_STCONN 2
185#define FD_STREADY 3
186#define FD_STERROR 4
187
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define TASK_IDLE 0
190#define TASK_RUNNING 1
191
willy tarreau5cbea6f2005-12-17 12:48:26 +0100192/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100193#define PR_STNEW 0
194#define PR_STIDLE 1
195#define PR_STRUN 2
196#define PR_STDISABLED 3
197
willy tarreau5cbea6f2005-12-17 12:48:26 +0100198/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100199#define PR_MODE_TCP 0
200#define PR_MODE_HTTP 1
201#define PR_MODE_HEALTH 2
202
willy tarreau5cbea6f2005-12-17 12:48:26 +0100203/* bits for proxy->options */
204#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
205#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
206#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
207#define PR_O_COOK_IND 8 /* keep only indirect cookies */
208#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
209#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
210#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
211#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100212#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
213#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100214#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
215#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100216#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100217#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100218#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
willy tarreau8337c6b2005-12-17 13:41:01 +0100219#define PR_O_PERSIST 8192 /* server persistence stays effective even when server is down */
willy tarreau9fe663a2005-12-17 13:02:59 +0100220
willy tarreau5cbea6f2005-12-17 12:48:26 +0100221
willy tarreaue39cd132005-12-17 13:00:18 +0100222/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100223#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
224#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
225#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
226#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
227#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
228#define SN_POST 0x00000020 /* the request was an HTTP POST */
229
230#define SN_CK_NONE 0x00000000 /* this session had no cookie */
231#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
232#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
233#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
234#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
235#define SN_CK_SHIFT 6 /* bit shift */
236
237#define SN_ERR_CLITO 0x00000100 /* client time-out */
238#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
239#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
240#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
241#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
242#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
243#define SN_ERR_SHIFT 8 /* bit shift */
244
245#define SN_FINST_R 0x00001000 /* session ended during client request */
246#define SN_FINST_C 0x00002000 /* session ended during server connect */
247#define SN_FINST_H 0x00003000 /* session ended during server headers */
248#define SN_FINST_D 0x00004000 /* session ended during data phase */
249#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
250#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
251#define SN_FINST_SHIFT 12 /* bit shift */
252
253#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
254#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
255#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
256#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
257#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
258#define SN_SCK_SHIFT 16 /* bit shift */
259
willy tarreau5cbea6f2005-12-17 12:48:26 +0100260
261/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100262#define CL_STHEADERS 0
263#define CL_STDATA 1
264#define CL_STSHUTR 2
265#define CL_STSHUTW 3
266#define CL_STCLOSE 4
267
willy tarreau5cbea6f2005-12-17 12:48:26 +0100268/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100269#define SV_STIDLE 0
270#define SV_STCONN 1
271#define SV_STHEADERS 2
272#define SV_STDATA 3
273#define SV_STSHUTR 4
274#define SV_STSHUTW 5
275#define SV_STCLOSE 6
276
277/* result of an I/O event */
278#define RES_SILENT 0 /* didn't happen */
279#define RES_DATA 1 /* data were sent or received */
280#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
281#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
282
willy tarreau9fe663a2005-12-17 13:02:59 +0100283/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100284#define MODE_DEBUG 1
285#define MODE_STATS 2
286#define MODE_LOG 4
287#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100288#define MODE_QUIET 16
289
290/* server flags */
291#define SRV_RUNNING 1
willy tarreau8337c6b2005-12-17 13:41:01 +0100292#define SRV_BACKUP 2
willy tarreau0f7af912005-12-17 12:21:26 +0100293
willy tarreaue39cd132005-12-17 13:00:18 +0100294/* what to do when a header matches a regex */
295#define ACT_ALLOW 0 /* allow the request */
296#define ACT_REPLACE 1 /* replace the matching header */
297#define ACT_REMOVE 2 /* remove the matching header */
298#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100299#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100300
willy tarreau9fe663a2005-12-17 13:02:59 +0100301/* configuration sections */
302#define CFG_NONE 0
303#define CFG_GLOBAL 1
304#define CFG_LISTEN 2
305
willy tarreaua1598082005-12-17 13:08:06 +0100306/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100307#define LW_DATE 1 /* date */
308#define LW_CLIP 2 /* CLient IP */
309#define LW_SVIP 4 /* SerVer IP */
310#define LW_SVID 8 /* server ID */
311#define LW_REQ 16 /* http REQuest */
312#define LW_RESP 32 /* http RESPonse */
313#define LW_PXIP 64 /* proxy IP */
314#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100315#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100316
willy tarreau0f7af912005-12-17 12:21:26 +0100317/*********************************************************************/
318
319#define LIST_HEAD(a) ((void *)(&(a)))
320
321/*********************************************************************/
322
323struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100324 struct hdr_exp *next;
325 regex_t *preg; /* expression to look for */
326 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
327 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100328};
329
330struct buffer {
331 unsigned int l; /* data length */
332 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100333 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100334 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100335 char data[BUFSIZE];
336};
337
338struct server {
339 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100340 int state; /* server state (SRV_*) */
341 int cklen; /* the len of the cookie, to speed up checks */
342 char *cookie; /* the id set in the cookie */
343 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100344 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100345 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100346 int rise, fall; /* time in iterations */
347 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100348 int result; /* 0 = connect OK, -1 = connect KO */
349 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100350 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100351};
352
willy tarreau5cbea6f2005-12-17 12:48:26 +0100353/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100354struct task {
355 struct task *next, *prev; /* chaining ... */
356 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100357 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100358 int state; /* task state : IDLE or RUNNING */
359 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100360 int (*process)(struct task *t); /* the function which processes the task */
361 void *context; /* the task's context */
362};
363
364/* WARNING: if new fields are added, they must be initialized in event_accept() */
365struct session {
366 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100367 /* application specific below */
368 struct timeval crexpire; /* expiration date for a client read */
369 struct timeval cwexpire; /* expiration date for a client write */
370 struct timeval srexpire; /* expiration date for a server read */
371 struct timeval swexpire; /* expiration date for a server write */
372 struct timeval cnexpire; /* expiration date for a connect */
373 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
374 struct proxy *proxy; /* the proxy this socket belongs to */
375 int cli_fd; /* the client side fd */
376 int srv_fd; /* the server side fd */
377 int cli_state; /* state of the client side */
378 int srv_state; /* state of the server side */
379 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100380 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100381 struct buffer *req; /* request buffer */
382 struct buffer *rep; /* response buffer */
383 struct sockaddr_in cli_addr; /* the client address */
384 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100385 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100386 struct {
387 int logwait; /* log fields waiting to be collected : LW_* */
388 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
389 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
390 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
391 long t_data; /* delay before the first data byte from the server ... */
392 unsigned long t_close; /* total session duration */
393 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100394 char *cli_cookie; /* cookie presented by the client, in capture mode */
395 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100396 int status; /* HTTP status from the server, negative if from proxy */
397 long long bytes; /* number of bytes transferred from the server */
398 } logs;
willy tarreau0f7af912005-12-17 12:21:26 +0100399};
400
401struct proxy {
402 int listen_fd; /* the listen socket */
403 int state; /* proxy state */
404 struct sockaddr_in listen_addr; /* the address we listen to */
405 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100406 struct server *srv, *cursrv; /* known servers, current server */
407 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100408 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100409 int cookie_len; /* strlen(cookie_len), computed only once */
410 char *capture_name; /* beginning of the name of the cookie to capture */
411 int capture_namelen; /* length of the cookie name to match */
412 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100413 int clitimeout; /* client I/O timeout (in milliseconds) */
414 int srvtimeout; /* server I/O timeout (in milliseconds) */
415 int contimeout; /* connect timeout (in milliseconds) */
416 char *id; /* proxy id */
417 int nbconn; /* # of active sessions */
418 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100419 int conn_retries; /* maximum number of connect retries */
420 int options; /* PR_O_REDISP, PR_O_TRANSP */
421 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100422 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100423 struct proxy *next;
424 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
425 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100426 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100427 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100428 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100429 int nb_reqadd, nb_rspadd;
430 struct hdr_exp *req_exp; /* regular expressions for request headers */
431 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
432 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100433 int grace; /* grace time after stop request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100434 struct {
435 char *msg400; /* message for error 400 */
436 int len400; /* message length for error 400 */
437 char *msg403; /* message for error 403 */
438 int len403; /* message length for error 403 */
439 char *msg408; /* message for error 408 */
440 int len408; /* message length for error 408 */
441 char *msg500; /* message for error 500 */
442 int len500; /* message length for error 500 */
443 char *msg502; /* message for error 502 */
444 int len502; /* message length for error 502 */
445 char *msg503; /* message for error 503 */
446 int len503; /* message length for error 503 */
447 char *msg504; /* message for error 504 */
448 int len504; /* message length for error 504 */
449 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100450};
451
452/* info about one given fd */
453struct fdtab {
454 int (*read)(int fd); /* read function */
455 int (*write)(int fd); /* write function */
456 struct task *owner; /* the session (or proxy) associated with this fd */
457 int state; /* the state of this fd */
458};
459
460/*********************************************************************/
461
willy tarreau0f7af912005-12-17 12:21:26 +0100462int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100463char *cfg_cfgfile = NULL; /* configuration file */
464char *progname = NULL; /* program name */
465int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100466
467/* global options */
468static struct {
469 int uid;
470 int gid;
471 int nbproc;
472 int maxconn;
473 int maxsock; /* max # of sockets */
474 int mode;
475 char *chroot;
476 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100477 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100478 struct sockaddr_in logsrv1, logsrv2;
479} global = {
480 logfac1 : -1,
481 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100482 loglev1 : 7, /* max syslog level : debug */
483 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100484 /* others NULL OK */
485};
486
willy tarreau0f7af912005-12-17 12:21:26 +0100487/*********************************************************************/
488
489fd_set *ReadEvent,
490 *WriteEvent,
491 *StaticReadEvent,
492 *StaticWriteEvent;
493
494void **pool_session = NULL,
495 **pool_buffer = NULL,
496 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100497 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100498 **pool_task = NULL,
499 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100500
501struct proxy *proxy = NULL; /* list of all existing proxies */
502struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100503struct task *rq = NULL; /* global run queue */
504struct task wait_queue = { /* global wait queue */
505 prev:LIST_HEAD(wait_queue),
506 next:LIST_HEAD(wait_queue)
507};
willy tarreau0f7af912005-12-17 12:21:26 +0100508
willy tarreau0f7af912005-12-17 12:21:26 +0100509static int totalconn = 0; /* total # of terminated sessions */
510static int actconn = 0; /* # of active sessions */
511static int maxfd = 0; /* # of the highest fd + 1 */
512static int listeners = 0; /* # of listeners */
513static int stopping = 0; /* non zero means stopping in progress */
514static struct timeval now = {0,0}; /* the current date at any moment */
515
516static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100517/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100518static char trash[BUFSIZE];
519
520/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100521 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100522 */
523
524#define MAX_SYSLOG_LEN 1024
525#define NB_LOG_FACILITIES 24
526const char *log_facilities[NB_LOG_FACILITIES] = {
527 "kern", "user", "mail", "daemon",
528 "auth", "syslog", "lpr", "news",
529 "uucp", "cron", "auth2", "ftp",
530 "ntp", "audit", "alert", "cron2",
531 "local0", "local1", "local2", "local3",
532 "local4", "local5", "local6", "local7"
533};
534
535
536#define NB_LOG_LEVELS 8
537const char *log_levels[NB_LOG_LEVELS] = {
538 "emerg", "alert", "crit", "err",
539 "warning", "notice", "info", "debug"
540};
541
542#define SYSLOG_PORT 514
543
544const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
545 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100546
547const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
548const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
549const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
550const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
551 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
552 unknown, Set-cookie Rewritten */
553
willy tarreau0f7af912005-12-17 12:21:26 +0100554#define MAX_HOSTNAME_LEN 32
555static char hostname[MAX_HOSTNAME_LEN] = "";
556
willy tarreau8337c6b2005-12-17 13:41:01 +0100557const char *HTTP_302 =
558 "HTTP/1.0 302 Found\r\n"
559 "Cache-Control: no-cache\r\n"
560 "Connection: close\r\n"
561 "Location: "; /* not terminated since it will be concatenated with the URL */
562
willy tarreaua1598082005-12-17 13:08:06 +0100563const char *HTTP_400 =
564 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100565 "Cache-Control: no-cache\r\n"
566 "Connection: close\r\n"
567 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100568 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100569
willy tarreaua1598082005-12-17 13:08:06 +0100570const char *HTTP_403 =
571 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100572 "Cache-Control: no-cache\r\n"
573 "Connection: close\r\n"
574 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100575 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
576
willy tarreau8337c6b2005-12-17 13:41:01 +0100577const char *HTTP_408 =
578 "HTTP/1.0 408 Request Time-out\r\n"
579 "Cache-Control: no-cache\r\n"
580 "Connection: close\r\n"
581 "\r\n"
582 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
583
willy tarreau750a4722005-12-17 13:21:24 +0100584const char *HTTP_500 =
585 "HTTP/1.0 500 Server Error\r\n"
586 "Cache-Control: no-cache\r\n"
587 "Connection: close\r\n"
588 "\r\n"
589 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100590
591const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100592 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100593 "Cache-Control: no-cache\r\n"
594 "Connection: close\r\n"
595 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100596 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
597
598const char *HTTP_503 =
599 "HTTP/1.0 503 Service Unavailable\r\n"
600 "Cache-Control: no-cache\r\n"
601 "Connection: close\r\n"
602 "\r\n"
603 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
604
605const char *HTTP_504 =
606 "HTTP/1.0 504 Gateway Time-out\r\n"
607 "Cache-Control: no-cache\r\n"
608 "Connection: close\r\n"
609 "\r\n"
610 "<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 +0100611
willy tarreau0f7af912005-12-17 12:21:26 +0100612/*********************************************************************/
613/* statistics ******************************************************/
614/*********************************************************************/
615
willy tarreau750a4722005-12-17 13:21:24 +0100616#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100617static int stats_tsk_lsrch, stats_tsk_rsrch,
618 stats_tsk_good, stats_tsk_right, stats_tsk_left,
619 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100620#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100621
622
623/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100624/* debugging *******************************************************/
625/*********************************************************************/
626#ifdef DEBUG_FULL
627static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
628static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
629#endif
630
631/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100632/* function prototypes *********************************************/
633/*********************************************************************/
634
635int event_accept(int fd);
636int event_cli_read(int fd);
637int event_cli_write(int fd);
638int event_srv_read(int fd);
639int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100640int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100641
642/*********************************************************************/
643/* general purpose functions ***************************************/
644/*********************************************************************/
645
646void display_version() {
647 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100648 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100649}
650
651/*
652 * This function prints the command line usage and exits
653 */
654void usage(char *name) {
655 display_version();
656 fprintf(stderr,
657 "Usage : %s -f <cfgfile> [ -vd"
658#if STATTIME > 0
659 "sl"
660#endif
661 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
662 " -v displays version\n"
663 " -d enters debug mode\n"
664#if STATTIME > 0
665 " -s enables statistics output\n"
666 " -l enables long statistics format\n"
667#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100668 " -D goes daemon ; implies -q\n"
669 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100670 " -n sets the maximum total # of connections (%d)\n"
671 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100672 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100673 exit(1);
674}
675
676
677/*
678 * Displays the message on stderr with the date and pid.
679 */
680void Alert(char *fmt, ...) {
681 va_list argp;
682 struct timeval tv;
683 struct tm *tm;
684
willy tarreau9fe663a2005-12-17 13:02:59 +0100685 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100686 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100687
willy tarreau5cbea6f2005-12-17 12:48:26 +0100688 gettimeofday(&tv, NULL);
689 tm=localtime(&tv.tv_sec);
690 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100691 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100692 vfprintf(stderr, fmt, argp);
693 fflush(stderr);
694 va_end(argp);
695 }
willy tarreau0f7af912005-12-17 12:21:26 +0100696}
697
698
699/*
700 * Displays the message on stderr with the date and pid.
701 */
702void Warning(char *fmt, ...) {
703 va_list argp;
704 struct timeval tv;
705 struct tm *tm;
706
willy tarreau9fe663a2005-12-17 13:02:59 +0100707 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100708 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100709
willy tarreau5cbea6f2005-12-17 12:48:26 +0100710 gettimeofday(&tv, NULL);
711 tm=localtime(&tv.tv_sec);
712 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100713 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100714 vfprintf(stderr, fmt, argp);
715 fflush(stderr);
716 va_end(argp);
717 }
718}
719
720/*
721 * Displays the message on <out> only if quiet mode is not set.
722 */
723void qfprintf(FILE *out, char *fmt, ...) {
724 va_list argp;
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);
728 vfprintf(out, fmt, argp);
729 fflush(out);
730 va_end(argp);
731 }
willy tarreau0f7af912005-12-17 12:21:26 +0100732}
733
734
735/*
736 * converts <str> to a struct sockaddr_in* which is locally allocated.
737 * The format is "addr:port", where "addr" can be empty or "*" to indicate
738 * INADDR_ANY.
739 */
740struct sockaddr_in *str2sa(char *str) {
741 static struct sockaddr_in sa;
742 char *c;
743 int port;
744
willy tarreaua1598082005-12-17 13:08:06 +0100745 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100746 str=strdup(str);
747
748 if ((c=strrchr(str,':')) != NULL) {
749 *c++=0;
750 port=atol(c);
751 }
752 else
753 port=0;
754
755 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
756 sa.sin_addr.s_addr = INADDR_ANY;
757 }
758 else if (
759#ifndef SOLARIS
760 !inet_aton(str, &sa.sin_addr)
761#else
762 !inet_pton(AF_INET, str, &sa.sin_addr)
763#endif
764 ) {
765 struct hostent *he;
766
767 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100768 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100769 }
770 else
771 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
772 }
773 sa.sin_port=htons(port);
774 sa.sin_family=AF_INET;
775
776 free(str);
777 return &sa;
778}
779
willy tarreau9fe663a2005-12-17 13:02:59 +0100780
781/*
782 * This function sends a syslog message to both log servers of a proxy,
783 * or to global log servers if the proxy is NULL.
784 * It also tries not to waste too much time computing the message header.
785 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100786 */
787void send_log(struct proxy *p, int level, char *message, ...) {
788 static int logfd = -1; /* syslog UDP socket */
789 static long tvsec = -1; /* to force the string to be initialized */
790 struct timeval tv;
791 va_list argp;
792 static char logmsg[MAX_SYSLOG_LEN];
793 static char *dataptr = NULL;
794 int fac_level;
795 int hdr_len, data_len;
796 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +0100797 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +0100798 int nbloggers = 0;
799 char *log_ptr;
800
801 if (logfd < 0) {
802 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
803 return;
804 }
805
806 if (level < 0 || progname == NULL || message == NULL)
807 return;
808
809 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100810 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100811 /* this string is rebuild only once a second */
812 struct tm *tm = localtime(&tv.tv_sec);
813 tvsec = tv.tv_sec;
814
willy tarreauc29948c2005-12-17 13:10:27 +0100815 hdr_len = snprintf(logmsg, sizeof(logmsg),
816 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
817 monthname[tm->tm_mon],
818 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
819 progname, pid);
820 /* WARNING: depending upon implementations, snprintf may return
821 * either -1 or the number of bytes that would be needed to store
822 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100823 */
willy tarreauc29948c2005-12-17 13:10:27 +0100824 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
825 hdr_len = sizeof(logmsg);
826
827 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100828 }
829
830 va_start(argp, message);
831 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100832 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
833 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100834 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100835 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100836
837 if (p == NULL) {
838 if (global.logfac1 >= 0) {
839 sa[nbloggers] = &global.logsrv1;
840 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100841 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100842 nbloggers++;
843 }
844 if (global.logfac2 >= 0) {
845 sa[nbloggers] = &global.logsrv2;
846 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100847 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100848 nbloggers++;
849 }
850 } else {
851 if (p->logfac1 >= 0) {
852 sa[nbloggers] = &p->logsrv1;
853 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100854 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100855 nbloggers++;
856 }
857 if (p->logfac2 >= 0) {
858 sa[nbloggers] = &p->logsrv2;
859 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100860 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100861 nbloggers++;
862 }
863 }
864
865 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +0100866 /* we can filter the level of the messages that are sent to each logger */
867 if (level > loglevel[nbloggers])
868 continue;
869
willy tarreauc29948c2005-12-17 13:10:27 +0100870 /* For each target, we may have a different facility.
871 * We can also have a different log level for each message.
872 * This induces variations in the message header length.
873 * Since we don't want to recompute it each time, nor copy it every
874 * time, we only change the facility in the pre-computed header,
875 * and we change the pointer to the header accordingly.
876 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100877 fac_level = (facilities[nbloggers] << 3) + level;
878 log_ptr = logmsg + 3; /* last digit of the log level */
879 do {
880 *log_ptr = '0' + fac_level % 10;
881 fac_level /= 10;
882 log_ptr--;
883 } while (fac_level && log_ptr > logmsg);
884 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100885
willy tarreauc29948c2005-12-17 13:10:27 +0100886 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100887
888#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100889 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100890 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
891#else
willy tarreauc29948c2005-12-17 13:10:27 +0100892 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100893 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
894#endif
895 }
willy tarreau0f7af912005-12-17 12:21:26 +0100896}
897
898
899/* sets <tv> to the current time */
900static inline struct timeval *tv_now(struct timeval *tv) {
901 if (tv)
902 gettimeofday(tv, NULL);
903 return tv;
904}
905
906/*
907 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
908 */
909static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
910 if (!tv || !from)
911 return NULL;
912 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
913 tv->tv_sec = from->tv_sec + (ms/1000);
914 while (tv->tv_usec >= 1000000) {
915 tv->tv_usec -= 1000000;
916 tv->tv_sec++;
917 }
918 return tv;
919}
920
921/*
922 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
923 */
924static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +0100925 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100926 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100927 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100928 return 1;
929 else if (tv1->tv_usec < tv2->tv_usec)
930 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100931 else if (tv1->tv_usec > tv2->tv_usec)
932 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +0100933 else
934 return 0;
935}
936
937/*
938 * returns the absolute difference, in ms, between tv1 and tv2
939 */
940unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
941 int cmp;
942 unsigned long ret;
943
944
willy tarreauef900ab2005-12-17 12:52:52 +0100945 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100946 if (!cmp)
947 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +0100948 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100949 struct timeval *tmp = tv1;
950 tv1 = tv2;
951 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100952 }
willy tarreauef900ab2005-12-17 12:52:52 +0100953 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100954 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100955 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100956 else
willy tarreauef900ab2005-12-17 12:52:52 +0100957 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100958 return (unsigned long) ret;
959}
960
961/*
willy tarreau750a4722005-12-17 13:21:24 +0100962 * returns the difference, in ms, between tv1 and tv2
963 */
964static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
965 unsigned long ret;
966
willy tarreau6e682ce2005-12-17 13:26:49 +0100967 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
968 if (tv2->tv_usec > tv1->tv_usec)
969 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100970 else
willy tarreau6e682ce2005-12-17 13:26:49 +0100971 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100972 return (unsigned long) ret;
973}
974
975/*
willy tarreau0f7af912005-12-17 12:21:26 +0100976 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
977 */
978static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100979 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +0100980 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100981 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100982 else if (tv1->tv_usec > tv2->tv_usec + 1000)
983 return 1;
willy tarreauefae1842005-12-17 12:51:03 +0100984 else
985 return 0;
986 }
willy tarreau0f7af912005-12-17 12:21:26 +0100987 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100988 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100989 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100990 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
991 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
992 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +0100993 else
994 return 0;
995}
996
997/*
998 * returns the remaining time between tv1=now and event=tv2
999 * if tv2 is passed, 0 is returned.
1000 */
1001static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1002 unsigned long ret;
1003
willy tarreau0f7af912005-12-17 12:21:26 +01001004 if (tv_cmp_ms(tv1, tv2) >= 0)
1005 return 0; /* event elapsed */
1006
willy tarreauef900ab2005-12-17 12:52:52 +01001007 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001008 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001009 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001010 else
willy tarreauef900ab2005-12-17 12:52:52 +01001011 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001012 return (unsigned long) ret;
1013}
1014
1015
1016/*
1017 * zeroes a struct timeval
1018 */
1019
1020static inline struct timeval *tv_eternity(struct timeval *tv) {
1021 tv->tv_sec = tv->tv_usec = 0;
1022 return tv;
1023}
1024
1025/*
1026 * returns 1 if tv is null, else 0
1027 */
1028static inline int tv_iseternity(struct timeval *tv) {
1029 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1030 return 1;
1031 else
1032 return 0;
1033}
1034
1035/*
1036 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1037 * considering that 0 is the eternity.
1038 */
1039static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1040 if (tv_iseternity(tv1))
1041 if (tv_iseternity(tv2))
1042 return 0; /* same */
1043 else
1044 return 1; /* tv1 later than tv2 */
1045 else if (tv_iseternity(tv2))
1046 return -1; /* tv2 later than tv1 */
1047
1048 if (tv1->tv_sec > tv2->tv_sec)
1049 return 1;
1050 else if (tv1->tv_sec < tv2->tv_sec)
1051 return -1;
1052 else if (tv1->tv_usec > tv2->tv_usec)
1053 return 1;
1054 else if (tv1->tv_usec < tv2->tv_usec)
1055 return -1;
1056 else
1057 return 0;
1058}
1059
1060/*
1061 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1062 * considering that 0 is the eternity.
1063 */
1064static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1065 if (tv_iseternity(tv1))
1066 if (tv_iseternity(tv2))
1067 return 0; /* same */
1068 else
1069 return 1; /* tv1 later than tv2 */
1070 else if (tv_iseternity(tv2))
1071 return -1; /* tv2 later than tv1 */
1072
willy tarreauefae1842005-12-17 12:51:03 +01001073 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001074 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001075 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001076 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001077 return -1;
1078 else
1079 return 0;
1080 }
1081 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001082 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001083 return 1;
1084 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001085 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001086 return -1;
1087 else
1088 return 0;
1089}
1090
1091/*
1092 * returns the first event between tv1 and tv2 into tvmin.
1093 * a zero tv is ignored. tvmin is returned.
1094 */
1095static inline struct timeval *tv_min(struct timeval *tvmin,
1096 struct timeval *tv1, struct timeval *tv2) {
1097
1098 if (tv_cmp2(tv1, tv2) <= 0)
1099 *tvmin = *tv1;
1100 else
1101 *tvmin = *tv2;
1102
1103 return tvmin;
1104}
1105
1106
1107
1108/***********************************************************/
1109/* fd management ***************************************/
1110/***********************************************************/
1111
1112
1113
willy tarreau5cbea6f2005-12-17 12:48:26 +01001114/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1115 * The file descriptor is also closed.
1116 */
willy tarreau0f7af912005-12-17 12:21:26 +01001117static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001118 FD_CLR(fd, StaticReadEvent);
1119 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001120 close(fd);
1121 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001122
1123 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1124 maxfd--;
1125}
1126
1127/* recomputes the maxfd limit from the fd */
1128static inline void fd_insert(int fd) {
1129 if (fd+1 > maxfd)
1130 maxfd = fd+1;
1131}
1132
1133/*************************************************************/
1134/* task management ***************************************/
1135/*************************************************************/
1136
willy tarreau5cbea6f2005-12-17 12:48:26 +01001137/* puts the task <t> in run queue <q>, and returns <t> */
1138static inline struct task *task_wakeup(struct task **q, struct task *t) {
1139 if (t->state == TASK_RUNNING)
1140 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001141 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001142 t->rqnext = *q;
1143 t->state = TASK_RUNNING;
1144 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001145 }
1146}
1147
willy tarreau5cbea6f2005-12-17 12:48:26 +01001148/* removes the task <t> from the queue <q>
1149 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001150 * set the run queue to point to the next one, and return it
1151 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001152static inline struct task *task_sleep(struct task **q, struct task *t) {
1153 if (t->state == TASK_RUNNING) {
1154 *q = t->rqnext;
1155 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001156 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001157 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001158}
1159
1160/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001161 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001162 * from the run queue. A pointer to the task itself is returned.
1163 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001164static inline struct task *task_delete(struct task *t) {
1165 t->prev->next = t->next;
1166 t->next->prev = t->prev;
1167 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001168}
1169
1170/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001171 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001172 */
1173static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001174 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001175}
1176
willy tarreau5cbea6f2005-12-17 12:48:26 +01001177/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001178 * may be only moved or left where it was, depending on its timing requirements.
1179 * <task> is returned.
1180 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001181struct task *task_queue(struct task *task) {
1182 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001183 struct task *start_from;
1184
1185 /* first, test if the task was already in a list */
1186 if (task->prev == NULL) {
1187 // start_from = list;
1188 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001189#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001190 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001191#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001192 /* insert the unlinked <task> into the list, searching back from the last entry */
1193 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1194 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001195#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001196 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001197#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001198 }
1199
1200 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1201 // start_from = start_from->next;
1202 // stats_tsk_nsrch++;
1203 // }
1204 }
1205 else if (task->prev == list ||
1206 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1207 start_from = task->next;
1208 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001209#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001210 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001211#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001212 return task; /* it's already in the right place */
1213 }
1214
willy tarreau750a4722005-12-17 13:21:24 +01001215#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001216 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001217#endif
1218
1219 /* if the task is not at the right place, there's little chance that
1220 * it has only shifted a bit, and it will nearly always be queued
1221 * at the end of the list because of constant timeouts
1222 * (observed in real case).
1223 */
1224#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1225 start_from = list->prev; /* assume we'll queue to the end of the list */
1226 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1227 start_from = start_from->prev;
1228#if STATTIME > 0
1229 stats_tsk_lsrch++;
1230#endif
1231 }
1232#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001233 /* insert the unlinked <task> into the list, searching after position <start_from> */
1234 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1235 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001236#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001237 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001238#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001239 }
willy tarreau750a4722005-12-17 13:21:24 +01001240#endif /* WE_REALLY_... */
1241
willy tarreau0f7af912005-12-17 12:21:26 +01001242 /* we need to unlink it now */
1243 task_delete(task);
1244 }
1245 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001246#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001247 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001248#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001249#ifdef LEFT_TO_TOP /* not very good */
1250 start_from = list;
1251 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1252 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001253#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001254 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001255#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001256 }
1257#else
1258 start_from = task->prev->prev; /* valid because of the previous test above */
1259 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1260 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001261#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001262 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001263#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001264 }
1265#endif
1266 /* we need to unlink it now */
1267 task_delete(task);
1268 }
1269 task->prev = start_from;
1270 task->next = start_from->next;
1271 task->next->prev = task;
1272 start_from->next = task;
1273 return task;
1274}
1275
1276
1277/*********************************************************************/
1278/* more specific functions ***************************************/
1279/*********************************************************************/
1280
1281/* some prototypes */
1282static int maintain_proxies(void);
1283
willy tarreau5cbea6f2005-12-17 12:48:26 +01001284/* this either returns the sockname or the original destination address. Code
1285 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1286 */
1287static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001288#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001289 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1290#else
willy tarreaua1598082005-12-17 13:08:06 +01001291#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001292 return getsockname(fd, (struct sockaddr *)sa, salen);
1293#else
1294 return -1;
1295#endif
1296#endif
1297}
1298
1299/*
1300 * frees the context associated to a session. It must have been removed first.
1301 */
1302static inline void session_free(struct session *s) {
1303 if (s->req)
1304 pool_free(buffer, s->req);
1305 if (s->rep)
1306 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001307 if (s->logs.uri)
1308 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001309 if (s->logs.cli_cookie)
1310 pool_free(capture, s->logs.cli_cookie);
1311 if (s->logs.srv_cookie)
1312 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001313
willy tarreau5cbea6f2005-12-17 12:48:26 +01001314 pool_free(session, s);
1315}
1316
willy tarreau0f7af912005-12-17 12:21:26 +01001317
1318/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001319 * This function tries to find a running server for the proxy <px>. A first
1320 * pass looks for active servers, and if none is found, a second pass also
1321 * looks for backup servers.
1322 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1323 */
1324static inline struct server *find_server(struct proxy *px) {
1325 struct server *srv = px->cursrv;
1326 int ignore_backup = 1;
1327
1328 do {
1329 do {
1330 if (srv == NULL)
1331 srv = px->srv;
1332 if (srv->state & SRV_RUNNING
1333 && !((srv->state & SRV_BACKUP) && ignore_backup))
1334 return srv;
1335 srv = srv->next;
1336 } while (srv != px->cursrv);
1337 } while (ignore_backup--);
1338 return NULL;
1339}
1340
1341/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001342 * This function initiates a connection to the current server (s->srv) if (s->direct)
1343 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001344 * it's OK, -1 if it's impossible.
1345 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001346int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001347 int one = 1;
1348 int fd;
1349
1350 // fprintf(stderr,"connect_server : s=%p\n",s);
1351
willy tarreaue39cd132005-12-17 13:00:18 +01001352 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001353 s->srv_addr = s->srv->addr;
1354 }
1355 else if (s->proxy->options & PR_O_BALANCE) {
1356 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001357 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001358
willy tarreau8337c6b2005-12-17 13:41:01 +01001359 srv = find_server(s->proxy);
1360
1361 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001362 return -1;
1363
willy tarreau8337c6b2005-12-17 13:41:01 +01001364 s->srv_addr = srv->addr;
1365 s->srv = srv;
1366 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001367 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001368 else /* unknown balancing algorithm */
1369 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001370 }
willy tarreaua1598082005-12-17 13:08:06 +01001371 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001372 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001373 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001374 }
1375 else if (s->proxy->options & PR_O_TRANSP) {
1376 /* in transparent mode, use the original dest addr if no dispatch specified */
1377 int salen = sizeof(struct sockaddr_in);
1378 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1379 qfprintf(stderr, "Cannot get original server address.\n");
1380 return -1;
1381 }
1382 }
willy tarreau0f7af912005-12-17 12:21:26 +01001383
1384 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001385 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001386 return -1;
1387 }
1388
willy tarreau9fe663a2005-12-17 13:02:59 +01001389 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001390 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1391 close(fd);
1392 return -1;
1393 }
1394
willy tarreau0f7af912005-12-17 12:21:26 +01001395 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1396 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001397 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001398 close(fd);
1399 return -1;
1400 }
1401
willy tarreaua1598082005-12-17 13:08:06 +01001402 /* allow specific binding */
1403 if (s->proxy->options & PR_O_BIND_SRC &&
1404 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1405 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1406 close(fd);
1407 return -1;
1408 }
1409
willy tarreau0f7af912005-12-17 12:21:26 +01001410 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1411 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001412 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001413 close(fd);
1414 return -1;
1415 }
1416 else if (errno != EALREADY && errno != EISCONN) {
1417 close(fd);
1418 return -1;
1419 }
1420 }
1421
willy tarreau5cbea6f2005-12-17 12:48:26 +01001422 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001423 fdtab[fd].read = &event_srv_read;
1424 fdtab[fd].write = &event_srv_write;
1425 fdtab[fd].state = FD_STCONN; /* connection in progress */
1426
1427 FD_SET(fd, StaticWriteEvent); /* for connect status */
1428
1429 fd_insert(fd);
1430
1431 if (s->proxy->contimeout)
1432 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1433 else
1434 tv_eternity(&s->cnexpire);
1435 return 0;
1436}
1437
1438/*
1439 * this function is called on a read event from a client socket.
1440 * It returns 0.
1441 */
1442int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001443 struct task *t = fdtab[fd].owner;
1444 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001445 struct buffer *b = s->req;
1446 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001447
1448 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1449
willy tarreau0f7af912005-12-17 12:21:26 +01001450 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001451 while (1) {
1452 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1453 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001454 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001455 }
1456 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001457 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001458 }
1459 else {
1460 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001461 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1462 * since it means that the rewrite protection has been removed. This
1463 * implies that the if statement can be removed.
1464 */
1465 if (max > b->rlim - b->data)
1466 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001467 }
1468
1469 if (max == 0) { /* not anymore room to store data */
1470 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001471 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001472 }
1473
willy tarreau3242e862005-12-17 12:27:53 +01001474#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001475 {
1476 int skerr, lskerr;
1477
1478 lskerr = sizeof(skerr);
1479 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1480 if (skerr)
1481 ret = -1;
1482 else
1483 ret = recv(fd, b->r, max, 0);
1484 }
willy tarreau3242e862005-12-17 12:27:53 +01001485#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001486 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001487#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001488 if (ret > 0) {
1489 b->r += ret;
1490 b->l += ret;
1491 s->res_cr = RES_DATA;
1492
1493 if (b->r == b->data + BUFSIZE) {
1494 b->r = b->data; /* wrap around the buffer */
1495 }
willy tarreaua1598082005-12-17 13:08:06 +01001496
1497 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001498 /* we hope to read more data or to get a close on next round */
1499 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001500 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001501 else if (ret == 0) {
1502 s->res_cr = RES_NULL;
1503 break;
1504 }
1505 else if (errno == EAGAIN) {/* ignore EAGAIN */
1506 break;
1507 }
1508 else {
1509 s->res_cr = RES_ERROR;
1510 fdtab[fd].state = FD_STERROR;
1511 break;
1512 }
1513 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001514 }
1515 else {
1516 s->res_cr = RES_ERROR;
1517 fdtab[fd].state = FD_STERROR;
1518 }
1519
willy tarreau5cbea6f2005-12-17 12:48:26 +01001520 if (s->res_cr != RES_SILENT) {
1521 if (s->proxy->clitimeout)
1522 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1523 else
1524 tv_eternity(&s->crexpire);
1525
1526 task_wakeup(&rq, t);
1527 }
willy tarreau0f7af912005-12-17 12:21:26 +01001528
willy tarreau0f7af912005-12-17 12:21:26 +01001529 return 0;
1530}
1531
1532
1533/*
1534 * this function is called on a read event from a server socket.
1535 * It returns 0.
1536 */
1537int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001538 struct task *t = fdtab[fd].owner;
1539 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001540 struct buffer *b = s->rep;
1541 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001542
1543 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1544
willy tarreau0f7af912005-12-17 12:21:26 +01001545 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001546 while (1) {
1547 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1548 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001549 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001550 }
1551 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001552 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001553 }
1554 else {
1555 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001556 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1557 * since it means that the rewrite protection has been removed. This
1558 * implies that the if statement can be removed.
1559 */
1560 if (max > b->rlim - b->data)
1561 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562 }
1563
1564 if (max == 0) { /* not anymore room to store data */
1565 FD_CLR(fd, StaticReadEvent);
1566 break;
1567 }
1568
willy tarreau3242e862005-12-17 12:27:53 +01001569#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001570 {
1571 int skerr, lskerr;
1572
1573 lskerr = sizeof(skerr);
1574 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1575 if (skerr)
1576 ret = -1;
1577 else
1578 ret = recv(fd, b->r, max, 0);
1579 }
willy tarreau3242e862005-12-17 12:27:53 +01001580#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001581 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001582#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001583 if (ret > 0) {
1584 b->r += ret;
1585 b->l += ret;
1586 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001587
willy tarreau5cbea6f2005-12-17 12:48:26 +01001588 if (b->r == b->data + BUFSIZE) {
1589 b->r = b->data; /* wrap around the buffer */
1590 }
willy tarreaua1598082005-12-17 13:08:06 +01001591
1592 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001593 /* we hope to read more data or to get a close on next round */
1594 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001595 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001596 else if (ret == 0) {
1597 s->res_sr = RES_NULL;
1598 break;
1599 }
1600 else if (errno == EAGAIN) {/* ignore EAGAIN */
1601 break;
1602 }
1603 else {
1604 s->res_sr = RES_ERROR;
1605 fdtab[fd].state = FD_STERROR;
1606 break;
1607 }
1608 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001609 }
1610 else {
1611 s->res_sr = RES_ERROR;
1612 fdtab[fd].state = FD_STERROR;
1613 }
1614
willy tarreau5cbea6f2005-12-17 12:48:26 +01001615 if (s->res_sr != RES_SILENT) {
1616 if (s->proxy->srvtimeout)
1617 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1618 else
1619 tv_eternity(&s->srexpire);
1620
1621 task_wakeup(&rq, t);
1622 }
willy tarreau0f7af912005-12-17 12:21:26 +01001623
willy tarreau0f7af912005-12-17 12:21:26 +01001624 return 0;
1625}
1626
1627/*
1628 * this function is called on a write event from a client socket.
1629 * It returns 0.
1630 */
1631int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001632 struct task *t = fdtab[fd].owner;
1633 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001634 struct buffer *b = s->rep;
1635 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001636
1637 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1638
1639 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001640 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001641 // max = BUFSIZE; BUG !!!!
1642 max = 0;
1643 }
1644 else if (b->r > b->w) {
1645 max = b->r - b->w;
1646 }
1647 else
1648 max = b->data + BUFSIZE - b->w;
1649
willy tarreau0f7af912005-12-17 12:21:26 +01001650 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001651#ifndef MSG_NOSIGNAL
1652 int skerr, lskerr;
1653#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001654
1655 if (max == 0) {
1656 s->res_cw = RES_NULL;
1657 task_wakeup(&rq, t);
1658 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001659 }
1660
willy tarreau3242e862005-12-17 12:27:53 +01001661#ifndef MSG_NOSIGNAL
1662 lskerr=sizeof(skerr);
1663 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1664 if (skerr)
1665 ret = -1;
1666 else
1667 ret = send(fd, b->w, max, MSG_DONTWAIT);
1668#else
willy tarreau0f7af912005-12-17 12:21:26 +01001669 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001670#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001671
1672 if (ret > 0) {
1673 b->l -= ret;
1674 b->w += ret;
1675
1676 s->res_cw = RES_DATA;
1677
1678 if (b->w == b->data + BUFSIZE) {
1679 b->w = b->data; /* wrap around the buffer */
1680 }
1681 }
1682 else if (ret == 0) {
1683 /* nothing written, just make as if we were never called */
1684// s->res_cw = RES_NULL;
1685 return 0;
1686 }
1687 else if (errno == EAGAIN) /* ignore EAGAIN */
1688 return 0;
1689 else {
1690 s->res_cw = RES_ERROR;
1691 fdtab[fd].state = FD_STERROR;
1692 }
1693 }
1694 else {
1695 s->res_cw = RES_ERROR;
1696 fdtab[fd].state = FD_STERROR;
1697 }
1698
1699 if (s->proxy->clitimeout)
1700 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1701 else
1702 tv_eternity(&s->cwexpire);
1703
willy tarreau5cbea6f2005-12-17 12:48:26 +01001704 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001705 return 0;
1706}
1707
1708
1709/*
1710 * this function is called on a write event from a server socket.
1711 * It returns 0.
1712 */
1713int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001714 struct task *t = fdtab[fd].owner;
1715 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001716 struct buffer *b = s->req;
1717 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001718
1719 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1720
1721 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001722 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001723 // max = BUFSIZE; BUG !!!!
1724 max = 0;
1725 }
1726 else if (b->r > b->w) {
1727 max = b->r - b->w;
1728 }
1729 else
1730 max = b->data + BUFSIZE - b->w;
1731
willy tarreau0f7af912005-12-17 12:21:26 +01001732 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001733#ifndef MSG_NOSIGNAL
1734 int skerr, lskerr;
1735#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001736 if (max == 0) {
1737 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001738 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001739 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001740 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001741 return 0;
1742 }
1743
willy tarreauef900ab2005-12-17 12:52:52 +01001744
willy tarreau3242e862005-12-17 12:27:53 +01001745#ifndef MSG_NOSIGNAL
1746 lskerr=sizeof(skerr);
1747 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1748 if (skerr)
1749 ret = -1;
1750 else
1751 ret = send(fd, b->w, max, MSG_DONTWAIT);
1752#else
willy tarreau0f7af912005-12-17 12:21:26 +01001753 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001754#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001755 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001756 if (ret > 0) {
1757 b->l -= ret;
1758 b->w += ret;
1759
1760 s->res_sw = RES_DATA;
1761
1762 if (b->w == b->data + BUFSIZE) {
1763 b->w = b->data; /* wrap around the buffer */
1764 }
1765 }
1766 else if (ret == 0) {
1767 /* nothing written, just make as if we were never called */
1768 // s->res_sw = RES_NULL;
1769 return 0;
1770 }
1771 else if (errno == EAGAIN) /* ignore EAGAIN */
1772 return 0;
1773 else {
1774 s->res_sw = RES_ERROR;
1775 fdtab[fd].state = FD_STERROR;
1776 }
1777 }
1778 else {
1779 s->res_sw = RES_ERROR;
1780 fdtab[fd].state = FD_STERROR;
1781 }
1782
1783 if (s->proxy->srvtimeout)
1784 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1785 else
1786 tv_eternity(&s->swexpire);
1787
willy tarreau5cbea6f2005-12-17 12:48:26 +01001788 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001789 return 0;
1790}
1791
1792
1793/*
willy tarreaue39cd132005-12-17 13:00:18 +01001794 * returns a message to the client ; the connection is shut down for read,
1795 * and the request is cleared so that no server connection can be initiated.
1796 * The client must be in a valid state for this (HEADER, DATA ...).
1797 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01001798 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001799 */
1800void client_retnclose(struct session *s, int len, const char *msg) {
1801 FD_CLR(s->cli_fd, StaticReadEvent);
1802 FD_SET(s->cli_fd, StaticWriteEvent);
1803 tv_eternity(&s->crexpire);
1804 shutdown(s->cli_fd, SHUT_RD);
1805 s->cli_state = CL_STSHUTR;
1806 strcpy(s->rep->data, msg);
1807 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001808 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001809 s->rep->r += len;
1810 s->req->l = 0;
1811}
1812
1813
1814/*
1815 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01001816 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001817 */
1818void client_return(struct session *s, int len, const char *msg) {
1819 strcpy(s->rep->data, msg);
1820 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001821 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001822 s->rep->r += len;
1823 s->req->l = 0;
1824}
1825
willy tarreau9fe663a2005-12-17 13:02:59 +01001826/*
1827 * send a log for the session when we have enough info about it
1828 */
1829void sess_log(struct session *s) {
1830 unsigned char *pn;
1831 struct proxy *p = s->proxy;
1832 int log;
1833 char *uri;
1834 char *pxid;
1835 char *srv;
1836
1837 /* This is a first attempt at a better logging system.
1838 * For now, we rely on send_log() to provide the date, although it obviously
1839 * is the date of the log and not of the request, and most fields are not
1840 * computed.
1841 */
1842
willy tarreaua1598082005-12-17 13:08:06 +01001843 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001844
1845 pn = (log & LW_CLIP) ?
1846 (unsigned char *)&s->cli_addr.sin_addr :
1847 (unsigned char *)"\0\0\0\0";
1848
willy tarreaua1598082005-12-17 13:08:06 +01001849 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001850 pxid = p->id;
1851 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001852 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1853
1854 if (p->to_log & LW_DATE) {
1855 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1856
willy tarreau036e1ce2005-12-17 13:46:33 +01001857 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 +01001858 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1859 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1860 tm->tm_hour, tm->tm_min, tm->tm_sec,
1861 pxid, srv,
1862 s->logs.t_request,
1863 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1864 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1865 s->logs.t_close,
1866 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001867 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1868 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01001869 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
1870 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
1871 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
1872 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01001873 uri);
1874 }
1875 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01001876 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 +01001877 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1878 pxid, srv,
1879 s->logs.t_request,
1880 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1881 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1882 s->logs.t_close,
1883 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001884 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1885 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01001886 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
1887 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
1888 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
1889 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01001890 uri);
1891 }
1892
1893 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001894}
1895
willy tarreaue39cd132005-12-17 13:00:18 +01001896
1897/*
willy tarreau0f7af912005-12-17 12:21:26 +01001898 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001899 * to an accept. It tries to accept as many connections as possible.
1900 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001901 */
1902int event_accept(int fd) {
1903 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001904 struct session *s;
1905 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001906 int cfd;
1907 int one = 1;
1908
willy tarreau5cbea6f2005-12-17 12:48:26 +01001909 while (p->nbconn < p->maxconn) {
1910 struct sockaddr_in addr;
1911 int laddr = sizeof(addr);
1912 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1913 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001914
willy tarreau5cbea6f2005-12-17 12:48:26 +01001915 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1916 Alert("out of memory in event_accept().\n");
1917 FD_CLR(fd, StaticReadEvent);
1918 p->state = PR_STIDLE;
1919 close(cfd);
1920 return 0;
1921 }
willy tarreau0f7af912005-12-17 12:21:26 +01001922
willy tarreau5cbea6f2005-12-17 12:48:26 +01001923 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1924 Alert("out of memory in event_accept().\n");
1925 FD_CLR(fd, StaticReadEvent);
1926 p->state = PR_STIDLE;
1927 close(cfd);
1928 pool_free(session, s);
1929 return 0;
1930 }
willy tarreau0f7af912005-12-17 12:21:26 +01001931
willy tarreau5cbea6f2005-12-17 12:48:26 +01001932 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001933 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001934 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1935 close(cfd);
1936 pool_free(task, t);
1937 pool_free(session, s);
1938 return 0;
1939 }
willy tarreau0f7af912005-12-17 12:21:26 +01001940
willy tarreau5cbea6f2005-12-17 12:48:26 +01001941 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1942 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1943 (char *) &one, sizeof(one)) == -1)) {
1944 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1945 close(cfd);
1946 pool_free(task, t);
1947 pool_free(session, s);
1948 return 0;
1949 }
willy tarreau0f7af912005-12-17 12:21:26 +01001950
willy tarreau9fe663a2005-12-17 13:02:59 +01001951 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1952 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1953 t->state = TASK_IDLE;
1954 t->process = process_session;
1955 t->context = s;
1956
1957 s->task = t;
1958 s->proxy = p;
1959 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1960 s->srv_state = SV_STIDLE;
1961 s->req = s->rep = NULL; /* will be allocated later */
1962 s->flags = 0;
1963 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1964 s->cli_fd = cfd;
1965 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01001966 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01001967 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01001968
1969 s->logs.logwait = p->to_log;
1970 s->logs.tv_accept = now;
1971 s->logs.t_request = -1;
1972 s->logs.t_connect = -1;
1973 s->logs.t_data = -1;
1974 s->logs.t_close = 0;
1975 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01001976 s->logs.cli_cookie = NULL;
1977 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01001978 s->logs.status = -1;
1979 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001980
willy tarreau5cbea6f2005-12-17 12:48:26 +01001981 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1982 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01001983 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001984 unsigned char *pn, *sn;
1985 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01001986
willy tarreau5cbea6f2005-12-17 12:48:26 +01001987 namelen = sizeof(sockname);
1988 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1989 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1990 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01001991 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001992
willy tarreau9fe663a2005-12-17 13:02:59 +01001993 if (p->to_log) {
1994 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01001995 if (s->logs.logwait & LW_CLIP)
1996 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01001997 sess_log(s);
1998 }
1999 else
2000 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
2001 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
2002 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
2003 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01002004 }
willy tarreau0f7af912005-12-17 12:21:26 +01002005
willy tarreau9fe663a2005-12-17 13:02:59 +01002006 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002007 int len;
2008 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
2009 write(1, trash, len);
2010 }
willy tarreau0f7af912005-12-17 12:21:26 +01002011
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2013 close(cfd); /* nothing can be done for this fd without memory */
2014 pool_free(task, t);
2015 pool_free(session, s);
2016 return 0;
2017 }
2018 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002019 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002020 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2021 s->req->rlim = s->req->data + BUFSIZE;
2022 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
2023 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002024
willy tarreau5cbea6f2005-12-17 12:48:26 +01002025 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2026 pool_free(buffer, s->req);
2027 close(cfd); /* nothing can be done for this fd without memory */
2028 pool_free(task, t);
2029 pool_free(session, s);
2030 return 0;
2031 }
2032 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002033 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002034 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 +01002035
willy tarreau5cbea6f2005-12-17 12:48:26 +01002036 fdtab[cfd].read = &event_cli_read;
2037 fdtab[cfd].write = &event_cli_write;
2038 fdtab[cfd].owner = t;
2039 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002040
willy tarreau5cbea6f2005-12-17 12:48:26 +01002041 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01002042 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002043 }
2044 else {
2045 FD_SET(cfd, StaticReadEvent);
2046 }
2047
2048 fd_insert(cfd);
2049
2050 tv_eternity(&s->cnexpire);
2051 tv_eternity(&s->srexpire);
2052 tv_eternity(&s->swexpire);
2053 tv_eternity(&s->cwexpire);
2054
2055 if (s->proxy->clitimeout)
2056 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2057 else
2058 tv_eternity(&s->crexpire);
2059
2060 t->expire = s->crexpire;
2061
2062 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002063
2064 if (p->mode != PR_MODE_HEALTH)
2065 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002066
2067 p->nbconn++;
2068 actconn++;
2069 totalconn++;
2070
2071 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2072 } /* end of while (p->nbconn < p->maxconn) */
2073 return 0;
2074}
willy tarreau0f7af912005-12-17 12:21:26 +01002075
willy tarreau0f7af912005-12-17 12:21:26 +01002076
willy tarreau5cbea6f2005-12-17 12:48:26 +01002077/*
2078 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002079 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2080 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002081 * or -1 if an error occured.
2082 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002083int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002084 struct task *t = fdtab[fd].owner;
2085 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002086
willy tarreau5cbea6f2005-12-17 12:48:26 +01002087 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002088 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002089 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2090 if (skerr)
2091 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002092 else {
2093 if (s->proxy->options & PR_O_HTTP_CHK) {
2094 int ret;
willy tarreau036e1ce2005-12-17 13:46:33 +01002095 /* we want to check if this host replies to "OPTIONS * HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002096 * so we'll send the request, and won't wake the checker up now.
2097 */
2098#ifndef MSG_NOSIGNAL
willy tarreau036e1ce2005-12-17 13:46:33 +01002099 ret = send(fd, "OPTIONS * HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002100#else
willy tarreau036e1ce2005-12-17 13:46:33 +01002101 ret = send(fd, "OPTIONS * HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002102#endif
2103 if (ret == 22) {
2104 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2105 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2106 return 0;
2107 }
2108 else
2109 s->result = -1;
2110 }
2111 else {
2112 /* good TCP connection is enough */
2113 s->result = 1;
2114 }
2115 }
2116
2117 task_wakeup(&rq, t);
2118 return 0;
2119}
2120
willy tarreau0f7af912005-12-17 12:21:26 +01002121
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002122/*
2123 * This function is used only for server health-checks. It handles
2124 * the server's reply to an HTTP request. It returns 1 if the server replies
2125 * 2xx or 3xx (valid responses), or -1 in other cases.
2126 */
2127int event_srv_chk_r(int fd) {
2128 char reply[64];
2129 int len;
2130 struct task *t = fdtab[fd].owner;
2131 struct server *s = t->context;
2132
2133 int skerr, lskerr;
2134 lskerr = sizeof(skerr);
2135 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2136 s->result = -1;
2137 if (!skerr) {
2138#ifndef MSG_NOSIGNAL
2139 len = recv(fd, reply, sizeof(reply), 0);
2140#else
2141 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
2142#endif
2143 if ((len >= sizeof("HTTP/1.0 000")) &&
2144 !memcmp(reply, "HTTP/1.", 7) &&
2145 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2146 s->result = 1;
2147 }
2148
2149 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002150 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002151 return 0;
2152}
2153
2154
2155/*
2156 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2157 * and moves <end> just after the end of <str>.
2158 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2159 * the shift value (positive or negative) is returned.
2160 * If there's no space left, the move is not done.
2161 *
2162 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002163int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002164 int delta;
2165 int len;
2166
2167 len = strlen(str);
2168 delta = len - (end - pos);
2169
2170 if (delta + b->r >= b->data + BUFSIZE)
2171 return 0; /* no space left */
2172
2173 /* first, protect the end of the buffer */
2174 memmove(end + delta, end, b->data + b->l - end);
2175
2176 /* now, copy str over pos */
2177 memcpy(pos, str,len);
2178
willy tarreau5cbea6f2005-12-17 12:48:26 +01002179 /* we only move data after the displaced zone */
2180 if (b->r > pos) b->r += delta;
2181 if (b->w > pos) b->w += delta;
2182 if (b->h > pos) b->h += delta;
2183 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002184 b->l += delta;
2185
2186 return delta;
2187}
2188
willy tarreau8337c6b2005-12-17 13:41:01 +01002189/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002190 * len is 0.
2191 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002192int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002193 int delta;
2194
2195 delta = len - (end - pos);
2196
2197 if (delta + b->r >= b->data + BUFSIZE)
2198 return 0; /* no space left */
2199
2200 /* first, protect the end of the buffer */
2201 memmove(end + delta, end, b->data + b->l - end);
2202
2203 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002204 if (len)
2205 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002206
willy tarreau5cbea6f2005-12-17 12:48:26 +01002207 /* we only move data after the displaced zone */
2208 if (b->r > pos) b->r += delta;
2209 if (b->w > pos) b->w += delta;
2210 if (b->h > pos) b->h += delta;
2211 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002212 b->l += delta;
2213
2214 return delta;
2215}
2216
2217
2218int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2219 char *old_dst = dst;
2220
2221 while (*str) {
2222 if (*str == '\\') {
2223 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002224 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002225 int len, num;
2226
2227 num = *str - '0';
2228 str++;
2229
2230 if (matches[num].rm_so > -1) {
2231 len = matches[num].rm_eo - matches[num].rm_so;
2232 memcpy(dst, src + matches[num].rm_so, len);
2233 dst += len;
2234 }
2235
2236 }
2237 else if (*str == 'x') {
2238 unsigned char hex1, hex2;
2239 str++;
2240
2241 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2242
2243 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2244 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2245 *dst++ = (hex1<<4) + hex2;
2246 }
2247 else
2248 *dst++ = *str++;
2249 }
2250 else
2251 *dst++ = *str++;
2252 }
2253 *dst = 0;
2254 return dst - old_dst;
2255}
2256
willy tarreau9fe663a2005-12-17 13:02:59 +01002257
willy tarreau0f7af912005-12-17 12:21:26 +01002258/*
2259 * manages the client FSM and its socket. BTW, it also tries to handle the
2260 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2261 * 0 else.
2262 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002263int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002264 int s = t->srv_state;
2265 int c = t->cli_state;
2266 struct buffer *req = t->req;
2267 struct buffer *rep = t->rep;
2268
willy tarreau750a4722005-12-17 13:21:24 +01002269#ifdef DEBUG_FULL
2270 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2271#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002272 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2273 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2274 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2275 //);
2276 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002277 /* now parse the partial (or complete) headers */
2278 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2279 char *ptr;
2280 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002281
willy tarreau5cbea6f2005-12-17 12:48:26 +01002282 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002283
willy tarreau0f7af912005-12-17 12:21:26 +01002284 /* look for the end of the current header */
2285 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2286 ptr++;
2287
willy tarreau5cbea6f2005-12-17 12:48:26 +01002288 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002289 int line, len;
2290 /* we can only get here after an end of headers */
2291 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002292
willy tarreaue39cd132005-12-17 13:00:18 +01002293 if (t->flags & SN_CLDENY) {
2294 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002295 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002296 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002297 if (!(t->flags & SN_ERR_MASK))
2298 t->flags |= SN_ERR_PRXCOND;
2299 if (!(t->flags & SN_FINST_MASK))
2300 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002301 return 1;
2302 }
2303
willy tarreau5cbea6f2005-12-17 12:48:26 +01002304 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002305 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2306 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002307 }
willy tarreau0f7af912005-12-17 12:21:26 +01002308
willy tarreau9fe663a2005-12-17 13:02:59 +01002309 if (t->proxy->options & PR_O_FWDFOR) {
2310 /* insert an X-Forwarded-For header */
2311 unsigned char *pn;
2312 pn = (unsigned char *)&t->cli_addr.sin_addr;
willy tarreau750a4722005-12-17 13:21:24 +01002313 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01002314 pn[0], pn[1], pn[2], pn[3]);
willy tarreau750a4722005-12-17 13:21:24 +01002315 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau9fe663a2005-12-17 13:02:59 +01002316 }
2317
willy tarreaucd878942005-12-17 13:27:43 +01002318 if (!memcmp(req->data, "POST ", 5))
2319 t->flags |= SN_POST; /* this is a POST request */
2320
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002322 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002323
willy tarreau750a4722005-12-17 13:21:24 +01002324 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002325 /* FIXME: we'll set the client in a wait state while we try to
2326 * connect to the server. Is this really needed ? wouldn't it be
2327 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002328 //FD_CLR(t->cli_fd, StaticReadEvent);
2329 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002330 break;
2331 }
willy tarreau0f7af912005-12-17 12:21:26 +01002332
willy tarreau5cbea6f2005-12-17 12:48:26 +01002333 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2334 if (ptr > req->r - 2) {
2335 /* this is a partial header, let's wait for more to come */
2336 req->lr = ptr;
2337 break;
2338 }
willy tarreau0f7af912005-12-17 12:21:26 +01002339
willy tarreau5cbea6f2005-12-17 12:48:26 +01002340 /* now we know that *ptr is either \r or \n,
2341 * and that there are at least 1 char after it.
2342 */
2343 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2344 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2345 else
2346 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002347
willy tarreau5cbea6f2005-12-17 12:48:26 +01002348 /*
2349 * now we know that we have a full header ; we can do whatever
2350 * we want with these pointers :
2351 * req->h = beginning of header
2352 * ptr = end of header (first \r or \n)
2353 * req->lr = beginning of next line (next rep->h)
2354 * req->r = end of data (not used at this stage)
2355 */
willy tarreau0f7af912005-12-17 12:21:26 +01002356
willy tarreau8337c6b2005-12-17 13:41:01 +01002357 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002358 /* we have a complete HTTP request that we must log */
2359 int urilen;
2360
willy tarreaua1598082005-12-17 13:08:06 +01002361 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002362 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002363 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002364 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002365 if (!(t->flags & SN_ERR_MASK))
2366 t->flags |= SN_ERR_PRXCOND;
2367 if (!(t->flags & SN_FINST_MASK))
2368 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002369 return 1;
2370 }
2371
2372 urilen = ptr - req->h;
2373 if (urilen >= REQURI_LEN)
2374 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002375 memcpy(t->logs.uri, req->h, urilen);
2376 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002377
willy tarreaua1598082005-12-17 13:08:06 +01002378 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002379 sess_log(t);
2380 }
2381
willy tarreau5cbea6f2005-12-17 12:48:26 +01002382 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002383
willy tarreau9fe663a2005-12-17 13:02:59 +01002384 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002385 int len, max;
2386 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2387 max = ptr - req->h;
2388 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002389 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002390 trash[len++] = '\n';
2391 write(1, trash, len);
2392 }
willy tarreau0f7af912005-12-17 12:21:26 +01002393
willy tarreau5cbea6f2005-12-17 12:48:26 +01002394 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002395 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2396 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002397 char term;
2398
2399 term = *ptr;
2400 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002401 exp = t->proxy->req_exp;
2402 do {
2403 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2404 switch (exp->action) {
2405 case ACT_ALLOW:
2406 if (!(t->flags & SN_CLDENY))
2407 t->flags |= SN_CLALLOW;
2408 break;
2409 case ACT_REPLACE:
2410 if (!(t->flags & SN_CLDENY)) {
2411 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2412 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2413 }
2414 break;
2415 case ACT_REMOVE:
2416 if (!(t->flags & SN_CLDENY))
2417 delete_header = 1;
2418 break;
2419 case ACT_DENY:
2420 if (!(t->flags & SN_CLALLOW))
2421 t->flags |= SN_CLDENY;
2422 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002423 case ACT_PASS: /* we simply don't deny this one */
2424 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002425 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002426 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002427 }
willy tarreaue39cd132005-12-17 13:00:18 +01002428 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002429 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002430 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002431
willy tarreau240afa62005-12-17 13:14:35 +01002432 /* Now look for cookies. Conforming to RFC2109, we have to support
2433 * attributes whose name begin with a '$', and associate them with
2434 * the right cookie, if we want to delete this cookie.
2435 * So there are 3 cases for each cookie read :
2436 * 1) it's a special attribute, beginning with a '$' : ignore it.
2437 * 2) it's a server id cookie that we *MAY* want to delete : save
2438 * some pointers on it (last semi-colon, beginning of cookie...)
2439 * 3) it's an application cookie : we *MAY* have to delete a previous
2440 * "special" cookie.
2441 * At the end of loop, if a "special" cookie remains, we may have to
2442 * remove it. If no application cookie persists in the header, we
2443 * *MUST* delete it
2444 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002445 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002446 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau8337c6b2005-12-17 13:41:01 +01002447 && (memcmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002448 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002449 char *del_colon, *del_cookie, *colon;
2450 int app_cookies;
2451
willy tarreau5cbea6f2005-12-17 12:48:26 +01002452 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002453 colon = p1;
2454 /* del_cookie == NULL => nothing to be deleted */
2455 del_colon = del_cookie = NULL;
2456 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002457
2458 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002459 /* skip spaces and colons, but keep an eye on these ones */
2460 while (p1 < ptr) {
2461 if (*p1 == ';' || *p1 == ',')
2462 colon = p1;
2463 else if (!isspace((int)*p1))
2464 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002465 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002466 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002467
2468 if (p1 == ptr)
2469 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002470
2471 /* p1 is at the beginning of the cookie name */
2472 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002473 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002474 p2++;
2475
2476 if (p2 == ptr)
2477 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002478
2479 p3 = p2 + 1; /* skips the '=' sign */
2480 if (p3 == ptr)
2481 break;
2482
willy tarreau240afa62005-12-17 13:14:35 +01002483 p4 = p3;
2484 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002485 p4++;
2486
2487 /* here, we have the cookie name between p1 and p2,
2488 * and its value between p3 and p4.
2489 * we can process it.
2490 */
2491
willy tarreau240afa62005-12-17 13:14:35 +01002492 if (*p1 == '$') {
2493 /* skip this one */
2494 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002495 else {
2496 /* first, let's see if we want to capture it */
2497 if (t->proxy->capture_name != NULL &&
2498 t->logs.cli_cookie == NULL &&
2499 (p4 - p1 >= t->proxy->capture_namelen) &&
2500 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2501 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002502
willy tarreau8337c6b2005-12-17 13:41:01 +01002503 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2504 Alert("HTTP logging : out of memory.\n");
2505 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002506
willy tarreau8337c6b2005-12-17 13:41:01 +01002507 if (log_len > t->proxy->capture_len)
2508 log_len = t->proxy->capture_len;
2509 memcpy(t->logs.cli_cookie, p1, log_len);
2510 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002511 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002512
2513 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2514 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2515 /* Cool... it's the right one */
2516 struct server *srv = t->proxy->srv;
2517
2518 while (srv &&
2519 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2520 srv = srv->next;
2521 }
2522
willy tarreau036e1ce2005-12-17 13:46:33 +01002523 if (!srv) {
2524 t->flags &= ~SN_CK_MASK;
2525 t->flags |= SN_CK_INVALID;
2526 }
2527 else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002528 /* we found the server and it's usable */
willy tarreau036e1ce2005-12-17 13:46:33 +01002529 t->flags &= ~SN_CK_MASK;
2530 t->flags |= SN_CK_VALID | SN_DIRECT;
willy tarreau8337c6b2005-12-17 13:41:01 +01002531 t->srv = srv;
2532 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002533 else {
2534 t->flags &= ~SN_CK_MASK;
2535 t->flags |= SN_CK_DOWN;
2536 }
2537
willy tarreau8337c6b2005-12-17 13:41:01 +01002538 /* if this cookie was set in insert+indirect mode, then it's better that the
2539 * server never sees it.
2540 */
2541 if (del_cookie == NULL &&
2542 (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 +01002543 del_cookie = p1;
2544 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002545 }
willy tarreau240afa62005-12-17 13:14:35 +01002546 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002547 else {
2548 /* now we know that we must keep this cookie since it's
2549 * not ours. But if we wanted to delete our cookie
2550 * earlier, we cannot remove the complete header, but we
2551 * can remove the previous block itself.
2552 */
2553 app_cookies++;
2554
2555 if (del_cookie != NULL) {
2556 buffer_replace2(req, del_cookie, p1, NULL, 0);
2557 p4 -= (p1 - del_cookie);
2558 ptr -= (p1 - del_cookie);
2559 del_cookie = del_colon = NULL;
2560 }
willy tarreau240afa62005-12-17 13:14:35 +01002561 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002562 }
willy tarreau240afa62005-12-17 13:14:35 +01002563
willy tarreau5cbea6f2005-12-17 12:48:26 +01002564 /* we'll have to look for another cookie ... */
2565 p1 = p4;
2566 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002567
2568 /* There's no more cookie on this line.
2569 * We may have marked the last one(s) for deletion.
2570 * We must do this now in two ways :
2571 * - if there is no app cookie, we simply delete the header ;
2572 * - if there are app cookies, we must delete the end of the
2573 * string properly, including the colon/semi-colon before
2574 * the cookie name.
2575 */
2576 if (del_cookie != NULL) {
2577 if (app_cookies) {
2578 buffer_replace2(req, del_colon, ptr, NULL, 0);
2579 /* WARNING! <ptr> becomes invalid for now. If some code
2580 * below needs to rely on it before the end of the global
2581 * header loop, we need to correct it with this code :
2582 * ptr = del_colon;
2583 */
2584 }
2585 else
2586 delete_header = 1;
2587 }
2588 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002589
2590 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002591 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002592 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002593 }
willy tarreau240afa62005-12-17 13:14:35 +01002594 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2595
willy tarreau5cbea6f2005-12-17 12:48:26 +01002596 req->h = req->lr;
2597 } /* while (req->lr < req->r) */
2598
2599 /* end of header processing (even if incomplete) */
2600
willy tarreauef900ab2005-12-17 12:52:52 +01002601 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2602 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2603 * full. We cannot loop here since event_cli_read will disable it only if
2604 * req->l == rlim-data
2605 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002606 FD_SET(t->cli_fd, StaticReadEvent);
2607 if (t->proxy->clitimeout)
2608 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2609 else
2610 tv_eternity(&t->crexpire);
2611 }
2612
willy tarreaue39cd132005-12-17 13:00:18 +01002613 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002614 * won't be able to free more later, so the session will never terminate.
2615 */
willy tarreaue39cd132005-12-17 13:00:18 +01002616 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002617 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01002618 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01002619 if (!(t->flags & SN_ERR_MASK))
2620 t->flags |= SN_ERR_PRXCOND;
2621 if (!(t->flags & SN_FINST_MASK))
2622 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002623 return 1;
2624 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002625 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002626 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002627 tv_eternity(&t->crexpire);
2628 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002629 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002630 if (!(t->flags & SN_ERR_MASK))
2631 t->flags |= SN_ERR_CLICL;
2632 if (!(t->flags & SN_FINST_MASK))
2633 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002634 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002635 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002636 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2637
2638 /* read timeout : give up with an error message.
2639 */
2640 t->logs.status = 408;
2641 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01002642 if (!(t->flags & SN_ERR_MASK))
2643 t->flags |= SN_ERR_CLITO;
2644 if (!(t->flags & SN_FINST_MASK))
2645 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01002646 return 1;
2647 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002648
2649 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002650 }
2651 else if (c == CL_STDATA) {
2652 /* read or write error */
2653 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002654 tv_eternity(&t->crexpire);
2655 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002657 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002658 if (!(t->flags & SN_ERR_MASK))
2659 t->flags |= SN_ERR_CLICL;
2660 if (!(t->flags & SN_FINST_MASK))
2661 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002662 return 1;
2663 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002664 /* last read, or end of server write */
2665 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002666 FD_CLR(t->cli_fd, StaticReadEvent);
2667 // if (req->l == 0) /* nothing to write on the server side */
2668 // FD_CLR(t->srv_fd, StaticWriteEvent);
2669 tv_eternity(&t->crexpire);
2670 shutdown(t->cli_fd, SHUT_RD);
2671 t->cli_state = CL_STSHUTR;
2672 return 1;
2673 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002674 /* last server read and buffer empty */
2675 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002676 FD_CLR(t->cli_fd, StaticWriteEvent);
2677 tv_eternity(&t->cwexpire);
2678 shutdown(t->cli_fd, SHUT_WR);
2679 t->cli_state = CL_STSHUTW;
2680 return 1;
2681 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002682 /* read timeout */
2683 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2684 FD_CLR(t->cli_fd, StaticReadEvent);
2685 // if (req->l == 0) /* nothing to write on the server side */
2686 // FD_CLR(t->srv_fd, StaticWriteEvent);
2687 tv_eternity(&t->crexpire);
2688 shutdown(t->cli_fd, SHUT_RD);
2689 t->cli_state = CL_STSHUTR;
2690 if (!(t->flags & SN_ERR_MASK))
2691 t->flags |= SN_ERR_CLITO;
2692 if (!(t->flags & SN_FINST_MASK))
2693 t->flags |= SN_FINST_D;
2694 return 1;
2695 }
2696 /* write timeout */
2697 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2698 FD_CLR(t->cli_fd, StaticWriteEvent);
2699 tv_eternity(&t->cwexpire);
2700 shutdown(t->cli_fd, SHUT_WR);
2701 t->cli_state = CL_STSHUTW;
2702 if (!(t->flags & SN_ERR_MASK))
2703 t->flags |= SN_ERR_CLICL;
2704 if (!(t->flags & SN_FINST_MASK))
2705 t->flags |= SN_FINST_D;
2706 return 1;
2707 }
willy tarreau0f7af912005-12-17 12:21:26 +01002708
willy tarreauef900ab2005-12-17 12:52:52 +01002709 if (req->l >= req->rlim - req->data) {
2710 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002711 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002712 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002713 FD_CLR(t->cli_fd, StaticReadEvent);
2714 tv_eternity(&t->crexpire);
2715 }
2716 }
2717 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002718 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002719 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2720 FD_SET(t->cli_fd, StaticReadEvent);
2721 if (t->proxy->clitimeout)
2722 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2723 else
2724 tv_eternity(&t->crexpire);
2725 }
2726 }
2727
2728 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002729 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002730 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2731 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2732 tv_eternity(&t->cwexpire);
2733 }
2734 }
2735 else { /* buffer not empty */
2736 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2737 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2738 if (t->proxy->clitimeout)
2739 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2740 else
2741 tv_eternity(&t->cwexpire);
2742 }
2743 }
2744 return 0; /* other cases change nothing */
2745 }
2746 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002747 if (t->res_cw == RES_ERROR) {
2748 tv_eternity(&t->cwexpire);
2749 fd_delete(t->cli_fd);
2750 t->cli_state = CL_STCLOSE;
2751 if (!(t->flags & SN_ERR_MASK))
2752 t->flags |= SN_ERR_CLICL;
2753 if (!(t->flags & SN_FINST_MASK))
2754 t->flags |= SN_FINST_D;
2755 return 1;
2756 }
2757 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002758 tv_eternity(&t->cwexpire);
2759 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002760 t->cli_state = CL_STCLOSE;
2761 return 1;
2762 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002763 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2764 tv_eternity(&t->cwexpire);
2765 fd_delete(t->cli_fd);
2766 t->cli_state = CL_STCLOSE;
2767 if (!(t->flags & SN_ERR_MASK))
2768 t->flags |= SN_ERR_CLITO;
2769 if (!(t->flags & SN_FINST_MASK))
2770 t->flags |= SN_FINST_D;
2771 return 1;
2772 }
willy tarreau0f7af912005-12-17 12:21:26 +01002773 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002774 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002775 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2776 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2777 tv_eternity(&t->cwexpire);
2778 }
2779 }
2780 else { /* buffer not empty */
2781 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2782 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2783 if (t->proxy->clitimeout)
2784 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2785 else
2786 tv_eternity(&t->cwexpire);
2787 }
2788 }
2789 return 0;
2790 }
2791 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002792 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002793 tv_eternity(&t->crexpire);
2794 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002795 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002796 if (!(t->flags & SN_ERR_MASK))
2797 t->flags |= SN_ERR_CLICL;
2798 if (!(t->flags & SN_FINST_MASK))
2799 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002800 return 1;
2801 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002802 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
2803 tv_eternity(&t->crexpire);
2804 fd_delete(t->cli_fd);
2805 t->cli_state = CL_STCLOSE;
2806 return 1;
2807 }
2808 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2809 tv_eternity(&t->crexpire);
2810 fd_delete(t->cli_fd);
2811 t->cli_state = CL_STCLOSE;
2812 if (!(t->flags & SN_ERR_MASK))
2813 t->flags |= SN_ERR_CLITO;
2814 if (!(t->flags & SN_FINST_MASK))
2815 t->flags |= SN_FINST_D;
2816 return 1;
2817 }
willy tarreauef900ab2005-12-17 12:52:52 +01002818 else if (req->l >= req->rlim - req->data) {
2819 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002820 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002821 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002822 FD_CLR(t->cli_fd, StaticReadEvent);
2823 tv_eternity(&t->crexpire);
2824 }
2825 }
2826 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002827 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002828 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2829 FD_SET(t->cli_fd, StaticReadEvent);
2830 if (t->proxy->clitimeout)
2831 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2832 else
2833 tv_eternity(&t->crexpire);
2834 }
2835 }
2836 return 0;
2837 }
2838 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002839 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002840 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002841 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002842 write(1, trash, len);
2843 }
2844 return 0;
2845 }
2846 return 0;
2847}
2848
2849
2850/*
2851 * manages the server FSM and its socket. It returns 1 if a state has changed
2852 * (and a resync may be needed), 0 else.
2853 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002854int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002855 int s = t->srv_state;
2856 int c = t->cli_state;
2857 struct buffer *req = t->req;
2858 struct buffer *rep = t->rep;
2859
willy tarreau750a4722005-12-17 13:21:24 +01002860#ifdef DEBUG_FULL
2861 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2862#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002863 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2864 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2865 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2866 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002867 if (s == SV_STIDLE) {
2868 if (c == CL_STHEADERS)
2869 return 0; /* stay in idle, waiting for data to reach the client side */
2870 else if (c == CL_STCLOSE ||
2871 c == CL_STSHUTW ||
2872 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2873 tv_eternity(&t->cnexpire);
2874 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002875 if (!(t->flags & SN_ERR_MASK))
2876 t->flags |= SN_ERR_CLICL;
2877 if (!(t->flags & SN_FINST_MASK))
2878 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01002879 return 1;
2880 }
2881 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002882 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002883 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2884 t->srv_state = SV_STCONN;
2885 }
2886 else { /* try again */
2887 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002888 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002889 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002890 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01002891 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
2892 t->flags &= ~SN_CK_MASK;
2893 t->flags |= SN_CK_DOWN;
2894 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002895 }
2896
2897 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002898 t->srv_state = SV_STCONN;
2899 break;
2900 }
2901 }
2902 if (t->conn_retries < 0) {
2903 /* if conn_retries < 0 or other error, let's abort */
2904 tv_eternity(&t->cnexpire);
2905 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01002906 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01002907 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01002908 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01002909 if (!(t->flags & SN_ERR_MASK))
2910 t->flags |= SN_ERR_SRVCL;
2911 if (!(t->flags & SN_FINST_MASK))
2912 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01002913 }
2914 }
2915 return 1;
2916 }
2917 }
2918 else if (s == SV_STCONN) { /* connection in progress */
2919 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2920 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2921 return 0; /* nothing changed */
2922 }
2923 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2924 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2925 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002926 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002927 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002928 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002929 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002930 if (t->conn_retries >= 0) {
2931 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002932 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002933 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01002934 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
2935 t->flags &= ~SN_CK_MASK;
2936 t->flags |= SN_CK_DOWN;
2937 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002938 }
2939 if (connect_server(t) == 0)
2940 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002941 }
2942 /* if conn_retries < 0 or other error, let's abort */
2943 tv_eternity(&t->cnexpire);
2944 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01002945 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01002946 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01002947 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01002948 if (!(t->flags & SN_ERR_MASK))
2949 t->flags |= SN_ERR_SRVCL;
2950 if (!(t->flags & SN_FINST_MASK))
2951 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01002952 return 1;
2953 }
2954 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01002955 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01002956
willy tarreau0f7af912005-12-17 12:21:26 +01002957 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2958 if (req->l == 0) /* nothing to write */
2959 FD_CLR(t->srv_fd, StaticWriteEvent);
2960 else /* need the right to write */
2961 FD_SET(t->srv_fd, StaticWriteEvent);
2962
2963 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2964 FD_SET(t->srv_fd, StaticReadEvent);
2965 if (t->proxy->srvtimeout)
2966 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2967 else
2968 tv_eternity(&t->srexpire);
2969
2970 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002971 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002972 }
willy tarreauef900ab2005-12-17 12:52:52 +01002973 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002974 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002975 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2976 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002977 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002978 return 1;
2979 }
2980 }
2981 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002982 /* now parse the partial (or complete) headers */
2983 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2984 char *ptr;
2985 int delete_header;
2986
2987 ptr = rep->lr;
2988
2989 /* look for the end of the current header */
2990 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2991 ptr++;
2992
2993 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002994 int line, len;
2995
2996 /* we can only get here after an end of headers */
2997 /* we'll have something else to do here : add new headers ... */
2998
willy tarreaucd878942005-12-17 13:27:43 +01002999 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3000 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003001 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003002 * insert a set-cookie here, except if we want to insert only on POST
3003 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003004 */
willy tarreau750a4722005-12-17 13:21:24 +01003005 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003006 t->proxy->cookie_name,
3007 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003008
willy tarreau036e1ce2005-12-17 13:46:33 +01003009 t->flags |= SN_SCK_INSERTED;
3010
willy tarreau750a4722005-12-17 13:21:24 +01003011 /* Here, we will tell an eventual cache on the client side that we don't
3012 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3013 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3014 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3015 */
willy tarreau240afa62005-12-17 13:14:35 +01003016 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003017 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3018 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003019
willy tarreau750a4722005-12-17 13:21:24 +01003020 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003021 }
3022
3023 /* headers to be added */
3024 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003025 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3026 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003027 }
3028
3029 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003030 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003031 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003032 break;
3033 }
3034
3035 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3036 if (ptr > rep->r - 2) {
3037 /* this is a partial header, let's wait for more to come */
3038 rep->lr = ptr;
3039 break;
3040 }
3041
3042 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3043 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3044
3045 /* now we know that *ptr is either \r or \n,
3046 * and that there are at least 1 char after it.
3047 */
3048 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3049 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3050 else
3051 rep->lr = ptr + 2; /* \r\n or \n\r */
3052
3053 /*
3054 * now we know that we have a full header ; we can do whatever
3055 * we want with these pointers :
3056 * rep->h = beginning of header
3057 * ptr = end of header (first \r or \n)
3058 * rep->lr = beginning of next line (next rep->h)
3059 * rep->r = end of data (not used at this stage)
3060 */
3061
willy tarreaua1598082005-12-17 13:08:06 +01003062
3063 if (t->logs.logwait & LW_RESP) {
3064 t->logs.logwait &= ~LW_RESP;
3065 t->logs.status = atoi(rep->h + 9);
3066 }
3067
willy tarreau5cbea6f2005-12-17 12:48:26 +01003068 delete_header = 0;
3069
willy tarreau9fe663a2005-12-17 13:02:59 +01003070 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003071 int len, max;
3072 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
3073 max = ptr - rep->h;
3074 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003075 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003076 trash[len++] = '\n';
3077 write(1, trash, len);
3078 }
3079
3080 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01003081 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
3082 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003083 char term;
3084
3085 term = *ptr;
3086 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003087 exp = t->proxy->rsp_exp;
3088 do {
3089 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3090 switch (exp->action) {
3091 case ACT_ALLOW:
3092 if (!(t->flags & SN_SVDENY))
3093 t->flags |= SN_SVALLOW;
3094 break;
3095 case ACT_REPLACE:
3096 if (!(t->flags & SN_SVDENY)) {
3097 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3098 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3099 }
3100 break;
3101 case ACT_REMOVE:
3102 if (!(t->flags & SN_SVDENY))
3103 delete_header = 1;
3104 break;
3105 case ACT_DENY:
3106 if (!(t->flags & SN_SVALLOW))
3107 t->flags |= SN_SVDENY;
3108 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003109 case ACT_PASS: /* we simply don't deny this one */
3110 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003111 }
3112 break;
3113 }
willy tarreaue39cd132005-12-17 13:00:18 +01003114 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003115 *ptr = term; /* restore the string terminator */
3116 }
3117
3118 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003119 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3120 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
3121 && (ptr >= rep->h + 12)
3122 && (memcmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003123 char *p1, *p2, *p3, *p4;
3124
3125 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3126
3127 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003128 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003129 p1++;
3130
3131 if (p1 == ptr || *p1 == ';') /* end of cookie */
3132 break;
3133
3134 /* p1 is at the beginning of the cookie name */
3135 p2 = p1;
3136
3137 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3138 p2++;
3139
3140 if (p2 == ptr || *p2 == ';') /* next cookie */
3141 break;
3142
3143 p3 = p2 + 1; /* skips the '=' sign */
3144 if (p3 == ptr)
3145 break;
3146
3147 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003148 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003149 p4++;
3150
3151 /* here, we have the cookie name between p1 and p2,
3152 * and its value between p3 and p4.
3153 * we can process it.
3154 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003155
3156 /* first, let's see if we want to capture it */
3157 if (t->proxy->capture_name != NULL &&
3158 t->logs.srv_cookie == NULL &&
3159 (p4 - p1 >= t->proxy->capture_namelen) &&
3160 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3161 int log_len = p4 - p1;
3162
3163 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3164 Alert("HTTP logging : out of memory.\n");
3165 }
3166
3167 if (log_len > t->proxy->capture_len)
3168 log_len = t->proxy->capture_len;
3169 memcpy(t->logs.srv_cookie, p1, log_len);
3170 t->logs.srv_cookie[log_len] = 0;
3171 }
3172
3173 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3174 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003175 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003176 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003177
3178 /* If the cookie is in insert mode on a known server, we'll delete
3179 * this occurrence because we'll insert another one later.
3180 * We'll delete it too if the "indirect" option is set and we're in
3181 * a direct access. */
3182 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003183 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003184 /* this header must be deleted */
3185 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003186 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003187 }
3188 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3189 /* replace bytes p3->p4 with the cookie name associated
3190 * with this server since we know it.
3191 */
3192 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003193 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003194 }
3195 break;
3196 }
3197 else {
3198 // fprintf(stderr,"Ignoring unknown cookie : ");
3199 // write(2, p1, p2-p1);
3200 // fprintf(stderr," = ");
3201 // write(2, p3, p4-p3);
3202 // fprintf(stderr,"\n");
3203 }
3204 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3205 } /* we're now at the end of the cookie value */
3206 } /* end of cookie processing */
3207
3208 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003209 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003210 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003211
willy tarreau5cbea6f2005-12-17 12:48:26 +01003212 rep->h = rep->lr;
3213 } /* while (rep->lr < rep->r) */
3214
3215 /* end of header processing (even if incomplete) */
3216
willy tarreauef900ab2005-12-17 12:52:52 +01003217 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3218 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3219 * full. We cannot loop here since event_srv_read will disable it only if
3220 * rep->l == rlim-data
3221 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003222 FD_SET(t->srv_fd, StaticReadEvent);
3223 if (t->proxy->srvtimeout)
3224 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3225 else
3226 tv_eternity(&t->srexpire);
3227 }
willy tarreau0f7af912005-12-17 12:21:26 +01003228
willy tarreau8337c6b2005-12-17 13:41:01 +01003229 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003230 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003231 tv_eternity(&t->srexpire);
3232 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003233 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003234 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003235 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003236 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003237 if (!(t->flags & SN_ERR_MASK))
3238 t->flags |= SN_ERR_SRVCL;
3239 if (!(t->flags & SN_FINST_MASK))
3240 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003241 return 1;
3242 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003243 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003244 * since we are in header mode, if there's no space left for headers, we
3245 * won't be able to free more later, so the session will never terminate.
3246 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003247 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 +01003248 FD_CLR(t->srv_fd, StaticReadEvent);
3249 tv_eternity(&t->srexpire);
3250 shutdown(t->srv_fd, SHUT_RD);
3251 t->srv_state = SV_STSHUTR;
3252 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003253 }
3254 /* read timeout : return a 504 to the client.
3255 */
3256 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3257 tv_eternity(&t->srexpire);
3258 tv_eternity(&t->swexpire);
3259 fd_delete(t->srv_fd);
3260 t->srv_state = SV_STCLOSE;
3261 t->logs.status = 504;
3262 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003263 if (!(t->flags & SN_ERR_MASK))
3264 t->flags |= SN_ERR_SRVTO;
3265 if (!(t->flags & SN_FINST_MASK))
3266 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003267 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003268
3269 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003270 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003271 /* FIXME!!! here, we don't want to switch to SHUTW if the
3272 * client shuts read too early, because we may still have
3273 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01003274 * The side-effect is that if the client completely closes its
3275 * connection during SV_STHEADER, the connection to the server
3276 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01003277 */
willy tarreau036e1ce2005-12-17 13:46:33 +01003278 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003279 FD_CLR(t->srv_fd, StaticWriteEvent);
3280 tv_eternity(&t->swexpire);
3281 shutdown(t->srv_fd, SHUT_WR);
3282 t->srv_state = SV_STSHUTW;
3283 return 1;
3284 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003285 /* write timeout */
3286 /* FIXME!!! here, we don't want to switch to SHUTW if the
3287 * client shuts read too early, because we may still have
3288 * some work to do on the headers.
3289 */
3290 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3291 FD_CLR(t->srv_fd, StaticWriteEvent);
3292 tv_eternity(&t->swexpire);
3293 shutdown(t->srv_fd, SHUT_WR);
3294 t->srv_state = SV_STSHUTW;
3295 if (!(t->flags & SN_ERR_MASK))
3296 t->flags |= SN_ERR_SRVTO;
3297 if (!(t->flags & SN_FINST_MASK))
3298 t->flags |= SN_FINST_H;
3299 return 1;
3300 }
willy tarreau0f7af912005-12-17 12:21:26 +01003301
3302 if (req->l == 0) {
3303 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3304 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3305 tv_eternity(&t->swexpire);
3306 }
3307 }
3308 else { /* client buffer not empty */
3309 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3310 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3311 if (t->proxy->srvtimeout)
3312 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3313 else
3314 tv_eternity(&t->swexpire);
3315 }
3316 }
3317
willy tarreau5cbea6f2005-12-17 12:48:26 +01003318 /* be nice with the client side which would like to send a complete header
3319 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3320 * would read all remaining data at once ! The client should not write past rep->lr
3321 * when the server is in header state.
3322 */
3323 //return header_processed;
3324 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003325 }
3326 else if (s == SV_STDATA) {
3327 /* read or write error */
3328 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003329 tv_eternity(&t->srexpire);
3330 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003331 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003332 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003333 if (!(t->flags & SN_ERR_MASK))
3334 t->flags |= SN_ERR_SRVCL;
3335 if (!(t->flags & SN_FINST_MASK))
3336 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003337 return 1;
3338 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003339 /* last read, or end of client write */
3340 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003341 FD_CLR(t->srv_fd, StaticReadEvent);
3342 tv_eternity(&t->srexpire);
3343 shutdown(t->srv_fd, SHUT_RD);
3344 t->srv_state = SV_STSHUTR;
3345 return 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003346 }
3347 /* read timeout */
3348 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3349 FD_CLR(t->srv_fd, StaticReadEvent);
3350 tv_eternity(&t->srexpire);
3351 shutdown(t->srv_fd, SHUT_RD);
3352 t->srv_state = SV_STSHUTR;
3353 if (!(t->flags & SN_ERR_MASK))
3354 t->flags |= SN_ERR_SRVTO;
3355 if (!(t->flags & SN_FINST_MASK))
3356 t->flags |= SN_FINST_D;
3357 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003358 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003359 /* write timeout */
3360 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003361 FD_CLR(t->srv_fd, StaticWriteEvent);
3362 tv_eternity(&t->swexpire);
3363 shutdown(t->srv_fd, SHUT_WR);
3364 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01003365 if (!(t->flags & SN_ERR_MASK))
3366 t->flags |= SN_ERR_SRVTO;
3367 if (!(t->flags & SN_FINST_MASK))
3368 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003369 return 1;
3370 }
3371 else if (req->l == 0) {
3372 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3373 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3374 tv_eternity(&t->swexpire);
3375 }
3376 }
3377 else { /* buffer not empty */
3378 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3379 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3380 if (t->proxy->srvtimeout)
3381 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3382 else
3383 tv_eternity(&t->swexpire);
3384 }
3385 }
3386
3387 if (rep->l == BUFSIZE) { /* no room to read more data */
3388 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3389 FD_CLR(t->srv_fd, StaticReadEvent);
3390 tv_eternity(&t->srexpire);
3391 }
3392 }
3393 else {
3394 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3395 FD_SET(t->srv_fd, StaticReadEvent);
3396 if (t->proxy->srvtimeout)
3397 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3398 else
3399 tv_eternity(&t->srexpire);
3400 }
3401 }
3402
3403 return 0; /* other cases change nothing */
3404 }
3405 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003406 if (t->res_sw == RES_ERROR) {
3407 //FD_CLR(t->srv_fd, StaticWriteEvent);
3408 tv_eternity(&t->swexpire);
3409 fd_delete(t->srv_fd);
3410 //close(t->srv_fd);
3411 t->srv_state = SV_STCLOSE;
3412 if (!(t->flags & SN_ERR_MASK))
3413 t->flags |= SN_ERR_SRVCL;
3414 if (!(t->flags & SN_FINST_MASK))
3415 t->flags |= SN_FINST_D;
3416 return 1;
3417 }
3418 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003419 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003420 tv_eternity(&t->swexpire);
3421 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003422 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003423 t->srv_state = SV_STCLOSE;
3424 return 1;
3425 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003426 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3427 //FD_CLR(t->srv_fd, StaticWriteEvent);
3428 tv_eternity(&t->swexpire);
3429 fd_delete(t->srv_fd);
3430 //close(t->srv_fd);
3431 t->srv_state = SV_STCLOSE;
3432 if (!(t->flags & SN_ERR_MASK))
3433 t->flags |= SN_ERR_SRVTO;
3434 if (!(t->flags & SN_FINST_MASK))
3435 t->flags |= SN_FINST_D;
3436 return 1;
3437 }
willy tarreau0f7af912005-12-17 12:21:26 +01003438 else if (req->l == 0) {
3439 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3440 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3441 tv_eternity(&t->swexpire);
3442 }
3443 }
3444 else { /* buffer not empty */
3445 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3446 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3447 if (t->proxy->srvtimeout)
3448 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3449 else
3450 tv_eternity(&t->swexpire);
3451 }
3452 }
3453 return 0;
3454 }
3455 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003456 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003457 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003458 tv_eternity(&t->srexpire);
3459 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003460 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003461 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003462 if (!(t->flags & SN_ERR_MASK))
3463 t->flags |= SN_ERR_SRVCL;
3464 if (!(t->flags & SN_FINST_MASK))
3465 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003466 return 1;
3467 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003468 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
3469 //FD_CLR(t->srv_fd, StaticReadEvent);
3470 tv_eternity(&t->srexpire);
3471 fd_delete(t->srv_fd);
3472 //close(t->srv_fd);
3473 t->srv_state = SV_STCLOSE;
3474 return 1;
3475 }
3476 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3477 //FD_CLR(t->srv_fd, StaticReadEvent);
3478 tv_eternity(&t->srexpire);
3479 fd_delete(t->srv_fd);
3480 //close(t->srv_fd);
3481 t->srv_state = SV_STCLOSE;
3482 if (!(t->flags & SN_ERR_MASK))
3483 t->flags |= SN_ERR_SRVTO;
3484 if (!(t->flags & SN_FINST_MASK))
3485 t->flags |= SN_FINST_D;
3486 return 1;
3487 }
willy tarreau0f7af912005-12-17 12:21:26 +01003488 else if (rep->l == BUFSIZE) { /* no room to read more data */
3489 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3490 FD_CLR(t->srv_fd, StaticReadEvent);
3491 tv_eternity(&t->srexpire);
3492 }
3493 }
3494 else {
3495 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3496 FD_SET(t->srv_fd, StaticReadEvent);
3497 if (t->proxy->srvtimeout)
3498 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3499 else
3500 tv_eternity(&t->srexpire);
3501 }
3502 }
3503 return 0;
3504 }
3505 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003506 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003507 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003508 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003509 write(1, trash, len);
3510 }
3511 return 0;
3512 }
3513 return 0;
3514}
3515
3516
willy tarreau5cbea6f2005-12-17 12:48:26 +01003517/* Processes the client and server jobs of a session task, then
3518 * puts it back to the wait queue in a clean state, or
3519 * cleans up its resources if it must be deleted. Returns
3520 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003521 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003522int process_session(struct task *t) {
3523 struct session *s = t->context;
3524 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003525
willy tarreau5cbea6f2005-12-17 12:48:26 +01003526 do {
3527 fsm_resync = 0;
3528 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3529 fsm_resync |= process_cli(s);
3530 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3531 fsm_resync |= process_srv(s);
3532 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3533 } while (fsm_resync);
3534
3535 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003536 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003537 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003538
willy tarreau5cbea6f2005-12-17 12:48:26 +01003539 tv_min(&min1, &s->crexpire, &s->cwexpire);
3540 tv_min(&min2, &s->srexpire, &s->swexpire);
3541 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003542 tv_min(&t->expire, &min1, &min2);
3543
3544 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003545 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003546
willy tarreau5cbea6f2005-12-17 12:48:26 +01003547 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003548 }
3549
willy tarreau5cbea6f2005-12-17 12:48:26 +01003550 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003551 actconn--;
3552
willy tarreau9fe663a2005-12-17 13:02:59 +01003553 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003554 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003555 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003556 write(1, trash, len);
3557 }
3558
willy tarreau750a4722005-12-17 13:21:24 +01003559 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003560 if (s->rep != NULL)
3561 s->logs.bytes = s->rep->total;
3562
willy tarreau9fe663a2005-12-17 13:02:59 +01003563 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003564 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003565 sess_log(s);
3566
willy tarreau0f7af912005-12-17 12:21:26 +01003567 /* the task MUST not be in the run queue anymore */
3568 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003569 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003570 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003571 return -1; /* rest in peace for eternity */
3572}
3573
3574
3575
3576/*
3577 * manages a server health-check. Returns
3578 * the time the task accepts to wait, or -1 for infinity.
3579 */
3580int process_chk(struct task *t) {
3581 struct server *s = t->context;
3582 int fd = s->curfd;
3583 int one = 1;
3584
willy tarreauef900ab2005-12-17 12:52:52 +01003585 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003586
3587 if (fd < 0) { /* no check currently running */
3588 //fprintf(stderr, "process_chk: 2\n");
3589 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3590 task_queue(t); /* restore t to its place in the task list */
3591 return tv_remain(&now, &t->expire);
3592 }
3593
3594 /* we'll initiate a new check */
3595 s->result = 0; /* no result yet */
3596 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003597 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003598 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3599 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3600 //fprintf(stderr, "process_chk: 3\n");
3601
willy tarreau036e1ce2005-12-17 13:46:33 +01003602 /* allow specific binding */
3603 if (s->proxy->options & PR_O_BIND_SRC &&
3604 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
3605 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
3606 close(fd);
3607 s->result = -1;
3608 }
3609 else if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003610 /* OK, connection in progress or established */
3611
3612 //fprintf(stderr, "process_chk: 4\n");
3613
3614 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3615 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003616 fdtab[fd].read = &event_srv_chk_r;
3617 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003618 fdtab[fd].state = FD_STCONN; /* connection in progress */
3619 FD_SET(fd, StaticWriteEvent); /* for connect status */
3620 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003621 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3622 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003623 task_queue(t); /* restore t to its place in the task list */
3624 return tv_remain(&now, &t->expire);
3625 }
3626 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3627 s->result = -1; /* a real error */
3628 }
3629 }
3630 //fprintf(stderr, "process_chk: 5\n");
3631 close(fd);
3632 }
3633
3634 if (!s->result) { /* nothing done */
3635 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003636 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003637 task_queue(t); /* restore t to its place in the task list */
3638 return tv_remain(&now, &t->expire);
3639 }
3640
3641 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003642 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003643 s->health--; /* still good */
3644 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003645 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003646 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003647 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003648
willy tarreau9fe663a2005-12-17 13:02:59 +01003649 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003650 }
willy tarreauef900ab2005-12-17 12:52:52 +01003651
willy tarreau5cbea6f2005-12-17 12:48:26 +01003652 s->health = 0; /* failure */
3653 s->state &= ~SRV_RUNNING;
3654 }
3655
3656 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003657 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3658 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003659 }
3660 else {
3661 //fprintf(stderr, "process_chk: 8\n");
3662 /* there was a test running */
3663 if (s->result > 0) { /* good server detected */
3664 //fprintf(stderr, "process_chk: 9\n");
3665 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003666 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003667 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003668 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003669 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003670 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003671 }
willy tarreauef900ab2005-12-17 12:52:52 +01003672
willy tarreaue47c8d72005-12-17 12:55:52 +01003673 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003674 s->state |= SRV_RUNNING;
3675 }
willy tarreauef900ab2005-12-17 12:52:52 +01003676 s->curfd = -1; /* no check running anymore */
3677 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003678 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003679 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003680 }
3681 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3682 //fprintf(stderr, "process_chk: 10\n");
3683 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003684 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003685 s->health--; /* still good */
3686 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003687 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003688 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003689 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003690
3691 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003692 }
willy tarreauef900ab2005-12-17 12:52:52 +01003693
willy tarreau5cbea6f2005-12-17 12:48:26 +01003694 s->health = 0; /* failure */
3695 s->state &= ~SRV_RUNNING;
3696 }
3697 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003698 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003699 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003700 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003701 }
3702 /* if result is 0 and there's no timeout, we have to wait again */
3703 }
3704 //fprintf(stderr, "process_chk: 11\n");
3705 s->result = 0;
3706 task_queue(t); /* restore t to its place in the task list */
3707 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003708}
3709
3710
willy tarreau5cbea6f2005-12-17 12:48:26 +01003711
willy tarreau0f7af912005-12-17 12:21:26 +01003712#if STATTIME > 0
3713int stats(void);
3714#endif
3715
3716/*
3717 * Main select() loop.
3718 */
3719
3720void select_loop() {
3721 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003722 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003723 int status;
3724 int fd,i;
3725 struct timeval delta;
3726 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003727 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003728
willy tarreau5cbea6f2005-12-17 12:48:26 +01003729 tv_now(&now);
3730
3731 while (1) {
3732 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003733
willy tarreau5cbea6f2005-12-17 12:48:26 +01003734 /* look for expired tasks and add them to the run queue.
3735 */
3736 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3737 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3738 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003739 if (t->state & TASK_RUNNING)
3740 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003741
3742 /* wakeup expired entries. It doesn't matter if they are
3743 * already running because of a previous event
3744 */
3745 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003746 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003747 task_wakeup(&rq, t);
3748 }
3749 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003750 /* first non-runnable task. Use its expiration date as an upper bound */
3751 int temp_time = tv_remain(&now, &t->expire);
3752 if (temp_time)
3753 next_time = temp_time;
3754 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003755 break;
3756 }
3757 }
3758
3759 /* process each task in the run queue now. Each task may be deleted
3760 * since we only use tnext.
3761 */
3762 tnext = rq;
3763 while ((t = tnext) != NULL) {
3764 int temp_time;
3765
3766 tnext = t->rqnext;
3767 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003768 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003769 temp_time = t->process(t);
3770 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003771 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003772 }
3773
willy tarreauef900ab2005-12-17 12:52:52 +01003774 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003775
3776 /* maintain all proxies in a consistent state. This should quickly become a task */
3777 time2 = maintain_proxies();
3778 next_time = MINTIME(time2, next_time);
3779
3780 /* stop when there's no connection left and we don't allow them anymore */
3781 if (!actconn && listeners == 0)
3782 break;
3783
willy tarreau0f7af912005-12-17 12:21:26 +01003784
3785#if STATTIME > 0
3786 time2 = stats();
3787 // fprintf(stderr," stats = %d\n", time2);
3788 next_time = MINTIME(time2, next_time);
3789#endif
3790
willy tarreau5cbea6f2005-12-17 12:48:26 +01003791 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003792 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003793 /* to avoid eventual select loops due to timer precision */
3794 next_time += SCHEDULER_RESOLUTION;
3795 delta.tv_sec = next_time / 1000;
3796 delta.tv_usec = (next_time % 1000) * 1000;
3797 }
3798 else if (next_time == 0) { /* allow select to return immediately when needed */
3799 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003800 }
3801
3802
3803 /* let's restore fdset state */
3804
3805 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003806 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003807 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3808 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3809 }
3810
3811// /* just a verification code, needs to be removed for performance */
3812// for (i=0; i<maxfd; i++) {
3813// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3814// abort();
3815// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3816// abort();
3817//
3818// }
3819
3820 status=select(maxfd,
3821 readnotnull ? ReadEvent : NULL,
3822 writenotnull ? WriteEvent : NULL,
3823 NULL,
3824 (next_time >= 0) ? &delta : NULL);
3825
willy tarreau5cbea6f2005-12-17 12:48:26 +01003826 /* this is an experiment on the separation of the select work */
3827 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3828 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3829
willy tarreau0f7af912005-12-17 12:21:26 +01003830 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003831
willy tarreau0f7af912005-12-17 12:21:26 +01003832 if (status > 0) { /* must proceed with events */
3833
3834 int fds;
3835 char count;
3836
3837 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3838 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3839 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3840
willy tarreau5cbea6f2005-12-17 12:48:26 +01003841 /* if we specify read first, the accepts and zero reads will be
3842 * seen first. Moreover, system buffers will be flushed faster.
3843 */
willy tarreau0f7af912005-12-17 12:21:26 +01003844 if (fdtab[fd].state == FD_STCLOSE)
3845 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003846
3847 if (FD_ISSET(fd, ReadEvent))
3848 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003849
willy tarreau5cbea6f2005-12-17 12:48:26 +01003850 if (FD_ISSET(fd, WriteEvent))
3851 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003852 }
3853 }
3854 else {
3855 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3856 }
willy tarreau0f7af912005-12-17 12:21:26 +01003857 }
3858}
3859
3860
3861#if STATTIME > 0
3862/*
3863 * Display proxy statistics regularly. It is designed to be called from the
3864 * select_loop().
3865 */
3866int stats(void) {
3867 static int lines;
3868 static struct timeval nextevt;
3869 static struct timeval lastevt;
3870 static struct timeval starttime = {0,0};
3871 unsigned long totaltime, deltatime;
3872 int ret;
3873
willy tarreau750a4722005-12-17 13:21:24 +01003874 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01003875 deltatime = (tv_diff(&lastevt, &now)?:1);
3876 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01003877
willy tarreau9fe663a2005-12-17 13:02:59 +01003878 if (global.mode & MODE_STATS) {
3879 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003880 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003881 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3882 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003883 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003884 actconn, totalconn,
3885 stats_tsk_new, stats_tsk_good,
3886 stats_tsk_left, stats_tsk_right,
3887 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3888 }
3889 }
3890
3891 tv_delayfrom(&nextevt, &now, STATTIME);
3892
3893 lastevt=now;
3894 }
3895 ret = tv_remain(&now, &nextevt);
3896 return ret;
3897}
3898#endif
3899
3900
3901/*
3902 * this function enables proxies when there are enough free sessions,
3903 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003904 * select_loop(). It returns the time left before next expiration event
3905 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003906 */
3907static int maintain_proxies(void) {
3908 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003910
3911 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003912 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003913
3914 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003915 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003916 while (p) {
3917 if (p->nbconn < p->maxconn) {
3918 if (p->state == PR_STIDLE) {
3919 FD_SET(p->listen_fd, StaticReadEvent);
3920 p->state = PR_STRUN;
3921 }
3922 }
3923 else {
3924 if (p->state == PR_STRUN) {
3925 FD_CLR(p->listen_fd, StaticReadEvent);
3926 p->state = PR_STIDLE;
3927 }
3928 }
3929 p = p->next;
3930 }
3931 }
3932 else { /* block all proxies */
3933 while (p) {
3934 if (p->state == PR_STRUN) {
3935 FD_CLR(p->listen_fd, StaticReadEvent);
3936 p->state = PR_STIDLE;
3937 }
3938 p = p->next;
3939 }
3940 }
3941
willy tarreau5cbea6f2005-12-17 12:48:26 +01003942 if (stopping) {
3943 p = proxy;
3944 while (p) {
3945 if (p->state != PR_STDISABLED) {
3946 int t;
3947 t = tv_remain(&now, &p->stop_time);
3948 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003949 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003950 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003951
willy tarreau5cbea6f2005-12-17 12:48:26 +01003952 fd_delete(p->listen_fd);
3953 p->state = PR_STDISABLED;
3954 listeners--;
3955 }
3956 else {
3957 tleft = MINTIME(t, tleft);
3958 }
3959 }
3960 p = p->next;
3961 }
3962 }
3963 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003964}
3965
3966/*
3967 * this function disables health-check servers so that the process will quickly be ignored
3968 * by load balancers.
3969 */
3970static void soft_stop(void) {
3971 struct proxy *p;
3972
3973 stopping = 1;
3974 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003975 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003976 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003977 if (p->state != PR_STDISABLED) {
3978 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01003979 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01003980 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01003981 }
willy tarreau0f7af912005-12-17 12:21:26 +01003982 p = p->next;
3983 }
3984}
3985
3986/*
3987 * upon SIGUSR1, let's have a soft stop.
3988 */
3989void sig_soft_stop(int sig) {
3990 soft_stop();
3991 signal(sig, SIG_IGN);
3992}
3993
3994
willy tarreau8337c6b2005-12-17 13:41:01 +01003995/*
3996 * this function dumps every server's state when the process receives SIGHUP.
3997 */
3998void sig_dump_state(int sig) {
3999 struct proxy *p = proxy;
4000
4001 Warning("SIGHUP received, dumping servers states.\n");
4002 while (p) {
4003 struct server *s = p->srv;
4004
4005 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4006 while (s) {
4007 if (s->state & SRV_RUNNING) {
4008 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4009 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4010 }
4011 else {
4012 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4013 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4014 }
4015 s = s->next;
4016 }
4017 p = p->next;
4018 }
4019 signal(sig, sig_dump_state);
4020}
4021
willy tarreau0f7af912005-12-17 12:21:26 +01004022void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004023 struct task *t, *tnext;
4024 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004025
willy tarreau5cbea6f2005-12-17 12:48:26 +01004026 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4027 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4028 tnext = t->next;
4029 s = t->context;
4030 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4031 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4032 "req=%d, rep=%d, clifd=%d\n",
4033 s, tv_remain(&now, &t->expire),
4034 s->cli_state,
4035 s->srv_state,
4036 FD_ISSET(s->cli_fd, StaticReadEvent),
4037 FD_ISSET(s->cli_fd, StaticWriteEvent),
4038 FD_ISSET(s->srv_fd, StaticReadEvent),
4039 FD_ISSET(s->srv_fd, StaticWriteEvent),
4040 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4041 );
willy tarreau0f7af912005-12-17 12:21:26 +01004042 }
4043}
4044
willy tarreaue39cd132005-12-17 13:00:18 +01004045void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4046 struct hdr_exp *exp;
4047
4048 while (*head != NULL)
4049 head = &(*head)->next;
4050
4051 exp = calloc(1, sizeof(struct hdr_exp));
4052
4053 exp->preg = preg;
4054 exp->replace = replace;
4055 exp->action = action;
4056 *head = exp;
4057}
4058
willy tarreau9fe663a2005-12-17 13:02:59 +01004059
willy tarreau0f7af912005-12-17 12:21:26 +01004060/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004061 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004062 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004063int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004064
willy tarreau9fe663a2005-12-17 13:02:59 +01004065 if (!strcmp(args[0], "global")) { /* new section */
4066 /* no option, nothing special to do */
4067 return 0;
4068 }
4069 else if (!strcmp(args[0], "daemon")) {
4070 global.mode |= MODE_DAEMON;
4071 }
4072 else if (!strcmp(args[0], "debug")) {
4073 global.mode |= MODE_DEBUG;
4074 }
4075 else if (!strcmp(args[0], "quiet")) {
4076 global.mode |= MODE_QUIET;
4077 }
4078 else if (!strcmp(args[0], "stats")) {
4079 global.mode |= MODE_STATS;
4080 }
4081 else if (!strcmp(args[0], "uid")) {
4082 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004083 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004084 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004085 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004086 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004087 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004088 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004089 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004090 global.uid = atol(args[1]);
4091 }
4092 else if (!strcmp(args[0], "gid")) {
4093 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004094 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004095 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004096 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004097 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004098 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004099 return -1;
4100 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004101 global.gid = atol(args[1]);
4102 }
4103 else if (!strcmp(args[0], "nbproc")) {
4104 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004105 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004106 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004107 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004108 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004109 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004110 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004111 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004112 global.nbproc = atol(args[1]);
4113 }
4114 else if (!strcmp(args[0], "maxconn")) {
4115 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004116 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004117 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004118 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004119 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004120 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004121 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004122 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004123 global.maxconn = atol(args[1]);
4124 }
4125 else if (!strcmp(args[0], "chroot")) {
4126 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004127 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004128 return 0;
4129 }
4130 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004131 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004132 return -1;
4133 }
4134 global.chroot = strdup(args[1]);
4135 }
4136 else if (!strcmp(args[0], "log")) { /* syslog server address */
4137 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004138 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004139
4140 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004141 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004142 return -1;
4143 }
4144
4145 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4146 if (!strcmp(log_facilities[facility], args[2]))
4147 break;
4148
4149 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004150 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004151 exit(1);
4152 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004153
4154 level = 7; /* max syslog level = debug */
4155 if (*(args[3])) {
4156 while (level >= 0 && strcmp(log_levels[level], args[3]))
4157 level--;
4158 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004159 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004160 exit(1);
4161 }
4162 }
4163
willy tarreau9fe663a2005-12-17 13:02:59 +01004164 sa = str2sa(args[1]);
4165 if (!sa->sin_port)
4166 sa->sin_port = htons(SYSLOG_PORT);
4167
4168 if (global.logfac1 == -1) {
4169 global.logsrv1 = *sa;
4170 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004171 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004172 }
4173 else if (global.logfac2 == -1) {
4174 global.logsrv2 = *sa;
4175 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004176 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004177 }
4178 else {
4179 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4180 return -1;
4181 }
4182
4183 }
4184 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004185 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004186 return -1;
4187 }
4188 return 0;
4189}
4190
4191
4192/*
4193 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4194 */
4195int cfg_parse_listen(char *file, int linenum, char **args) {
4196 static struct proxy *curproxy = NULL;
4197 struct server *newsrv = NULL;
4198
4199 if (!strcmp(args[0], "listen")) { /* new proxy */
4200 if (strchr(args[2], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004201 Alert("parsing [%s:%d] : '%s' expects <id> and <addr:port> as arguments.\n",
4202 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004203 return -1;
4204 }
4205
4206 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004207 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004208 return -1;
4209 }
4210 curproxy->next = proxy;
4211 proxy = curproxy;
4212 curproxy->id = strdup(args[1]);
4213 curproxy->listen_addr = *str2sa(args[2]);
4214 curproxy->state = PR_STNEW;
4215 /* set default values */
4216 curproxy->maxconn = cfg_maxpconn;
4217 curproxy->conn_retries = CONN_RETRIES;
4218 curproxy->options = 0;
4219 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
4220 curproxy->mode = PR_MODE_TCP;
4221 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
4222 curproxy->to_log = 0;
4223 return 0;
4224 }
4225 else if (curproxy == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004226 Alert("parsing [%s:%d] : 'listen' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004227 return -1;
4228 }
4229
4230 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
4231 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
4232 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
4233 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
4234 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004235 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004236 return -1;
4237 }
4238 }
4239 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
4240 curproxy->state = PR_STDISABLED;
4241 }
4242 else if (!strcmp(args[0], "cookie")) { /* cookie name */
4243 int cur_arg;
4244 if (curproxy->cookie_name != NULL) {
4245 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
4246 file, linenum);
4247 return 0;
4248 }
4249
4250 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004251 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
4252 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004253 return -1;
4254 }
4255 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004256 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004257
4258 cur_arg = 2;
4259 while (*(args[cur_arg])) {
4260 if (!strcmp(args[cur_arg], "rewrite")) {
4261 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01004262 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004263 else if (!strcmp(args[cur_arg], "indirect")) {
4264 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01004265 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004266 else if (!strcmp(args[cur_arg], "insert")) {
4267 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01004268 }
willy tarreau240afa62005-12-17 13:14:35 +01004269 else if (!strcmp(args[cur_arg], "nocache")) {
4270 curproxy->options |= PR_O_COOK_NOC;
4271 }
willy tarreaucd878942005-12-17 13:27:43 +01004272 else if (!strcmp(args[cur_arg], "postonly")) {
4273 curproxy->options |= PR_O_COOK_POST;
4274 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004275 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004276 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
4277 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004278 return -1;
4279 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004280 cur_arg++;
4281 }
4282 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004283 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatibles.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004284 file, linenum);
4285 return -1;
4286 }
4287 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004288 else if (!strcmp(args[0], "capture")) { /* name of a cookie to capture */
4289 if (curproxy->capture_name != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004290 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4291 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004292 return 0;
4293 }
4294
4295 if (*(args[4]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004296 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
4297 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004298 return -1;
4299 }
4300 curproxy->capture_name = strdup(args[2]);
4301 curproxy->capture_namelen = strlen(curproxy->capture_name);
4302 curproxy->capture_len = atol(args[4]);
4303 if (curproxy->capture_len >= CAPTURE_LEN) {
4304 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
4305 file, linenum, CAPTURE_LEN - 1);
4306 curproxy->capture_len = CAPTURE_LEN - 1;
4307 }
4308 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004309 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
4310 if (curproxy->contimeout != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004311 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004312 return 0;
4313 }
4314 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004315 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4316 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004317 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004318 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004319 curproxy->contimeout = atol(args[1]);
4320 }
4321 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
4322 if (curproxy->clitimeout != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004323 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4324 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004325 return 0;
4326 }
4327 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004328 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4329 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004330 return -1;
4331 }
4332 curproxy->clitimeout = atol(args[1]);
4333 }
4334 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
4335 if (curproxy->srvtimeout != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004336 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004337 return 0;
4338 }
4339 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004340 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4341 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004342 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004343 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004344 curproxy->srvtimeout = atol(args[1]);
4345 }
4346 else if (!strcmp(args[0], "retries")) { /* connection retries */
4347 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004348 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
4349 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004350 return -1;
4351 }
4352 curproxy->conn_retries = atol(args[1]);
4353 }
4354 else if (!strcmp(args[0], "option")) {
4355 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004356 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004357 return -1;
4358 }
4359 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004360 /* enable reconnections to dispatch */
4361 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004362#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004363 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004364 /* enable transparent proxy connections */
4365 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004366#endif
4367 else if (!strcmp(args[1], "keepalive"))
4368 /* enable keep-alive */
4369 curproxy->options |= PR_O_KEEPALIVE;
4370 else if (!strcmp(args[1], "forwardfor"))
4371 /* insert x-forwarded-for field */
4372 curproxy->options |= PR_O_FWDFOR;
4373 else if (!strcmp(args[1], "httplog")) {
4374 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01004375 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
4376 }
4377 else if (!strcmp(args[1], "dontlognull")) {
4378 /* don't log empty requests */
4379 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004380 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004381 else if (!strcmp(args[1], "httpchk")) {
4382 /* use HTTP request to check servers' health */
4383 curproxy->options |= PR_O_HTTP_CHK;
4384 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004385 else if (!strcmp(args[1], "persist")) {
4386 /* persist on using the server specified by the cookie, even when it's down */
4387 curproxy->options |= PR_O_PERSIST;
4388 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004389 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004390 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004391 return -1;
4392 }
4393 return 0;
4394 }
4395 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4396 /* enable reconnections to dispatch */
4397 curproxy->options |= PR_O_REDISP;
4398 }
willy tarreaua1598082005-12-17 13:08:06 +01004399#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004400 else if (!strcmp(args[0], "transparent")) {
4401 /* enable transparent proxy connections */
4402 curproxy->options |= PR_O_TRANSP;
4403 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004404#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004405 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4406 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004407 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004408 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004409 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004410 curproxy->maxconn = atol(args[1]);
4411 }
4412 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4413 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004414 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004415 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004416 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004417 curproxy->grace = atol(args[1]);
4418 }
4419 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
4420 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004421 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004422 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004423 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004424 curproxy->dispatch_addr = *str2sa(args[1]);
4425 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004426 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01004427 if (*(args[1])) {
4428 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004429 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004430 }
4431 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004432 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004433 return -1;
4434 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004435 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004436 else /* if no option is set, use round-robin by default */
4437 curproxy->options |= PR_O_BALANCE_RR;
4438 }
4439 else if (!strcmp(args[0], "server")) { /* server address */
4440 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004441
willy tarreau9fe663a2005-12-17 13:02:59 +01004442 if (strchr(args[2], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004443 Alert("parsing [%s:%d] : '%s' expects <name> and <addr:port> as arguments.\n",
4444 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004445 return -1;
4446 }
4447 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4448 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4449 return -1;
4450 }
4451 newsrv->next = curproxy->srv;
4452 curproxy->srv = newsrv;
4453 newsrv->proxy = curproxy;
4454 newsrv->id = strdup(args[1]);
4455 newsrv->addr = *str2sa(args[2]);
4456 newsrv->state = SRV_RUNNING; /* early server setup */
4457 newsrv->curfd = -1; /* no health-check in progress */
4458 newsrv->inter = DEF_CHKINTR;
4459 newsrv->rise = DEF_RISETIME;
4460 newsrv->fall = DEF_FALLTIME;
4461 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4462 cur_arg = 3;
4463 while (*args[cur_arg]) {
4464 if (!strcmp(args[cur_arg], "cookie")) {
4465 newsrv->cookie = strdup(args[cur_arg + 1]);
4466 newsrv->cklen = strlen(args[cur_arg + 1]);
4467 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004468 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004469 else if (!strcmp(args[cur_arg], "rise")) {
4470 newsrv->rise = atol(args[cur_arg + 1]);
4471 newsrv->health = newsrv->rise;
4472 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004473 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004474 else if (!strcmp(args[cur_arg], "fall")) {
4475 newsrv->fall = atol(args[cur_arg + 1]);
4476 cur_arg += 2;
4477 }
4478 else if (!strcmp(args[cur_arg], "inter")) {
4479 newsrv->inter = atol(args[cur_arg + 1]);
4480 cur_arg += 2;
4481 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004482 else if (!strcmp(args[cur_arg], "backup")) {
4483 newsrv->state |= SRV_BACKUP;
4484 cur_arg ++;
4485 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004486 else if (!strcmp(args[cur_arg], "check")) {
4487 struct task *t;
4488
4489 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
4490 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004491 return -1;
4492 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004493
4494 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4495 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4496 t->state = TASK_IDLE;
4497 t->process = process_chk;
4498 t->context = newsrv;
4499
4500 if (curproxy->state != PR_STDISABLED) {
4501 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4502 task_queue(t);
4503 task_wakeup(&rq, t);
4504 }
4505
4506 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004507 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004508 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004509 Alert("parsing [%s:%d] : server %s only supports options 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004510 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004511 return -1;
4512 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004513 }
4514 curproxy->nbservers++;
4515 }
4516 else if (!strcmp(args[0], "log")) { /* syslog server address */
4517 struct sockaddr_in *sa;
4518 int facility;
4519
4520 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4521 curproxy->logfac1 = global.logfac1;
4522 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004523 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004524 curproxy->logfac2 = global.logfac2;
4525 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01004526 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01004527 }
4528 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01004529 int level;
4530
willy tarreau0f7af912005-12-17 12:21:26 +01004531 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4532 if (!strcmp(log_facilities[facility], args[2]))
4533 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004534
willy tarreau0f7af912005-12-17 12:21:26 +01004535 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004536 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01004537 exit(1);
4538 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004539
willy tarreau8337c6b2005-12-17 13:41:01 +01004540 level = 7; /* max syslog level = debug */
4541 if (*(args[3])) {
4542 while (level >= 0 && strcmp(log_levels[level], args[3]))
4543 level--;
4544 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004545 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004546 exit(1);
4547 }
4548 }
4549
willy tarreau0f7af912005-12-17 12:21:26 +01004550 sa = str2sa(args[1]);
4551 if (!sa->sin_port)
4552 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004553
willy tarreau0f7af912005-12-17 12:21:26 +01004554 if (curproxy->logfac1 == -1) {
4555 curproxy->logsrv1 = *sa;
4556 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004557 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004558 }
4559 else if (curproxy->logfac2 == -1) {
4560 curproxy->logsrv2 = *sa;
4561 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004562 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004563 }
4564 else {
4565 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004566 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004567 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004568 }
4569 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004570 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004571 file, linenum);
4572 return -1;
4573 }
4574 }
willy tarreaua1598082005-12-17 13:08:06 +01004575 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
4576 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004577 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n",
4578 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01004579 return -1;
4580 }
4581
4582 curproxy->source_addr = *str2sa(args[1]);
4583 curproxy->options |= PR_O_BIND_SRC;
4584 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004585 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4586 regex_t *preg;
4587
4588 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004589 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4590 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004591 return -1;
4592 }
4593
4594 preg = calloc(1, sizeof(regex_t));
4595 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004596 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004597 return -1;
4598 }
4599
4600 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4601 }
4602 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4603 regex_t *preg;
4604
4605 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004606 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004607 return -1;
4608 }
4609
4610 preg = calloc(1, sizeof(regex_t));
4611 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004612 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004613 return -1;
4614 }
4615
4616 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4617 }
4618 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
4619 regex_t *preg;
4620
4621 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004622 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004623 return -1;
4624 }
4625
4626 preg = calloc(1, sizeof(regex_t));
4627 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004628 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004629 return -1;
4630 }
4631
4632 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4633 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004634 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
4635 regex_t *preg;
4636
4637 if (*(args[1]) == 0) {
4638 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
4639 return -1;
4640 }
4641
4642 preg = calloc(1, sizeof(regex_t));
4643 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4644 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
4645 return -1;
4646 }
4647
4648 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
4649 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004650 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4651 regex_t *preg;
4652
4653 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004654 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004655 return -1;
4656 }
4657
4658 preg = calloc(1, sizeof(regex_t));
4659 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004660 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004661 return -1;
4662 }
4663
4664 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4665 }
4666 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4667 regex_t *preg;
4668
4669 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004670 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4671 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004672 return -1;
4673 }
4674
4675 preg = calloc(1, sizeof(regex_t));
4676 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004677 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004678 return -1;
4679 }
4680
4681 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4682 }
4683 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4684 regex_t *preg;
4685
4686 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004687 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004688 return -1;
4689 }
4690
4691 preg = calloc(1, sizeof(regex_t));
4692 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004693 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004694 return -1;
4695 }
4696
4697 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4698 }
4699 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4700 regex_t *preg;
4701
4702 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004703 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004704 return -1;
4705 }
4706
4707 preg = calloc(1, sizeof(regex_t));
4708 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004709 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004710 return -1;
4711 }
4712
4713 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4714 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004715 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
4716 regex_t *preg;
4717
4718 if (*(args[1]) == 0) {
4719 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
4720 return -1;
4721 }
4722
4723 preg = calloc(1, sizeof(regex_t));
4724 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4725 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
4726 return -1;
4727 }
4728
4729 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
4730 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004731 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4732 regex_t *preg;
4733
4734 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004735 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004736 return -1;
4737 }
4738
4739 preg = calloc(1, sizeof(regex_t));
4740 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004741 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004742 return -1;
4743 }
4744
4745 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4746 }
4747 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4748 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004749 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004750 return 0;
4751 }
4752
4753 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004754 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004755 return -1;
4756 }
4757
4758 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004759 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004760 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004761 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004762
4763 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004764 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4765 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004766 return -1;
4767 }
4768
4769 preg = calloc(1, sizeof(regex_t));
4770 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004771 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004772 return -1;
4773 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004774
4775 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4776 }
4777 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4778 regex_t *preg;
4779
4780 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004781 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004782 return -1;
4783 }
willy tarreaue39cd132005-12-17 13:00:18 +01004784
willy tarreau9fe663a2005-12-17 13:02:59 +01004785 preg = calloc(1, sizeof(regex_t));
4786 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004787 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004788 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004789 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004790
4791 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4792 }
4793 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004794 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004795
willy tarreau9fe663a2005-12-17 13:02:59 +01004796 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004797 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
4798 file, linenum, args[0]);
willy tarreaue39cd132005-12-17 13:00:18 +01004799 return -1;
4800 }
4801
4802 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004803 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004804 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreaue39cd132005-12-17 13:00:18 +01004805 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004806 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004807
4808 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4809 }
4810 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4811 regex_t *preg;
4812
4813 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004814 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004815 return -1;
4816 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004817
willy tarreau9fe663a2005-12-17 13:02:59 +01004818 preg = calloc(1, sizeof(regex_t));
4819 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004820 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004821 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004822 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004823
4824 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4825 }
4826 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4827 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004828 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004829 return 0;
4830 }
4831
4832 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004833 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004834 return -1;
4835 }
4836
4837 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4838 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004839 else if (!strcmp(args[0], "errorloc")) { /* error location */
4840 int errnum;
4841 char *err;
4842
4843 if (*(args[2]) == 0) {
4844 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
4845 return -1;
4846 }
4847
4848 errnum = atol(args[1]);
4849 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
4850 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
4851
4852 if (errnum == 400) {
4853 if (curproxy->errmsg.msg400) {
4854 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4855 free(curproxy->errmsg.msg400);
4856 }
4857 curproxy->errmsg.msg400 = err;
4858 curproxy->errmsg.len400 = strlen(err);
4859 }
4860 else if (errnum == 403) {
4861 if (curproxy->errmsg.msg403) {
4862 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4863 free(curproxy->errmsg.msg403);
4864 }
4865 curproxy->errmsg.msg403 = err;
4866 curproxy->errmsg.len403 = strlen(err);
4867 }
4868 else if (errnum == 408) {
4869 if (curproxy->errmsg.msg408) {
4870 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4871 free(curproxy->errmsg.msg408);
4872 }
4873 curproxy->errmsg.msg408 = err;
4874 curproxy->errmsg.len408 = strlen(err);
4875 }
4876 else if (errnum == 500) {
4877 if (curproxy->errmsg.msg500) {
4878 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4879 free(curproxy->errmsg.msg500);
4880 }
4881 curproxy->errmsg.msg500 = err;
4882 curproxy->errmsg.len500 = strlen(err);
4883 }
4884 else if (errnum == 502) {
4885 if (curproxy->errmsg.msg502) {
4886 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4887 free(curproxy->errmsg.msg502);
4888 }
4889 curproxy->errmsg.msg502 = err;
4890 curproxy->errmsg.len502 = strlen(err);
4891 }
4892 else if (errnum == 503) {
4893 if (curproxy->errmsg.msg503) {
4894 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4895 free(curproxy->errmsg.msg503);
4896 }
4897 curproxy->errmsg.msg503 = err;
4898 curproxy->errmsg.len503 = strlen(err);
4899 }
4900 else if (errnum == 504) {
4901 if (curproxy->errmsg.msg504) {
4902 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4903 free(curproxy->errmsg.msg504);
4904 }
4905 curproxy->errmsg.msg504 = err;
4906 curproxy->errmsg.len504 = strlen(err);
4907 }
4908 else {
4909 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
4910 free(err);
4911 }
4912 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004913 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004914 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01004915 return -1;
4916 }
4917 return 0;
4918}
willy tarreaue39cd132005-12-17 13:00:18 +01004919
willy tarreau5cbea6f2005-12-17 12:48:26 +01004920
willy tarreau9fe663a2005-12-17 13:02:59 +01004921/*
4922 * This function reads and parses the configuration file given in the argument.
4923 * returns 0 if OK, -1 if error.
4924 */
4925int readcfgfile(char *file) {
4926 char thisline[256];
4927 char *line;
4928 FILE *f;
4929 int linenum = 0;
4930 char *end;
4931 char *args[MAX_LINE_ARGS];
4932 int arg;
4933 int cfgerr = 0;
4934 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01004935
willy tarreau9fe663a2005-12-17 13:02:59 +01004936 struct proxy *curproxy = NULL;
4937 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01004938
willy tarreau9fe663a2005-12-17 13:02:59 +01004939 if ((f=fopen(file,"r")) == NULL)
4940 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004941
willy tarreau9fe663a2005-12-17 13:02:59 +01004942 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
4943 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004944
willy tarreau9fe663a2005-12-17 13:02:59 +01004945 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004946
willy tarreau9fe663a2005-12-17 13:02:59 +01004947 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01004948 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01004949 line++;
4950
4951 arg = 0;
4952 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01004953
willy tarreau9fe663a2005-12-17 13:02:59 +01004954 while (*line && arg < MAX_LINE_ARGS) {
4955 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
4956 * C equivalent value. Other combinations left unchanged (eg: \1).
4957 */
4958 if (*line == '\\') {
4959 int skip = 0;
4960 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
4961 *line = line[1];
4962 skip = 1;
4963 }
4964 else if (line[1] == 'r') {
4965 *line = '\r';
4966 skip = 1;
4967 }
4968 else if (line[1] == 'n') {
4969 *line = '\n';
4970 skip = 1;
4971 }
4972 else if (line[1] == 't') {
4973 *line = '\t';
4974 skip = 1;
4975 }
4976 else if (line[1] == 'x' && (line + 3 < end )) {
4977 unsigned char hex1, hex2;
4978 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
4979 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4980 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4981 *line = (hex1<<4) + hex2;
4982 skip = 3;
4983 }
4984 if (skip) {
4985 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
4986 end -= skip;
4987 }
4988 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004989 }
willy tarreaua1598082005-12-17 13:08:06 +01004990 else if (*line == '#' || *line == '\n' || *line == '\r') {
4991 /* end of string, end of loop */
4992 *line = 0;
4993 break;
4994 }
willy tarreauc29948c2005-12-17 13:10:27 +01004995 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004996 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01004997 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01004998 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01004999 line++;
5000 args[++arg] = line;
5001 }
5002 else {
5003 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005004 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005005 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005006
willy tarreau9fe663a2005-12-17 13:02:59 +01005007 /* empty line */
5008 if (!**args)
5009 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01005010
willy tarreau9fe663a2005-12-17 13:02:59 +01005011 /* zero out remaining args */
5012 while (++arg < MAX_LINE_ARGS) {
5013 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005014 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005015
willy tarreau9fe663a2005-12-17 13:02:59 +01005016 if (!strcmp(args[0], "listen")) /* new proxy */
5017 confsect = CFG_LISTEN;
5018 else if (!strcmp(args[0], "global")) /* global config */
5019 confsect = CFG_GLOBAL;
5020 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005021
willy tarreau9fe663a2005-12-17 13:02:59 +01005022 switch (confsect) {
5023 case CFG_LISTEN:
5024 if (cfg_parse_listen(file, linenum, args) < 0)
5025 return -1;
5026 break;
5027 case CFG_GLOBAL:
5028 if (cfg_parse_global(file, linenum, args) < 0)
5029 return -1;
5030 break;
5031 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01005032 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005033 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005034 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005035
5036
willy tarreau0f7af912005-12-17 12:21:26 +01005037 }
5038 fclose(f);
5039
5040 /*
5041 * Now, check for the integrity of all that we have collected.
5042 */
5043
5044 if ((curproxy = proxy) == NULL) {
5045 Alert("parsing %s : no <listen> line. Nothing to do !\n",
5046 file);
5047 return -1;
5048 }
5049
5050 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01005051 if (curproxy->state == PR_STDISABLED) {
5052 curproxy = curproxy->next;
5053 continue;
5054 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005055 if ((curproxy->mode != PR_MODE_HEALTH) &&
5056 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01005057 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005058 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
5059 file, curproxy->id);
5060 cfgerr++;
5061 }
5062 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
5063 if (curproxy->options & PR_O_TRANSP) {
5064 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
5065 file, curproxy->id);
5066 cfgerr++;
5067 }
5068 else if (curproxy->srv == NULL) {
5069 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
5070 file, curproxy->id);
5071 cfgerr++;
5072 }
willy tarreaua1598082005-12-17 13:08:06 +01005073 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005074 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
5075 file, curproxy->id);
5076 }
5077 }
5078 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01005079 if (curproxy->cookie_name != NULL) {
5080 Warning("parsing %s : cookie will be ignored for listener %s.\n",
5081 file, curproxy->id);
5082 }
5083 if ((newsrv = curproxy->srv) != NULL) {
5084 Warning("parsing %s : servers will be ignored for listener %s.\n",
5085 file, curproxy->id);
5086 }
willy tarreaue39cd132005-12-17 13:00:18 +01005087 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005088 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
5089 file, curproxy->id);
5090 }
willy tarreaue39cd132005-12-17 13:00:18 +01005091 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005092 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
5093 file, curproxy->id);
5094 }
5095 }
5096 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
5097 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
5098 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
5099 file, curproxy->id);
5100 cfgerr++;
5101 }
5102 else {
5103 while (newsrv != NULL) {
5104 /* nothing to check for now */
5105 newsrv = newsrv->next;
5106 }
5107 }
5108 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005109 if (curproxy->errmsg.msg400 == NULL) {
5110 curproxy->errmsg.msg400 = (char *)HTTP_400;
5111 curproxy->errmsg.len400 = strlen(HTTP_400);
5112 }
5113 if (curproxy->errmsg.msg403 == NULL) {
5114 curproxy->errmsg.msg403 = (char *)HTTP_403;
5115 curproxy->errmsg.len403 = strlen(HTTP_403);
5116 }
5117 if (curproxy->errmsg.msg408 == NULL) {
5118 curproxy->errmsg.msg408 = (char *)HTTP_408;
5119 curproxy->errmsg.len408 = strlen(HTTP_408);
5120 }
5121 if (curproxy->errmsg.msg500 == NULL) {
5122 curproxy->errmsg.msg500 = (char *)HTTP_500;
5123 curproxy->errmsg.len500 = strlen(HTTP_500);
5124 }
5125 if (curproxy->errmsg.msg502 == NULL) {
5126 curproxy->errmsg.msg502 = (char *)HTTP_502;
5127 curproxy->errmsg.len502 = strlen(HTTP_502);
5128 }
5129 if (curproxy->errmsg.msg503 == NULL) {
5130 curproxy->errmsg.msg503 = (char *)HTTP_503;
5131 curproxy->errmsg.len503 = strlen(HTTP_503);
5132 }
5133 if (curproxy->errmsg.msg504 == NULL) {
5134 curproxy->errmsg.msg504 = (char *)HTTP_504;
5135 curproxy->errmsg.len504 = strlen(HTTP_504);
5136 }
willy tarreau0f7af912005-12-17 12:21:26 +01005137 curproxy = curproxy->next;
5138 }
5139 if (cfgerr > 0) {
5140 Alert("Errors found in configuration file, aborting.\n");
5141 return -1;
5142 }
5143 else
5144 return 0;
5145}
5146
5147
5148/*
5149 * This function initializes all the necessary variables. It only returns
5150 * if everything is OK. If something fails, it exits.
5151 */
5152void init(int argc, char **argv) {
5153 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01005154 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01005155 char *old_argv = *argv;
5156 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01005157 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01005158
5159 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005160 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005161 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
5162 sizeof(int)*8);
5163 exit(1);
5164 }
5165
5166 pid = getpid();
5167 progname = *argv;
5168 while ((tmp = strchr(progname, '/')) != NULL)
5169 progname = tmp + 1;
5170
5171 argc--; argv++;
5172 while (argc > 0) {
5173 char *flag;
5174
5175 if (**argv == '-') {
5176 flag = *argv+1;
5177
5178 /* 1 arg */
5179 if (*flag == 'v') {
5180 display_version();
5181 exit(0);
5182 }
5183 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01005184 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01005185 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01005186 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005187 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01005188 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01005189#if STATTIME > 0
5190 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01005191 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01005192 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01005193 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01005194#endif
5195 else { /* >=2 args */
5196 argv++; argc--;
5197 if (argc == 0)
5198 usage(old_argv);
5199
5200 switch (*flag) {
5201 case 'n' : cfg_maxconn = atol(*argv); break;
5202 case 'N' : cfg_maxpconn = atol(*argv); break;
5203 case 'f' : cfg_cfgfile = *argv; break;
5204 default: usage(old_argv);
5205 }
5206 }
5207 }
5208 else
5209 usage(old_argv);
5210 argv++; argc--;
5211 }
5212
willy tarreau0f7af912005-12-17 12:21:26 +01005213 if (!cfg_cfgfile)
5214 usage(old_argv);
5215
5216 gethostname(hostname, MAX_HOSTNAME_LEN);
5217
5218 if (readcfgfile(cfg_cfgfile) < 0) {
5219 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
5220 exit(1);
5221 }
5222
willy tarreau9fe663a2005-12-17 13:02:59 +01005223 if (cfg_maxconn > 0)
5224 global.maxconn = cfg_maxconn;
5225
5226 if (global.maxconn == 0)
5227 global.maxconn = DEFAULT_MAXCONN;
5228
5229 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
5230
5231 if (arg_mode & MODE_DEBUG) {
5232 /* command line debug mode inhibits configuration mode */
5233 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5234 }
willy tarreau750a4722005-12-17 13:21:24 +01005235 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01005236
5237 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
5238 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
5239 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5240 }
5241
5242 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
5243 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
5244 global.nbproc = 1;
5245 }
5246
5247 if (global.nbproc < 1)
5248 global.nbproc = 1;
5249
willy tarreau0f7af912005-12-17 12:21:26 +01005250 ReadEvent = (fd_set *)calloc(1,
5251 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005252 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005253 WriteEvent = (fd_set *)calloc(1,
5254 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005255 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005256 StaticReadEvent = (fd_set *)calloc(1,
5257 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005258 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005259 StaticWriteEvent = (fd_set *)calloc(1,
5260 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005261 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005262
5263 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01005264 sizeof(struct fdtab) * (global.maxsock));
5265 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01005266 fdtab[i].state = FD_STCLOSE;
5267 }
5268}
5269
5270/*
5271 * this function starts all the proxies. It returns 0 if OK, -1 if not.
5272 */
5273int start_proxies() {
5274 struct proxy *curproxy;
5275 int one = 1;
5276 int fd;
5277
5278 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
5279
5280 if (curproxy->state == PR_STDISABLED)
5281 continue;
5282
5283 if ((fd = curproxy->listen_fd =
5284 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
5285 Alert("cannot create listening socket for proxy %s. Aborting.\n",
5286 curproxy->id);
5287 return -1;
5288 }
5289
willy tarreau9fe663a2005-12-17 13:02:59 +01005290 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005291 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
5292 curproxy->id);
5293 close(fd);
5294 return -1;
5295 }
5296
willy tarreau0f7af912005-12-17 12:21:26 +01005297 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
5298 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
5299 (char *) &one, sizeof(one)) == -1)) {
5300 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
5301 curproxy->id);
5302 close(fd);
5303 return -1;
5304 }
5305
5306 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
5307 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
5308 curproxy->id);
5309 }
5310
5311 if (bind(fd,
5312 (struct sockaddr *)&curproxy->listen_addr,
5313 sizeof(curproxy->listen_addr)) == -1) {
5314 Alert("cannot bind socket for proxy %s. Aborting.\n",
5315 curproxy->id);
5316 close(fd);
5317 return -1;
5318 }
5319
5320 if (listen(fd, curproxy->maxconn) == -1) {
5321 Alert("cannot listen to socket for proxy %s. Aborting.\n",
5322 curproxy->id);
5323 close(fd);
5324 return -1;
5325 }
5326
5327 /* the function for the accept() event */
5328 fdtab[fd].read = &event_accept;
5329 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005330 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01005331 curproxy->state = PR_STRUN;
5332 fdtab[fd].state = FD_STLISTEN;
5333 FD_SET(fd, StaticReadEvent);
5334 fd_insert(fd);
5335 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01005336
willy tarreaua1598082005-12-17 13:08:06 +01005337 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005338
willy tarreau0f7af912005-12-17 12:21:26 +01005339 }
5340 return 0;
5341}
5342
5343
5344int main(int argc, char **argv) {
5345 init(argc, argv);
5346
willy tarreau9fe663a2005-12-17 13:02:59 +01005347 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01005348 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005349 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01005350 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01005351 }
5352
5353 signal(SIGQUIT, dump);
5354 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01005355 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005356
5357 /* on very high loads, a sigpipe sometimes happen just between the
5358 * getsockopt() which tells "it's OK to write", and the following write :-(
5359 */
willy tarreau3242e862005-12-17 12:27:53 +01005360#ifndef MSG_NOSIGNAL
5361 signal(SIGPIPE, SIG_IGN);
5362#endif
willy tarreau0f7af912005-12-17 12:21:26 +01005363
5364 if (start_proxies() < 0)
5365 exit(1);
5366
willy tarreau9fe663a2005-12-17 13:02:59 +01005367 /* open log files */
5368
5369 /* chroot if needed */
5370 if (global.chroot != NULL) {
5371 if (chroot(global.chroot) == -1) {
5372 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
5373 exit(1);
5374 }
5375 chdir("/");
5376 }
5377
5378 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01005379 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005380 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
5381 exit(1);
5382 }
5383
willy tarreau036e1ce2005-12-17 13:46:33 +01005384 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005385 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
5386 exit(1);
5387 }
5388
5389 if (global.mode & MODE_DAEMON) {
5390 int ret = 0;
5391 int proc;
5392
5393 /* the father launches the required number of processes */
5394 for (proc = 0; proc < global.nbproc; proc++) {
5395 ret = fork();
5396 if (ret < 0) {
5397 Alert("[%s.main()] Cannot fork.\n", argv[0]);
5398 exit(1); /* there has been an error */
5399 }
5400 else if (ret == 0) /* child breaks here */
5401 break;
5402 }
5403 if (proc == global.nbproc)
5404 exit(0); /* parent must leave */
5405
willy tarreau750a4722005-12-17 13:21:24 +01005406 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
5407 * that we can detach from the TTY. We MUST NOT do it in other cases since
5408 * it would have already be done, and 0-2 would have been affected to listening
5409 * sockets
5410 */
5411 if (!(global.mode & MODE_QUIET)) {
5412 /* detach from the tty */
5413 fclose(stdin); fclose(stdout); fclose(stderr);
5414 close(0); close(1); close(2); /* close all fd's */
5415 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
5416 }
willy tarreaua1598082005-12-17 13:08:06 +01005417 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01005418 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01005419 }
5420
willy tarreau0f7af912005-12-17 12:21:26 +01005421 select_loop();
5422
5423 exit(0);
5424}