blob: c9520579e011d79cf06c2f51833cb2a69ac2ea14 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreaudd07e972005-12-18 00:48:48 +01003 * 2000-2004 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
11 * RFC2965 for informations about cookies usage.
12 *
13 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010014 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
15 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010016 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010017 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
18 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010019 * - a proxy with an invalid config will prevent the startup even if disabled.
20 *
willy tarreau036e1ce2005-12-17 13:46:33 +010021 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010022 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010023 * TODO:
24 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010025 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010026 * - fix client/server state transition when server is in connect or headers state
27 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
28 * still handle HTTP headers.
willy tarreau0f7af912005-12-17 12:21:26 +010029 *
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <string.h>
36#include <ctype.h>
37#include <sys/time.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <netinet/tcp.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <netdb.h>
44#include <fcntl.h>
45#include <errno.h>
46#include <signal.h>
47#include <stdarg.h>
48#include <sys/resource.h>
49#include <time.h>
50#include <regex.h>
51#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010052#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010053#include <linux/netfilter_ipv4.h>
54#endif
willy tarreau0f7af912005-12-17 12:21:26 +010055
willy tarreaudd07e972005-12-18 00:48:48 +010056#define HAPROXY_VERSION "1.2.1"
willy tarreau25c4ea52005-12-18 00:49:49 +010057#define HAPROXY_DATE "2004/06/05"
willy tarreau0f7af912005-12-17 12:21:26 +010058
59/* this is for libc5 for example */
60#ifndef TCP_NODELAY
61#define TCP_NODELAY 1
62#endif
63
64#ifndef SHUT_RD
65#define SHUT_RD 0
66#endif
67
68#ifndef SHUT_WR
69#define SHUT_WR 1
70#endif
71
willy tarreau535ae7a2005-12-17 12:58:00 +010072#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +010073
74// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +010075#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +010076#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +010077#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +010078
willy tarreau5cbea6f2005-12-17 12:48:26 +010079// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +010080#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +010081
willy tarreaue39cd132005-12-17 13:00:18 +010082// max # of added headers per request
83#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +010084
85// max # of matches per regexp
86#define MAX_MATCH 10
87
willy tarreau5cbea6f2005-12-17 12:48:26 +010088/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +010089#define COOKIENAME_LEN 16
90#define SERVERID_LEN 16
91#define CONN_RETRIES 3
92
willy tarreau5cbea6f2005-12-17 12:48:26 +010093#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +010094#define DEF_CHKINTR 2000
95#define DEF_FALLTIME 3
96#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +010097#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +010098
willy tarreau9fe663a2005-12-17 13:02:59 +010099/* default connections limit */
100#define DEFAULT_MAXCONN 2000
101
willy tarreau0f7af912005-12-17 12:21:26 +0100102/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
103#define INTBITS 5
104
105/* show stats this every millisecond, 0 to disable */
106#ifndef STATTIME
107#define STATTIME 2000
108#endif
109
willy tarreau5cbea6f2005-12-17 12:48:26 +0100110/* this reduces the number of calls to select() by choosing appropriate
111 * sheduler precision in milliseconds. It should be near the minimum
112 * time that is needed by select() to collect all events. All timeouts
113 * are rounded up by adding this value prior to pass it to select().
114 */
115#define SCHEDULER_RESOLUTION 9
116
willy tarreau0f7af912005-12-17 12:21:26 +0100117#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
118#define SETNOW(a) (*a=now)
119
willy tarreau9da061b2005-12-17 12:29:56 +0100120/****** string-specific macros and functions ******/
121/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
122#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
123
124/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
125#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
126
willy tarreau9da061b2005-12-17 12:29:56 +0100127/*
128 * copies at most <size-1> chars from <src> to <dst>. Last char is always
129 * set to 0, unless <size> is 0. The number of chars copied is returned
130 * (excluding the terminating zero).
131 * This code has been optimized for size and speed : on x86, it's 45 bytes
132 * long, uses only registers, and consumes only 4 cycles per char.
133 */
willy tarreau750a4722005-12-17 13:21:24 +0100134int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100135 char *orig = dst;
136 if (size) {
137 while (--size && (*dst = *src)) {
138 src++; dst++;
139 }
140 *dst = 0;
141 }
142 return dst - orig;
143}
willy tarreau9da061b2005-12-17 12:29:56 +0100144
willy tarreau0f7af912005-12-17 12:21:26 +0100145#define MEM_OPTIM
146#ifdef MEM_OPTIM
147/*
148 * Returns a pointer to type <type> taken from the
149 * pool <pool_type> or dynamically allocated. In the
150 * first case, <pool_type> is updated to point to the
151 * next element in the list.
152 */
153#define pool_alloc(type) ({ \
154 void *p; \
155 if ((p = pool_##type) == NULL) \
156 p = malloc(sizeof_##type); \
157 else { \
158 pool_##type = *(void **)pool_##type; \
159 } \
160 p; \
161})
162
163/*
164 * Puts a memory area back to the corresponding pool.
165 * Items are chained directly through a pointer that
166 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100167 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100168 * that each memory area is at least as big as one
169 * pointer.
170 */
171#define pool_free(type, ptr) ({ \
172 *(void **)ptr = (void *)pool_##type; \
173 pool_##type = (void *)ptr; \
174})
175
176#else
177#define pool_alloc(type) (calloc(1,sizeof_##type));
178#define pool_free(type, ptr) (free(ptr));
179#endif /* MEM_OPTIM */
180
willy tarreau5cbea6f2005-12-17 12:48:26 +0100181#define sizeof_task sizeof(struct task)
182#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100183#define sizeof_buffer sizeof(struct buffer)
184#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100185#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100186#define sizeof_capture CAPTURE_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100187
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define FD_STCLOSE 0
190#define FD_STLISTEN 1
191#define FD_STCONN 2
192#define FD_STREADY 3
193#define FD_STERROR 4
194
willy tarreau5cbea6f2005-12-17 12:48:26 +0100195/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100196#define TASK_IDLE 0
197#define TASK_RUNNING 1
198
willy tarreau5cbea6f2005-12-17 12:48:26 +0100199/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100200#define PR_STNEW 0
201#define PR_STIDLE 1
202#define PR_STRUN 2
203#define PR_STDISABLED 3
204
willy tarreau5cbea6f2005-12-17 12:48:26 +0100205/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100206#define PR_MODE_TCP 0
207#define PR_MODE_HTTP 1
208#define PR_MODE_HEALTH 2
209
willy tarreau5cbea6f2005-12-17 12:48:26 +0100210/* bits for proxy->options */
211#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
212#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
213#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
214#define PR_O_COOK_IND 8 /* keep only indirect cookies */
215#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
216#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
217#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
218#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100219#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
220#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100221#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
222#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100223#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100224#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100225#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
willy tarreau8337c6b2005-12-17 13:41:01 +0100226#define PR_O_PERSIST 8192 /* server persistence stays effective even when server is down */
willy tarreau25c4ea52005-12-18 00:49:49 +0100227#define PR_O_LOGASAP 16384 /* log as soon as possible, without waiting for the session to complete */
228#define PR_O_HTTP_CLOSE 32768 /* force 'connection: close' in both directions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100229
willy tarreaue39cd132005-12-17 13:00:18 +0100230/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100231#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
232#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
233#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
234#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
235#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
236#define SN_POST 0x00000020 /* the request was an HTTP POST */
237
238#define SN_CK_NONE 0x00000000 /* this session had no cookie */
239#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
240#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
241#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
242#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
243#define SN_CK_SHIFT 6 /* bit shift */
244
245#define SN_ERR_CLITO 0x00000100 /* client time-out */
246#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
247#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
248#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
249#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
250#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
251#define SN_ERR_SHIFT 8 /* bit shift */
252
253#define SN_FINST_R 0x00001000 /* session ended during client request */
254#define SN_FINST_C 0x00002000 /* session ended during server connect */
255#define SN_FINST_H 0x00003000 /* session ended during server headers */
256#define SN_FINST_D 0x00004000 /* session ended during data phase */
257#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
258#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
259#define SN_FINST_SHIFT 12 /* bit shift */
260
261#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
262#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
263#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
264#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
265#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
266#define SN_SCK_SHIFT 16 /* bit shift */
267
willy tarreau5cbea6f2005-12-17 12:48:26 +0100268
269/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100270#define CL_STHEADERS 0
271#define CL_STDATA 1
272#define CL_STSHUTR 2
273#define CL_STSHUTW 3
274#define CL_STCLOSE 4
275
willy tarreau5cbea6f2005-12-17 12:48:26 +0100276/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100277#define SV_STIDLE 0
278#define SV_STCONN 1
279#define SV_STHEADERS 2
280#define SV_STDATA 3
281#define SV_STSHUTR 4
282#define SV_STSHUTW 5
283#define SV_STCLOSE 6
284
285/* result of an I/O event */
286#define RES_SILENT 0 /* didn't happen */
287#define RES_DATA 1 /* data were sent or received */
288#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
289#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
290
willy tarreau9fe663a2005-12-17 13:02:59 +0100291/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100292#define MODE_DEBUG 1
293#define MODE_STATS 2
294#define MODE_LOG 4
295#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100296#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100297#define MODE_CHECK 32
willy tarreau5cbea6f2005-12-17 12:48:26 +0100298
299/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100300#define SRV_RUNNING 1 /* the server is UP */
301#define SRV_BACKUP 2 /* this server is a backup server */
302#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0f7af912005-12-17 12:21:26 +0100303
willy tarreaue39cd132005-12-17 13:00:18 +0100304/* what to do when a header matches a regex */
305#define ACT_ALLOW 0 /* allow the request */
306#define ACT_REPLACE 1 /* replace the matching header */
307#define ACT_REMOVE 2 /* remove the matching header */
308#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100309#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100310
willy tarreau9fe663a2005-12-17 13:02:59 +0100311/* configuration sections */
312#define CFG_NONE 0
313#define CFG_GLOBAL 1
314#define CFG_LISTEN 2
315
willy tarreaua1598082005-12-17 13:08:06 +0100316/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100317#define LW_DATE 1 /* date */
318#define LW_CLIP 2 /* CLient IP */
319#define LW_SVIP 4 /* SerVer IP */
320#define LW_SVID 8 /* server ID */
321#define LW_REQ 16 /* http REQuest */
322#define LW_RESP 32 /* http RESPonse */
323#define LW_PXIP 64 /* proxy IP */
324#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100325#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100326
willy tarreau0f7af912005-12-17 12:21:26 +0100327/*********************************************************************/
328
329#define LIST_HEAD(a) ((void *)(&(a)))
330
331/*********************************************************************/
332
333struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100334 struct hdr_exp *next;
335 regex_t *preg; /* expression to look for */
336 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
337 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100338};
339
340struct buffer {
341 unsigned int l; /* data length */
342 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100343 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100344 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100345 char data[BUFSIZE];
346};
347
348struct server {
349 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100350 int state; /* server state (SRV_*) */
351 int cklen; /* the len of the cookie, to speed up checks */
352 char *cookie; /* the id set in the cookie */
353 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100354 struct sockaddr_in addr; /* the address to connect to */
willy tarreaua41a8b42005-12-17 14:02:24 +0100355 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100356 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100357 int rise, fall; /* time in iterations */
358 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100359 int result; /* 0 = connect OK, -1 = connect KO */
360 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100361 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100362};
363
willy tarreau5cbea6f2005-12-17 12:48:26 +0100364/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100365struct task {
366 struct task *next, *prev; /* chaining ... */
367 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100368 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100369 int state; /* task state : IDLE or RUNNING */
370 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100371 int (*process)(struct task *t); /* the function which processes the task */
372 void *context; /* the task's context */
373};
374
375/* WARNING: if new fields are added, they must be initialized in event_accept() */
376struct session {
377 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100378 /* application specific below */
379 struct timeval crexpire; /* expiration date for a client read */
380 struct timeval cwexpire; /* expiration date for a client write */
381 struct timeval srexpire; /* expiration date for a server read */
382 struct timeval swexpire; /* expiration date for a server write */
383 struct timeval cnexpire; /* expiration date for a connect */
384 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
385 struct proxy *proxy; /* the proxy this socket belongs to */
386 int cli_fd; /* the client side fd */
387 int srv_fd; /* the server side fd */
388 int cli_state; /* state of the client side */
389 int srv_state; /* state of the server side */
390 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100391 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100392 struct buffer *req; /* request buffer */
393 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100394 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100395 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100396 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100397 struct {
398 int logwait; /* log fields waiting to be collected : LW_* */
399 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
400 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
401 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
402 long t_data; /* delay before the first data byte from the server ... */
403 unsigned long t_close; /* total session duration */
404 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100405 char *cli_cookie; /* cookie presented by the client, in capture mode */
406 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100407 int status; /* HTTP status from the server, negative if from proxy */
408 long long bytes; /* number of bytes transferred from the server */
409 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100410 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100411};
412
willy tarreaua41a8b42005-12-17 14:02:24 +0100413struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100414 int fd; /* the listen socket */
415 struct sockaddr_storage addr; /* the address we listen to */
416 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100417};
418
419
willy tarreau0f7af912005-12-17 12:21:26 +0100420struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100421 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100422 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100423 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100424 struct server *srv, *cursrv; /* known servers, current server */
425 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100426 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100427 int cookie_len; /* strlen(cookie_len), computed only once */
428 char *capture_name; /* beginning of the name of the cookie to capture */
429 int capture_namelen; /* length of the cookie name to match */
430 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100431 int clitimeout; /* client I/O timeout (in milliseconds) */
432 int srvtimeout; /* server I/O timeout (in milliseconds) */
433 int contimeout; /* connect timeout (in milliseconds) */
434 char *id; /* proxy id */
435 int nbconn; /* # of active sessions */
436 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100437 int conn_retries; /* maximum number of connect retries */
438 int options; /* PR_O_REDISP, PR_O_TRANSP */
439 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100440 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100441 struct proxy *next;
442 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
443 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100444 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100445 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100446 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100447 int nb_reqadd, nb_rspadd;
448 struct hdr_exp *req_exp; /* regular expressions for request headers */
449 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
450 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100451 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100452 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
453 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100454 struct {
455 char *msg400; /* message for error 400 */
456 int len400; /* message length for error 400 */
457 char *msg403; /* message for error 403 */
458 int len403; /* message length for error 403 */
459 char *msg408; /* message for error 408 */
460 int len408; /* message length for error 408 */
461 char *msg500; /* message for error 500 */
462 int len500; /* message length for error 500 */
463 char *msg502; /* message for error 502 */
464 int len502; /* message length for error 502 */
465 char *msg503; /* message for error 503 */
466 int len503; /* message length for error 503 */
467 char *msg504; /* message for error 504 */
468 int len504; /* message length for error 504 */
469 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100470};
471
472/* info about one given fd */
473struct fdtab {
474 int (*read)(int fd); /* read function */
475 int (*write)(int fd); /* write function */
476 struct task *owner; /* the session (or proxy) associated with this fd */
477 int state; /* the state of this fd */
478};
479
480/*********************************************************************/
481
willy tarreau0f7af912005-12-17 12:21:26 +0100482int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100483char *cfg_cfgfile = NULL; /* configuration file */
484char *progname = NULL; /* program name */
485int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100486
487/* global options */
488static struct {
489 int uid;
490 int gid;
491 int nbproc;
492 int maxconn;
493 int maxsock; /* max # of sockets */
494 int mode;
495 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100496 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100497 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100498 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100499 struct sockaddr_in logsrv1, logsrv2;
500} global = {
501 logfac1 : -1,
502 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100503 loglev1 : 7, /* max syslog level : debug */
504 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100505 /* others NULL OK */
506};
507
willy tarreau0f7af912005-12-17 12:21:26 +0100508/*********************************************************************/
509
510fd_set *ReadEvent,
511 *WriteEvent,
512 *StaticReadEvent,
513 *StaticWriteEvent;
514
515void **pool_session = NULL,
516 **pool_buffer = NULL,
517 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100518 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100519 **pool_task = NULL,
520 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100521
522struct proxy *proxy = NULL; /* list of all existing proxies */
523struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100524struct task *rq = NULL; /* global run queue */
525struct task wait_queue = { /* global wait queue */
526 prev:LIST_HEAD(wait_queue),
527 next:LIST_HEAD(wait_queue)
528};
willy tarreau0f7af912005-12-17 12:21:26 +0100529
willy tarreau0f7af912005-12-17 12:21:26 +0100530static int totalconn = 0; /* total # of terminated sessions */
531static int actconn = 0; /* # of active sessions */
532static int maxfd = 0; /* # of the highest fd + 1 */
533static int listeners = 0; /* # of listeners */
534static int stopping = 0; /* non zero means stopping in progress */
535static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100536static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100537
538static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100539/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100540static char trash[BUFSIZE];
541
willy tarreaudd07e972005-12-18 00:48:48 +0100542const int zero = 0;
543const int one = 1;
544
willy tarreau0f7af912005-12-17 12:21:26 +0100545/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100546 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100547 */
548
549#define MAX_SYSLOG_LEN 1024
550#define NB_LOG_FACILITIES 24
551const char *log_facilities[NB_LOG_FACILITIES] = {
552 "kern", "user", "mail", "daemon",
553 "auth", "syslog", "lpr", "news",
554 "uucp", "cron", "auth2", "ftp",
555 "ntp", "audit", "alert", "cron2",
556 "local0", "local1", "local2", "local3",
557 "local4", "local5", "local6", "local7"
558};
559
560
561#define NB_LOG_LEVELS 8
562const char *log_levels[NB_LOG_LEVELS] = {
563 "emerg", "alert", "crit", "err",
564 "warning", "notice", "info", "debug"
565};
566
567#define SYSLOG_PORT 514
568
569const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
570 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100571
572const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
573const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
574const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
575const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
576 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
577 unknown, Set-cookie Rewritten */
578
willy tarreau0f7af912005-12-17 12:21:26 +0100579#define MAX_HOSTNAME_LEN 32
580static char hostname[MAX_HOSTNAME_LEN] = "";
581
willy tarreau8337c6b2005-12-17 13:41:01 +0100582const char *HTTP_302 =
583 "HTTP/1.0 302 Found\r\n"
584 "Cache-Control: no-cache\r\n"
585 "Connection: close\r\n"
586 "Location: "; /* not terminated since it will be concatenated with the URL */
587
willy tarreaua1598082005-12-17 13:08:06 +0100588const char *HTTP_400 =
589 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100590 "Cache-Control: no-cache\r\n"
591 "Connection: close\r\n"
592 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100593 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100594
willy tarreaua1598082005-12-17 13:08:06 +0100595const char *HTTP_403 =
596 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100597 "Cache-Control: no-cache\r\n"
598 "Connection: close\r\n"
599 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100600 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
601
willy tarreau8337c6b2005-12-17 13:41:01 +0100602const char *HTTP_408 =
603 "HTTP/1.0 408 Request Time-out\r\n"
604 "Cache-Control: no-cache\r\n"
605 "Connection: close\r\n"
606 "\r\n"
607 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
608
willy tarreau750a4722005-12-17 13:21:24 +0100609const char *HTTP_500 =
610 "HTTP/1.0 500 Server Error\r\n"
611 "Cache-Control: no-cache\r\n"
612 "Connection: close\r\n"
613 "\r\n"
614 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100615
616const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100617 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100618 "Cache-Control: no-cache\r\n"
619 "Connection: close\r\n"
620 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100621 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
622
623const char *HTTP_503 =
624 "HTTP/1.0 503 Service Unavailable\r\n"
625 "Cache-Control: no-cache\r\n"
626 "Connection: close\r\n"
627 "\r\n"
628 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
629
630const char *HTTP_504 =
631 "HTTP/1.0 504 Gateway Time-out\r\n"
632 "Cache-Control: no-cache\r\n"
633 "Connection: close\r\n"
634 "\r\n"
635 "<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 +0100636
willy tarreau0f7af912005-12-17 12:21:26 +0100637/*********************************************************************/
638/* statistics ******************************************************/
639/*********************************************************************/
640
willy tarreau750a4722005-12-17 13:21:24 +0100641#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100642static int stats_tsk_lsrch, stats_tsk_rsrch,
643 stats_tsk_good, stats_tsk_right, stats_tsk_left,
644 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100645#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100646
647
648/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100649/* debugging *******************************************************/
650/*********************************************************************/
651#ifdef DEBUG_FULL
652static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
653static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
654#endif
655
656/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100657/* function prototypes *********************************************/
658/*********************************************************************/
659
660int event_accept(int fd);
661int event_cli_read(int fd);
662int event_cli_write(int fd);
663int event_srv_read(int fd);
664int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100665int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100666
667/*********************************************************************/
668/* general purpose functions ***************************************/
669/*********************************************************************/
670
671void display_version() {
672 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreaudd07e972005-12-18 00:48:48 +0100673 printf("Copyright 2000-2004 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100674}
675
676/*
677 * This function prints the command line usage and exits
678 */
679void usage(char *name) {
680 display_version();
681 fprintf(stderr,
682 "Usage : %s -f <cfgfile> [ -vd"
683#if STATTIME > 0
684 "sl"
685#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100686 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100687 " -v displays version\n"
688 " -d enters debug mode\n"
689#if STATTIME > 0
690 " -s enables statistics output\n"
691 " -l enables long statistics format\n"
692#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100693 " -D goes daemon ; implies -q\n"
694 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100695 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100696 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100697 " -N sets the default, per-proxy maximum # of connections (%d)\n"
698 " -p writes pids of all children to this file\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100699 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100700 exit(1);
701}
702
703
704/*
705 * Displays the message on stderr with the date and pid.
706 */
707void Alert(char *fmt, ...) {
708 va_list argp;
709 struct timeval tv;
710 struct tm *tm;
711
willy tarreau9fe663a2005-12-17 13:02:59 +0100712 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100713 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100714
willy tarreau5cbea6f2005-12-17 12:48:26 +0100715 gettimeofday(&tv, NULL);
716 tm=localtime(&tv.tv_sec);
717 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100718 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100719 vfprintf(stderr, fmt, argp);
720 fflush(stderr);
721 va_end(argp);
722 }
willy tarreau0f7af912005-12-17 12:21:26 +0100723}
724
725
726/*
727 * Displays the message on stderr with the date and pid.
728 */
729void Warning(char *fmt, ...) {
730 va_list argp;
731 struct timeval tv;
732 struct tm *tm;
733
willy tarreau9fe663a2005-12-17 13:02:59 +0100734 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100735 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100736
willy tarreau5cbea6f2005-12-17 12:48:26 +0100737 gettimeofday(&tv, NULL);
738 tm=localtime(&tv.tv_sec);
739 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100740 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100741 vfprintf(stderr, fmt, argp);
742 fflush(stderr);
743 va_end(argp);
744 }
745}
746
747/*
748 * Displays the message on <out> only if quiet mode is not set.
749 */
750void qfprintf(FILE *out, char *fmt, ...) {
751 va_list argp;
752
willy tarreau9fe663a2005-12-17 13:02:59 +0100753 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100754 va_start(argp, fmt);
755 vfprintf(out, fmt, argp);
756 fflush(out);
757 va_end(argp);
758 }
willy tarreau0f7af912005-12-17 12:21:26 +0100759}
760
761
762/*
763 * converts <str> to a struct sockaddr_in* which is locally allocated.
764 * The format is "addr:port", where "addr" can be empty or "*" to indicate
765 * INADDR_ANY.
766 */
767struct sockaddr_in *str2sa(char *str) {
768 static struct sockaddr_in sa;
769 char *c;
770 int port;
771
willy tarreaua1598082005-12-17 13:08:06 +0100772 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100773 str=strdup(str);
774
775 if ((c=strrchr(str,':')) != NULL) {
776 *c++=0;
777 port=atol(c);
778 }
779 else
780 port=0;
781
782 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
783 sa.sin_addr.s_addr = INADDR_ANY;
784 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100785 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100786 struct hostent *he;
787
788 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100789 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100790 }
791 else
792 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
793 }
794 sa.sin_port=htons(port);
795 sa.sin_family=AF_INET;
796
797 free(str);
798 return &sa;
799}
800
willy tarreau9fe663a2005-12-17 13:02:59 +0100801
802/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100803 * converts <str> to a list of listeners which are dynamically allocated.
804 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
805 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
806 * - <port> is a numerical port from 1 to 65535 ;
807 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
808 * This can be repeated as many times as necessary, separated by a coma.
809 * The <tail> argument is a pointer to a current list which should be appended
810 * to the tail of the new list. The pointer to the new list is returned.
811 */
812struct listener *str2listener(char *str, struct listener *tail) {
813 struct listener *l;
814 char *c, *next, *range, *dupstr;
815 int port, end;
816
817 next = dupstr = strdup(str);
willy tarreaua41a8b42005-12-17 14:02:24 +0100818 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100819 struct sockaddr_storage ss;
820
willy tarreaua41a8b42005-12-17 14:02:24 +0100821 str = next;
822 /* 1) look for the end of the first address */
823 if ((next = strrchr(str, ',')) != NULL) {
824 *next++ = 0;
825 }
826
willy tarreau8a86dbf2005-12-18 00:45:59 +0100827 /* 2) look for the addr/port delimiter, it's the last colon. */
828 if ((range = strrchr(str, ':')) == NULL) {
829 Alert("Missing port number: '%s'\n", str);
830 }
831
832 *range++ = 0;
833
834 if (strrchr(str, ':') != NULL) {
835 /* IPv6 address contains ':' */
836 memset(&ss, 0, sizeof(ss));
837 ss.ss_family = AF_INET6;
838
839 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
840 Alert("Invalid server address: '%s'\n", str);
841 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100842 }
843 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100844 memset(&ss, 0, sizeof(ss));
845 ss.ss_family = AF_INET;
846
847 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
848 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
849 }
850 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
851 struct hostent *he;
852
853 if ((he = gethostbyname(str)) == NULL) {
854 Alert("Invalid server name: '%s'\n", str);
855 }
856 else
857 ((struct sockaddr_in *)&ss)->sin_addr =
858 *(struct in_addr *) *(he->h_addr_list);
859 }
860 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100861
862 /* 3) look for the port-end delimiter */
863 if ((c = strchr(range, '-')) != NULL) {
864 *c++ = 0;
865 end = atol(c);
866 }
867 else {
868 end = atol(range);
869 }
870
871 for (port = atol(range); port <= end; port++) {
872 l = (struct listener *)calloc(1, sizeof(struct listener));
873 l->next = tail;
874 tail = l;
875
willy tarreau8a86dbf2005-12-18 00:45:59 +0100876 l->addr = ss;
877 if (ss.ss_family == AF_INET6)
878 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
879 else
880 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
881
willy tarreaua41a8b42005-12-17 14:02:24 +0100882 } /* end for(port) */
883 } /* end while(next) */
884 free(dupstr);
885 return tail;
886}
887
888
889/*
willy tarreau9fe663a2005-12-17 13:02:59 +0100890 * This function sends a syslog message to both log servers of a proxy,
891 * or to global log servers if the proxy is NULL.
892 * It also tries not to waste too much time computing the message header.
893 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100894 */
895void send_log(struct proxy *p, int level, char *message, ...) {
896 static int logfd = -1; /* syslog UDP socket */
897 static long tvsec = -1; /* to force the string to be initialized */
898 struct timeval tv;
899 va_list argp;
900 static char logmsg[MAX_SYSLOG_LEN];
901 static char *dataptr = NULL;
902 int fac_level;
903 int hdr_len, data_len;
904 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +0100905 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +0100906 int nbloggers = 0;
907 char *log_ptr;
908
909 if (logfd < 0) {
910 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
911 return;
912 }
913
914 if (level < 0 || progname == NULL || message == NULL)
915 return;
916
917 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100918 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100919 /* this string is rebuild only once a second */
920 struct tm *tm = localtime(&tv.tv_sec);
921 tvsec = tv.tv_sec;
922
willy tarreauc29948c2005-12-17 13:10:27 +0100923 hdr_len = snprintf(logmsg, sizeof(logmsg),
924 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
925 monthname[tm->tm_mon],
926 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
927 progname, pid);
928 /* WARNING: depending upon implementations, snprintf may return
929 * either -1 or the number of bytes that would be needed to store
930 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100931 */
willy tarreauc29948c2005-12-17 13:10:27 +0100932 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
933 hdr_len = sizeof(logmsg);
934
935 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100936 }
937
938 va_start(argp, message);
939 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100940 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
941 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100942 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100943 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100944
945 if (p == NULL) {
946 if (global.logfac1 >= 0) {
947 sa[nbloggers] = &global.logsrv1;
948 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100949 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100950 nbloggers++;
951 }
952 if (global.logfac2 >= 0) {
953 sa[nbloggers] = &global.logsrv2;
954 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100955 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100956 nbloggers++;
957 }
958 } else {
959 if (p->logfac1 >= 0) {
960 sa[nbloggers] = &p->logsrv1;
961 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100962 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100963 nbloggers++;
964 }
965 if (p->logfac2 >= 0) {
966 sa[nbloggers] = &p->logsrv2;
967 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100968 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100969 nbloggers++;
970 }
971 }
972
973 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +0100974 /* we can filter the level of the messages that are sent to each logger */
975 if (level > loglevel[nbloggers])
976 continue;
977
willy tarreauc29948c2005-12-17 13:10:27 +0100978 /* For each target, we may have a different facility.
979 * We can also have a different log level for each message.
980 * This induces variations in the message header length.
981 * Since we don't want to recompute it each time, nor copy it every
982 * time, we only change the facility in the pre-computed header,
983 * and we change the pointer to the header accordingly.
984 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100985 fac_level = (facilities[nbloggers] << 3) + level;
986 log_ptr = logmsg + 3; /* last digit of the log level */
987 do {
988 *log_ptr = '0' + fac_level % 10;
989 fac_level /= 10;
990 log_ptr--;
991 } while (fac_level && log_ptr > logmsg);
992 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100993
willy tarreauc29948c2005-12-17 13:10:27 +0100994 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100995
996#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100997 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100998 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
999#else
willy tarreauc29948c2005-12-17 13:10:27 +01001000 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001001 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1002#endif
1003 }
willy tarreau0f7af912005-12-17 12:21:26 +01001004}
1005
1006
1007/* sets <tv> to the current time */
1008static inline struct timeval *tv_now(struct timeval *tv) {
1009 if (tv)
1010 gettimeofday(tv, NULL);
1011 return tv;
1012}
1013
1014/*
1015 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1016 */
1017static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1018 if (!tv || !from)
1019 return NULL;
1020 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1021 tv->tv_sec = from->tv_sec + (ms/1000);
1022 while (tv->tv_usec >= 1000000) {
1023 tv->tv_usec -= 1000000;
1024 tv->tv_sec++;
1025 }
1026 return tv;
1027}
1028
1029/*
1030 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1031 */
1032static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001033 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001034 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001035 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001036 return 1;
1037 else if (tv1->tv_usec < tv2->tv_usec)
1038 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001039 else if (tv1->tv_usec > tv2->tv_usec)
1040 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001041 else
1042 return 0;
1043}
1044
1045/*
1046 * returns the absolute difference, in ms, between tv1 and tv2
1047 */
1048unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1049 int cmp;
1050 unsigned long ret;
1051
1052
willy tarreauef900ab2005-12-17 12:52:52 +01001053 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001054 if (!cmp)
1055 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001056 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001057 struct timeval *tmp = tv1;
1058 tv1 = tv2;
1059 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001060 }
willy tarreauef900ab2005-12-17 12:52:52 +01001061 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001062 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001063 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001064 else
willy tarreauef900ab2005-12-17 12:52:52 +01001065 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001066 return (unsigned long) ret;
1067}
1068
1069/*
willy tarreau750a4722005-12-17 13:21:24 +01001070 * returns the difference, in ms, between tv1 and tv2
1071 */
1072static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1073 unsigned long ret;
1074
willy tarreau6e682ce2005-12-17 13:26:49 +01001075 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1076 if (tv2->tv_usec > tv1->tv_usec)
1077 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001078 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001079 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001080 return (unsigned long) ret;
1081}
1082
1083/*
willy tarreau0f7af912005-12-17 12:21:26 +01001084 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1085 */
1086static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001087 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001088 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001089 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001090 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1091 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001092 else
1093 return 0;
1094 }
willy tarreau0f7af912005-12-17 12:21:26 +01001095 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001096 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001097 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001098 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1099 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1100 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001101 else
1102 return 0;
1103}
1104
1105/*
1106 * returns the remaining time between tv1=now and event=tv2
1107 * if tv2 is passed, 0 is returned.
1108 */
1109static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1110 unsigned long ret;
1111
willy tarreau0f7af912005-12-17 12:21:26 +01001112 if (tv_cmp_ms(tv1, tv2) >= 0)
1113 return 0; /* event elapsed */
1114
willy tarreauef900ab2005-12-17 12:52:52 +01001115 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001116 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001117 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001118 else
willy tarreauef900ab2005-12-17 12:52:52 +01001119 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001120 return (unsigned long) ret;
1121}
1122
1123
1124/*
1125 * zeroes a struct timeval
1126 */
1127
1128static inline struct timeval *tv_eternity(struct timeval *tv) {
1129 tv->tv_sec = tv->tv_usec = 0;
1130 return tv;
1131}
1132
1133/*
1134 * returns 1 if tv is null, else 0
1135 */
1136static inline int tv_iseternity(struct timeval *tv) {
1137 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1138 return 1;
1139 else
1140 return 0;
1141}
1142
1143/*
1144 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1145 * considering that 0 is the eternity.
1146 */
1147static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1148 if (tv_iseternity(tv1))
1149 if (tv_iseternity(tv2))
1150 return 0; /* same */
1151 else
1152 return 1; /* tv1 later than tv2 */
1153 else if (tv_iseternity(tv2))
1154 return -1; /* tv2 later than tv1 */
1155
1156 if (tv1->tv_sec > tv2->tv_sec)
1157 return 1;
1158 else if (tv1->tv_sec < tv2->tv_sec)
1159 return -1;
1160 else if (tv1->tv_usec > tv2->tv_usec)
1161 return 1;
1162 else if (tv1->tv_usec < tv2->tv_usec)
1163 return -1;
1164 else
1165 return 0;
1166}
1167
1168/*
1169 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1170 * considering that 0 is the eternity.
1171 */
1172static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1173 if (tv_iseternity(tv1))
1174 if (tv_iseternity(tv2))
1175 return 0; /* same */
1176 else
1177 return 1; /* tv1 later than tv2 */
1178 else if (tv_iseternity(tv2))
1179 return -1; /* tv2 later than tv1 */
1180
willy tarreauefae1842005-12-17 12:51:03 +01001181 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001182 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001183 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001184 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001185 return -1;
1186 else
1187 return 0;
1188 }
1189 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001190 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001191 return 1;
1192 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001193 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001194 return -1;
1195 else
1196 return 0;
1197}
1198
1199/*
1200 * returns the first event between tv1 and tv2 into tvmin.
1201 * a zero tv is ignored. tvmin is returned.
1202 */
1203static inline struct timeval *tv_min(struct timeval *tvmin,
1204 struct timeval *tv1, struct timeval *tv2) {
1205
1206 if (tv_cmp2(tv1, tv2) <= 0)
1207 *tvmin = *tv1;
1208 else
1209 *tvmin = *tv2;
1210
1211 return tvmin;
1212}
1213
1214
1215
1216/***********************************************************/
1217/* fd management ***************************************/
1218/***********************************************************/
1219
1220
1221
willy tarreau5cbea6f2005-12-17 12:48:26 +01001222/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1223 * The file descriptor is also closed.
1224 */
willy tarreau0f7af912005-12-17 12:21:26 +01001225static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001226 FD_CLR(fd, StaticReadEvent);
1227 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001228 close(fd);
1229 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001230
1231 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1232 maxfd--;
1233}
1234
1235/* recomputes the maxfd limit from the fd */
1236static inline void fd_insert(int fd) {
1237 if (fd+1 > maxfd)
1238 maxfd = fd+1;
1239}
1240
1241/*************************************************************/
1242/* task management ***************************************/
1243/*************************************************************/
1244
willy tarreau5cbea6f2005-12-17 12:48:26 +01001245/* puts the task <t> in run queue <q>, and returns <t> */
1246static inline struct task *task_wakeup(struct task **q, struct task *t) {
1247 if (t->state == TASK_RUNNING)
1248 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001249 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001250 t->rqnext = *q;
1251 t->state = TASK_RUNNING;
1252 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001253 }
1254}
1255
willy tarreau5cbea6f2005-12-17 12:48:26 +01001256/* removes the task <t> from the queue <q>
1257 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001258 * set the run queue to point to the next one, and return it
1259 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001260static inline struct task *task_sleep(struct task **q, struct task *t) {
1261 if (t->state == TASK_RUNNING) {
1262 *q = t->rqnext;
1263 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001264 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001265 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001266}
1267
1268/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001269 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001270 * from the run queue. A pointer to the task itself is returned.
1271 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001272static inline struct task *task_delete(struct task *t) {
1273 t->prev->next = t->next;
1274 t->next->prev = t->prev;
1275 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001276}
1277
1278/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001279 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001280 */
1281static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001282 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001283}
1284
willy tarreau5cbea6f2005-12-17 12:48:26 +01001285/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001286 * may be only moved or left where it was, depending on its timing requirements.
1287 * <task> is returned.
1288 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001289struct task *task_queue(struct task *task) {
1290 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001291 struct task *start_from;
1292
1293 /* first, test if the task was already in a list */
1294 if (task->prev == NULL) {
1295 // start_from = list;
1296 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001297#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001298 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001299#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001300 /* insert the unlinked <task> into the list, searching back from the last entry */
1301 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1302 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001303#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001304 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001305#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001306 }
1307
1308 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1309 // start_from = start_from->next;
1310 // stats_tsk_nsrch++;
1311 // }
1312 }
1313 else if (task->prev == list ||
1314 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1315 start_from = task->next;
1316 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001317#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001318 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001319#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001320 return task; /* it's already in the right place */
1321 }
1322
willy tarreau750a4722005-12-17 13:21:24 +01001323#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001324 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001325#endif
1326
1327 /* if the task is not at the right place, there's little chance that
1328 * it has only shifted a bit, and it will nearly always be queued
1329 * at the end of the list because of constant timeouts
1330 * (observed in real case).
1331 */
1332#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1333 start_from = list->prev; /* assume we'll queue to the end of the list */
1334 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1335 start_from = start_from->prev;
1336#if STATTIME > 0
1337 stats_tsk_lsrch++;
1338#endif
1339 }
1340#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001341 /* insert the unlinked <task> into the list, searching after position <start_from> */
1342 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1343 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001344#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001345 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001346#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001347 }
willy tarreau750a4722005-12-17 13:21:24 +01001348#endif /* WE_REALLY_... */
1349
willy tarreau0f7af912005-12-17 12:21:26 +01001350 /* we need to unlink it now */
1351 task_delete(task);
1352 }
1353 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001354#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001355 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001356#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001357#ifdef LEFT_TO_TOP /* not very good */
1358 start_from = list;
1359 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1360 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001361#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001362 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001363#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001364 }
1365#else
1366 start_from = task->prev->prev; /* valid because of the previous test above */
1367 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1368 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001369#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001370 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001371#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001372 }
1373#endif
1374 /* we need to unlink it now */
1375 task_delete(task);
1376 }
1377 task->prev = start_from;
1378 task->next = start_from->next;
1379 task->next->prev = task;
1380 start_from->next = task;
1381 return task;
1382}
1383
1384
1385/*********************************************************************/
1386/* more specific functions ***************************************/
1387/*********************************************************************/
1388
1389/* some prototypes */
1390static int maintain_proxies(void);
1391
willy tarreau5cbea6f2005-12-17 12:48:26 +01001392/* this either returns the sockname or the original destination address. Code
1393 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1394 */
1395static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001396#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001397 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1398#else
willy tarreaua1598082005-12-17 13:08:06 +01001399#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001400 return getsockname(fd, (struct sockaddr *)sa, salen);
1401#else
1402 return -1;
1403#endif
1404#endif
1405}
1406
1407/*
1408 * frees the context associated to a session. It must have been removed first.
1409 */
1410static inline void session_free(struct session *s) {
1411 if (s->req)
1412 pool_free(buffer, s->req);
1413 if (s->rep)
1414 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001415 if (s->logs.uri)
1416 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001417 if (s->logs.cli_cookie)
1418 pool_free(capture, s->logs.cli_cookie);
1419 if (s->logs.srv_cookie)
1420 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001421
willy tarreau5cbea6f2005-12-17 12:48:26 +01001422 pool_free(session, s);
1423}
1424
willy tarreau0f7af912005-12-17 12:21:26 +01001425
1426/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001427 * This function tries to find a running server for the proxy <px>. A first
1428 * pass looks for active servers, and if none is found, a second pass also
1429 * looks for backup servers.
1430 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1431 */
1432static inline struct server *find_server(struct proxy *px) {
1433 struct server *srv = px->cursrv;
1434 int ignore_backup = 1;
1435
1436 do {
1437 do {
1438 if (srv == NULL)
1439 srv = px->srv;
1440 if (srv->state & SRV_RUNNING
1441 && !((srv->state & SRV_BACKUP) && ignore_backup))
1442 return srv;
1443 srv = srv->next;
1444 } while (srv != px->cursrv);
1445 } while (ignore_backup--);
1446 return NULL;
1447}
1448
1449/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001450 * This function initiates a connection to the current server (s->srv) if (s->direct)
1451 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001452 * it's OK, -1 if it's impossible.
1453 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001454int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001455 int fd;
1456
1457 // fprintf(stderr,"connect_server : s=%p\n",s);
1458
willy tarreaue39cd132005-12-17 13:00:18 +01001459 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001460 s->srv_addr = s->srv->addr;
1461 }
1462 else if (s->proxy->options & PR_O_BALANCE) {
1463 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001464 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001465
willy tarreau8337c6b2005-12-17 13:41:01 +01001466 srv = find_server(s->proxy);
1467
1468 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001469 return -1;
1470
willy tarreau8337c6b2005-12-17 13:41:01 +01001471 s->srv_addr = srv->addr;
1472 s->srv = srv;
1473 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001474 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001475 else /* unknown balancing algorithm */
1476 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001477 }
willy tarreaua1598082005-12-17 13:08:06 +01001478 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001479 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001480 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001481 }
1482 else if (s->proxy->options & PR_O_TRANSP) {
1483 /* in transparent mode, use the original dest addr if no dispatch specified */
1484 int salen = sizeof(struct sockaddr_in);
1485 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1486 qfprintf(stderr, "Cannot get original server address.\n");
1487 return -1;
1488 }
1489 }
willy tarreau0f7af912005-12-17 12:21:26 +01001490
willy tarreaua41a8b42005-12-17 14:02:24 +01001491 /* if this server remaps proxied ports, we'll use
1492 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001493 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001494 struct sockaddr_in sockname;
1495 int namelen;
1496
1497 namelen = sizeof(sockname);
1498 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1499 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1500 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1501 }
1502
willy tarreau0f7af912005-12-17 12:21:26 +01001503 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001504 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001505 return -1;
1506 }
1507
willy tarreau9fe663a2005-12-17 13:02:59 +01001508 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001509 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1510 close(fd);
1511 return -1;
1512 }
1513
willy tarreau0f7af912005-12-17 12:21:26 +01001514 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1515 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001516 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001517 close(fd);
1518 return -1;
1519 }
1520
willy tarreaua1598082005-12-17 13:08:06 +01001521 /* allow specific binding */
1522 if (s->proxy->options & PR_O_BIND_SRC &&
1523 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1524 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1525 close(fd);
1526 return -1;
1527 }
1528
willy tarreau0f7af912005-12-17 12:21:26 +01001529 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1530 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001531 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001532 close(fd);
1533 return -1;
1534 }
1535 else if (errno != EALREADY && errno != EISCONN) {
1536 close(fd);
1537 return -1;
1538 }
1539 }
1540
willy tarreau5cbea6f2005-12-17 12:48:26 +01001541 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001542 fdtab[fd].read = &event_srv_read;
1543 fdtab[fd].write = &event_srv_write;
1544 fdtab[fd].state = FD_STCONN; /* connection in progress */
1545
1546 FD_SET(fd, StaticWriteEvent); /* for connect status */
1547
1548 fd_insert(fd);
1549
1550 if (s->proxy->contimeout)
1551 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1552 else
1553 tv_eternity(&s->cnexpire);
1554 return 0;
1555}
1556
1557/*
1558 * this function is called on a read event from a client socket.
1559 * It returns 0.
1560 */
1561int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562 struct task *t = fdtab[fd].owner;
1563 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001564 struct buffer *b = s->req;
1565 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001566
1567 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1568
willy tarreau0f7af912005-12-17 12:21:26 +01001569 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001570 while (1) {
1571 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1572 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001573 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001574 }
1575 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001576 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001577 }
1578 else {
1579 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001580 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1581 * since it means that the rewrite protection has been removed. This
1582 * implies that the if statement can be removed.
1583 */
1584 if (max > b->rlim - b->data)
1585 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001586 }
1587
1588 if (max == 0) { /* not anymore room to store data */
1589 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001590 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001591 }
1592
willy tarreau3242e862005-12-17 12:27:53 +01001593#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594 {
1595 int skerr, lskerr;
1596
1597 lskerr = sizeof(skerr);
1598 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1599 if (skerr)
1600 ret = -1;
1601 else
1602 ret = recv(fd, b->r, max, 0);
1603 }
willy tarreau3242e862005-12-17 12:27:53 +01001604#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001605 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001606#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001607 if (ret > 0) {
1608 b->r += ret;
1609 b->l += ret;
1610 s->res_cr = RES_DATA;
1611
1612 if (b->r == b->data + BUFSIZE) {
1613 b->r = b->data; /* wrap around the buffer */
1614 }
willy tarreaua1598082005-12-17 13:08:06 +01001615
1616 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001617 /* we hope to read more data or to get a close on next round */
1618 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001619 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001620 else if (ret == 0) {
1621 s->res_cr = RES_NULL;
1622 break;
1623 }
1624 else if (errno == EAGAIN) {/* ignore EAGAIN */
1625 break;
1626 }
1627 else {
1628 s->res_cr = RES_ERROR;
1629 fdtab[fd].state = FD_STERROR;
1630 break;
1631 }
1632 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001633 }
1634 else {
1635 s->res_cr = RES_ERROR;
1636 fdtab[fd].state = FD_STERROR;
1637 }
1638
willy tarreau5cbea6f2005-12-17 12:48:26 +01001639 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001640 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001641 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1642 else
1643 tv_eternity(&s->crexpire);
1644
1645 task_wakeup(&rq, t);
1646 }
willy tarreau0f7af912005-12-17 12:21:26 +01001647
willy tarreau0f7af912005-12-17 12:21:26 +01001648 return 0;
1649}
1650
1651
1652/*
1653 * this function is called on a read event from a server socket.
1654 * It returns 0.
1655 */
1656int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001657 struct task *t = fdtab[fd].owner;
1658 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001659 struct buffer *b = s->rep;
1660 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001661
1662 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1663
willy tarreau0f7af912005-12-17 12:21:26 +01001664 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001665 while (1) {
1666 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1667 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001668 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001669 }
1670 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001671 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001672 }
1673 else {
1674 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001675 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1676 * since it means that the rewrite protection has been removed. This
1677 * implies that the if statement can be removed.
1678 */
1679 if (max > b->rlim - b->data)
1680 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001681 }
1682
1683 if (max == 0) { /* not anymore room to store data */
1684 FD_CLR(fd, StaticReadEvent);
1685 break;
1686 }
1687
willy tarreau3242e862005-12-17 12:27:53 +01001688#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001689 {
1690 int skerr, lskerr;
1691
1692 lskerr = sizeof(skerr);
1693 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1694 if (skerr)
1695 ret = -1;
1696 else
1697 ret = recv(fd, b->r, max, 0);
1698 }
willy tarreau3242e862005-12-17 12:27:53 +01001699#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001701#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001702 if (ret > 0) {
1703 b->r += ret;
1704 b->l += ret;
1705 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001706
willy tarreau5cbea6f2005-12-17 12:48:26 +01001707 if (b->r == b->data + BUFSIZE) {
1708 b->r = b->data; /* wrap around the buffer */
1709 }
willy tarreaua1598082005-12-17 13:08:06 +01001710
1711 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001712 /* we hope to read more data or to get a close on next round */
1713 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001714 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001715 else if (ret == 0) {
1716 s->res_sr = RES_NULL;
1717 break;
1718 }
1719 else if (errno == EAGAIN) {/* ignore EAGAIN */
1720 break;
1721 }
1722 else {
1723 s->res_sr = RES_ERROR;
1724 fdtab[fd].state = FD_STERROR;
1725 break;
1726 }
1727 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001728 }
1729 else {
1730 s->res_sr = RES_ERROR;
1731 fdtab[fd].state = FD_STERROR;
1732 }
1733
willy tarreau5cbea6f2005-12-17 12:48:26 +01001734 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001735 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001736 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1737 else
1738 tv_eternity(&s->srexpire);
1739
1740 task_wakeup(&rq, t);
1741 }
willy tarreau0f7af912005-12-17 12:21:26 +01001742
willy tarreau0f7af912005-12-17 12:21:26 +01001743 return 0;
1744}
1745
1746/*
1747 * this function is called on a write event from a client socket.
1748 * It returns 0.
1749 */
1750int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001751 struct task *t = fdtab[fd].owner;
1752 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001753 struct buffer *b = s->rep;
1754 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001755
1756 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1757
1758 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001759 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001760 // max = BUFSIZE; BUG !!!!
1761 max = 0;
1762 }
1763 else if (b->r > b->w) {
1764 max = b->r - b->w;
1765 }
1766 else
1767 max = b->data + BUFSIZE - b->w;
1768
willy tarreau0f7af912005-12-17 12:21:26 +01001769 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001770#ifndef MSG_NOSIGNAL
1771 int skerr, lskerr;
1772#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001773
1774 if (max == 0) {
1775 s->res_cw = RES_NULL;
1776 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001777 tv_eternity(&s->cwexpire);
1778 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001779 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001780 }
1781
willy tarreau3242e862005-12-17 12:27:53 +01001782#ifndef MSG_NOSIGNAL
1783 lskerr=sizeof(skerr);
1784 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1785 if (skerr)
1786 ret = -1;
1787 else
1788 ret = send(fd, b->w, max, MSG_DONTWAIT);
1789#else
willy tarreau0f7af912005-12-17 12:21:26 +01001790 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001791#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001792
1793 if (ret > 0) {
1794 b->l -= ret;
1795 b->w += ret;
1796
1797 s->res_cw = RES_DATA;
1798
1799 if (b->w == b->data + BUFSIZE) {
1800 b->w = b->data; /* wrap around the buffer */
1801 }
1802 }
1803 else if (ret == 0) {
1804 /* nothing written, just make as if we were never called */
1805// s->res_cw = RES_NULL;
1806 return 0;
1807 }
1808 else if (errno == EAGAIN) /* ignore EAGAIN */
1809 return 0;
1810 else {
1811 s->res_cw = RES_ERROR;
1812 fdtab[fd].state = FD_STERROR;
1813 }
1814 }
1815 else {
1816 s->res_cw = RES_ERROR;
1817 fdtab[fd].state = FD_STERROR;
1818 }
1819
willy tarreaub1ff9db2005-12-17 13:51:03 +01001820 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001821 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001822 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
1823 s->crexpire = s->cwexpire;
1824 }
willy tarreau0f7af912005-12-17 12:21:26 +01001825 else
1826 tv_eternity(&s->cwexpire);
1827
willy tarreau5cbea6f2005-12-17 12:48:26 +01001828 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001829 return 0;
1830}
1831
1832
1833/*
1834 * this function is called on a write event from a server socket.
1835 * It returns 0.
1836 */
1837int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001838 struct task *t = fdtab[fd].owner;
1839 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001840 struct buffer *b = s->req;
1841 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001842
1843 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1844
1845 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001846 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001847 // max = BUFSIZE; BUG !!!!
1848 max = 0;
1849 }
1850 else if (b->r > b->w) {
1851 max = b->r - b->w;
1852 }
1853 else
1854 max = b->data + BUFSIZE - b->w;
1855
willy tarreau0f7af912005-12-17 12:21:26 +01001856 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001857#ifndef MSG_NOSIGNAL
1858 int skerr, lskerr;
1859#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001860 if (max == 0) {
1861 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001862 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001863 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001864 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01001865 tv_eternity(&s->swexpire);
1866 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01001867 return 0;
1868 }
1869
willy tarreauef900ab2005-12-17 12:52:52 +01001870
willy tarreau3242e862005-12-17 12:27:53 +01001871#ifndef MSG_NOSIGNAL
1872 lskerr=sizeof(skerr);
1873 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1874 if (skerr)
1875 ret = -1;
1876 else
1877 ret = send(fd, b->w, max, MSG_DONTWAIT);
1878#else
willy tarreau0f7af912005-12-17 12:21:26 +01001879 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001880#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001881 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001882 if (ret > 0) {
1883 b->l -= ret;
1884 b->w += ret;
1885
1886 s->res_sw = RES_DATA;
1887
1888 if (b->w == b->data + BUFSIZE) {
1889 b->w = b->data; /* wrap around the buffer */
1890 }
1891 }
1892 else if (ret == 0) {
1893 /* nothing written, just make as if we were never called */
1894 // s->res_sw = RES_NULL;
1895 return 0;
1896 }
1897 else if (errno == EAGAIN) /* ignore EAGAIN */
1898 return 0;
1899 else {
1900 s->res_sw = RES_ERROR;
1901 fdtab[fd].state = FD_STERROR;
1902 }
1903 }
1904 else {
1905 s->res_sw = RES_ERROR;
1906 fdtab[fd].state = FD_STERROR;
1907 }
1908
willy tarreaub1ff9db2005-12-17 13:51:03 +01001909 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001910 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001911 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
1912 s->srexpire = s->swexpire;
1913 }
willy tarreau0f7af912005-12-17 12:21:26 +01001914 else
1915 tv_eternity(&s->swexpire);
1916
willy tarreau5cbea6f2005-12-17 12:48:26 +01001917 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001918 return 0;
1919}
1920
1921
1922/*
willy tarreaue39cd132005-12-17 13:00:18 +01001923 * returns a message to the client ; the connection is shut down for read,
1924 * and the request is cleared so that no server connection can be initiated.
1925 * The client must be in a valid state for this (HEADER, DATA ...).
1926 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01001927 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001928 */
1929void client_retnclose(struct session *s, int len, const char *msg) {
1930 FD_CLR(s->cli_fd, StaticReadEvent);
1931 FD_SET(s->cli_fd, StaticWriteEvent);
1932 tv_eternity(&s->crexpire);
1933 shutdown(s->cli_fd, SHUT_RD);
1934 s->cli_state = CL_STSHUTR;
1935 strcpy(s->rep->data, msg);
1936 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001937 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001938 s->rep->r += len;
1939 s->req->l = 0;
1940}
1941
1942
1943/*
1944 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01001945 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001946 */
1947void client_return(struct session *s, int len, const char *msg) {
1948 strcpy(s->rep->data, msg);
1949 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001950 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001951 s->rep->r += len;
1952 s->req->l = 0;
1953}
1954
willy tarreau9fe663a2005-12-17 13:02:59 +01001955/*
1956 * send a log for the session when we have enough info about it
1957 */
1958void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001959 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01001960 struct proxy *p = s->proxy;
1961 int log;
1962 char *uri;
1963 char *pxid;
1964 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01001965 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01001966
1967 /* This is a first attempt at a better logging system.
1968 * For now, we rely on send_log() to provide the date, although it obviously
1969 * is the date of the log and not of the request, and most fields are not
1970 * computed.
1971 */
1972
willy tarreaua1598082005-12-17 13:08:06 +01001973 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001974
willy tarreau8a86dbf2005-12-18 00:45:59 +01001975 if (s->cli_addr.ss_family == AF_INET)
1976 inet_ntop(AF_INET,
1977 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1978 pn, sizeof(pn));
1979 else
1980 inet_ntop(AF_INET6,
1981 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
1982 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01001983
willy tarreauc1cae632005-12-17 14:12:23 +01001984 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01001985 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01001986 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01001987
willy tarreauc1cae632005-12-17 14:12:23 +01001988 tm = localtime(&s->logs.tv_accept.tv_sec);
1989 if (p->to_log & LW_REQ) {
willy tarreau25c4ea52005-12-18 00:49:49 +01001990 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c \"%s\"\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01001991 pn,
1992 (s->cli_addr.ss_family == AF_INET) ?
1993 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
1994 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01001995 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1996 tm->tm_hour, tm->tm_min, tm->tm_sec,
1997 pxid, srv,
1998 s->logs.t_request,
1999 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2000 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002001 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2002 s->logs.status,
2003 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002004 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2005 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002006 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2007 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2008 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2009 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01002010 uri);
2011 }
2012 else {
willy tarreau25c4ea52005-12-18 00:49:49 +01002013 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002014 pn,
2015 (s->cli_addr.ss_family == AF_INET) ?
2016 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2017 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002018 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2019 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002020 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002021 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002022 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2023 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002024 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01002025 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01002026 }
2027
2028 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002029}
2030
willy tarreaue39cd132005-12-17 13:00:18 +01002031
2032/*
willy tarreau0f7af912005-12-17 12:21:26 +01002033 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002034 * to an accept. It tries to accept as many connections as possible.
2035 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002036 */
2037int event_accept(int fd) {
2038 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002039 struct session *s;
2040 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002041 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002042
willy tarreau5cbea6f2005-12-17 12:48:26 +01002043 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002044 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002045 int laddr = sizeof(addr);
2046 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2047 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002048
willy tarreau5cbea6f2005-12-17 12:48:26 +01002049 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2050 Alert("out of memory in event_accept().\n");
2051 FD_CLR(fd, StaticReadEvent);
2052 p->state = PR_STIDLE;
2053 close(cfd);
2054 return 0;
2055 }
willy tarreau0f7af912005-12-17 12:21:26 +01002056
willy tarreau5cbea6f2005-12-17 12:48:26 +01002057 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2058 Alert("out of memory in event_accept().\n");
2059 FD_CLR(fd, StaticReadEvent);
2060 p->state = PR_STIDLE;
2061 close(cfd);
2062 pool_free(session, s);
2063 return 0;
2064 }
willy tarreau0f7af912005-12-17 12:21:26 +01002065
willy tarreau5cbea6f2005-12-17 12:48:26 +01002066 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002067 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002068 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2069 close(cfd);
2070 pool_free(task, t);
2071 pool_free(session, s);
2072 return 0;
2073 }
willy tarreau0f7af912005-12-17 12:21:26 +01002074
willy tarreau5cbea6f2005-12-17 12:48:26 +01002075 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2076 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2077 (char *) &one, sizeof(one)) == -1)) {
2078 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2079 close(cfd);
2080 pool_free(task, t);
2081 pool_free(session, s);
2082 return 0;
2083 }
willy tarreau0f7af912005-12-17 12:21:26 +01002084
willy tarreau9fe663a2005-12-17 13:02:59 +01002085 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2086 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2087 t->state = TASK_IDLE;
2088 t->process = process_session;
2089 t->context = s;
2090
2091 s->task = t;
2092 s->proxy = p;
2093 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2094 s->srv_state = SV_STIDLE;
2095 s->req = s->rep = NULL; /* will be allocated later */
2096 s->flags = 0;
2097 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2098 s->cli_fd = cfd;
2099 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002100 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002101 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002102
2103 s->logs.logwait = p->to_log;
2104 s->logs.tv_accept = now;
2105 s->logs.t_request = -1;
2106 s->logs.t_connect = -1;
2107 s->logs.t_data = -1;
2108 s->logs.t_close = 0;
2109 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002110 s->logs.cli_cookie = NULL;
2111 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002112 s->logs.status = -1;
2113 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002114
willy tarreau2f6ba652005-12-17 13:57:42 +01002115 s->uniq_id = totalconn;
2116
willy tarreau5cbea6f2005-12-17 12:48:26 +01002117 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2118 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002119 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002120 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002121
willy tarreau5cbea6f2005-12-17 12:48:26 +01002122 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002123 if (addr.ss_family != AF_INET ||
2124 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002125 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002126
willy tarreau9fe663a2005-12-17 13:02:59 +01002127 if (p->to_log) {
2128 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002129 if (s->logs.logwait & LW_CLIP)
2130 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002131 sess_log(s);
2132 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002133 else if (s->cli_addr.ss_family == AF_INET) {
2134 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2135 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2136 sn, sizeof(sn)) &&
2137 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2138 pn, sizeof(pn))) {
2139 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2140 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2141 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2142 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2143 }
2144 }
2145 else {
2146 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2147 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2148 sn, sizeof(sn)) &&
2149 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2150 pn, sizeof(pn))) {
2151 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2152 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2153 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2154 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2155 }
2156 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002157 }
willy tarreau0f7af912005-12-17 12:21:26 +01002158
willy tarreau9fe663a2005-12-17 13:02:59 +01002159 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002160 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002161 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002162 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002163 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002164 if (addr.ss_family != AF_INET ||
2165 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002166 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002167
willy tarreau8a86dbf2005-12-18 00:45:59 +01002168 if (s->cli_addr.ss_family == AF_INET) {
2169 char pn[INET_ADDRSTRLEN];
2170 inet_ntop(AF_INET,
2171 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2172 pn, sizeof(pn));
2173
2174 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2175 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2176 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2177 }
2178 else {
2179 char pn[INET6_ADDRSTRLEN];
2180 inet_ntop(AF_INET6,
2181 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2182 pn, sizeof(pn));
2183
2184 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2185 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2186 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2187 }
2188
willy tarreauef900ab2005-12-17 12:52:52 +01002189 write(1, trash, len);
2190 }
willy tarreau0f7af912005-12-17 12:21:26 +01002191
willy tarreau5cbea6f2005-12-17 12:48:26 +01002192 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2193 close(cfd); /* nothing can be done for this fd without memory */
2194 pool_free(task, t);
2195 pool_free(session, s);
2196 return 0;
2197 }
2198 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002199 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002200 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2201 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002202 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002203 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002204
willy tarreau5cbea6f2005-12-17 12:48:26 +01002205 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2206 pool_free(buffer, s->req);
2207 close(cfd); /* nothing can be done for this fd without memory */
2208 pool_free(task, t);
2209 pool_free(session, s);
2210 return 0;
2211 }
2212 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002213 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002214 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 +01002215
willy tarreau5cbea6f2005-12-17 12:48:26 +01002216 fdtab[cfd].read = &event_cli_read;
2217 fdtab[cfd].write = &event_cli_write;
2218 fdtab[cfd].owner = t;
2219 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002220
willy tarreau5cbea6f2005-12-17 12:48:26 +01002221 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002222 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2223 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2224 else
2225 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002226 }
2227 else {
2228 FD_SET(cfd, StaticReadEvent);
2229 }
2230
2231 fd_insert(cfd);
2232
2233 tv_eternity(&s->cnexpire);
2234 tv_eternity(&s->srexpire);
2235 tv_eternity(&s->swexpire);
2236 tv_eternity(&s->cwexpire);
2237
2238 if (s->proxy->clitimeout)
2239 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2240 else
2241 tv_eternity(&s->crexpire);
2242
2243 t->expire = s->crexpire;
2244
2245 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002246
2247 if (p->mode != PR_MODE_HEALTH)
2248 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002249
2250 p->nbconn++;
2251 actconn++;
2252 totalconn++;
2253
2254 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2255 } /* end of while (p->nbconn < p->maxconn) */
2256 return 0;
2257}
willy tarreau0f7af912005-12-17 12:21:26 +01002258
willy tarreau0f7af912005-12-17 12:21:26 +01002259
willy tarreau5cbea6f2005-12-17 12:48:26 +01002260/*
2261 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002262 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2263 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002264 * or -1 if an error occured.
2265 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002266int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002267 struct task *t = fdtab[fd].owner;
2268 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002269
willy tarreau5cbea6f2005-12-17 12:48:26 +01002270 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002271 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002272 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002273 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002274 if (skerr)
2275 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002276 else {
2277 if (s->proxy->options & PR_O_HTTP_CHK) {
2278 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002279 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002280 * so we'll send the request, and won't wake the checker up now.
2281 */
2282#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002283 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002284#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002285 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002286#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002287 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002288 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2289 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2290 return 0;
2291 }
2292 else
2293 s->result = -1;
2294 }
2295 else {
2296 /* good TCP connection is enough */
2297 s->result = 1;
2298 }
2299 }
2300
2301 task_wakeup(&rq, t);
2302 return 0;
2303}
2304
willy tarreau0f7af912005-12-17 12:21:26 +01002305
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002306/*
2307 * This function is used only for server health-checks. It handles
2308 * the server's reply to an HTTP request. It returns 1 if the server replies
2309 * 2xx or 3xx (valid responses), or -1 in other cases.
2310 */
2311int event_srv_chk_r(int fd) {
2312 char reply[64];
2313 int len;
2314 struct task *t = fdtab[fd].owner;
2315 struct server *s = t->context;
2316
2317 int skerr, lskerr;
2318 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002319
2320 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002321#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002322 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2323 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002324 len = recv(fd, reply, sizeof(reply), 0);
2325#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002326 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2327 * but the connection was closed on the remote end. Fortunately, recv still
2328 * works correctly and we don't need to do the getsockopt() on linux.
2329 */
2330 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002331#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002332 if ((len >= sizeof("HTTP/1.0 000")) &&
2333 !memcmp(reply, "HTTP/1.", 7) &&
2334 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2335 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002336
2337 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002338 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002339 return 0;
2340}
2341
2342
2343/*
2344 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2345 * and moves <end> just after the end of <str>.
2346 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2347 * the shift value (positive or negative) is returned.
2348 * If there's no space left, the move is not done.
2349 *
2350 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002351int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002352 int delta;
2353 int len;
2354
2355 len = strlen(str);
2356 delta = len - (end - pos);
2357
2358 if (delta + b->r >= b->data + BUFSIZE)
2359 return 0; /* no space left */
2360
2361 /* first, protect the end of the buffer */
2362 memmove(end + delta, end, b->data + b->l - end);
2363
2364 /* now, copy str over pos */
2365 memcpy(pos, str,len);
2366
willy tarreau5cbea6f2005-12-17 12:48:26 +01002367 /* we only move data after the displaced zone */
2368 if (b->r > pos) b->r += delta;
2369 if (b->w > pos) b->w += delta;
2370 if (b->h > pos) b->h += delta;
2371 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002372 b->l += delta;
2373
2374 return delta;
2375}
2376
willy tarreau8337c6b2005-12-17 13:41:01 +01002377/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002378 * len is 0.
2379 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002380int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002381 int delta;
2382
2383 delta = len - (end - pos);
2384
2385 if (delta + b->r >= b->data + BUFSIZE)
2386 return 0; /* no space left */
2387
2388 /* first, protect the end of the buffer */
2389 memmove(end + delta, end, b->data + b->l - end);
2390
2391 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002392 if (len)
2393 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002394
willy tarreau5cbea6f2005-12-17 12:48:26 +01002395 /* we only move data after the displaced zone */
2396 if (b->r > pos) b->r += delta;
2397 if (b->w > pos) b->w += delta;
2398 if (b->h > pos) b->h += delta;
2399 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002400 b->l += delta;
2401
2402 return delta;
2403}
2404
2405
2406int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2407 char *old_dst = dst;
2408
2409 while (*str) {
2410 if (*str == '\\') {
2411 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002412 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002413 int len, num;
2414
2415 num = *str - '0';
2416 str++;
2417
willy tarreau8a86dbf2005-12-18 00:45:59 +01002418 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002419 len = matches[num].rm_eo - matches[num].rm_so;
2420 memcpy(dst, src + matches[num].rm_so, len);
2421 dst += len;
2422 }
2423
2424 }
2425 else if (*str == 'x') {
2426 unsigned char hex1, hex2;
2427 str++;
2428
2429 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2430
2431 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2432 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2433 *dst++ = (hex1<<4) + hex2;
2434 }
2435 else
2436 *dst++ = *str++;
2437 }
2438 else
2439 *dst++ = *str++;
2440 }
2441 *dst = 0;
2442 return dst - old_dst;
2443}
2444
willy tarreau9fe663a2005-12-17 13:02:59 +01002445
willy tarreau0f7af912005-12-17 12:21:26 +01002446/*
2447 * manages the client FSM and its socket. BTW, it also tries to handle the
2448 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2449 * 0 else.
2450 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002451int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002452 int s = t->srv_state;
2453 int c = t->cli_state;
2454 struct buffer *req = t->req;
2455 struct buffer *rep = t->rep;
2456
willy tarreau750a4722005-12-17 13:21:24 +01002457#ifdef DEBUG_FULL
2458 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2459#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002460 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2461 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2462 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2463 //);
2464 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002465 /* now parse the partial (or complete) headers */
2466 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2467 char *ptr;
2468 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002469
willy tarreau5cbea6f2005-12-17 12:48:26 +01002470 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002471
willy tarreau0f7af912005-12-17 12:21:26 +01002472 /* look for the end of the current header */
2473 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2474 ptr++;
2475
willy tarreau5cbea6f2005-12-17 12:48:26 +01002476 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002477 int line, len;
2478 /* we can only get here after an end of headers */
2479 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002480
willy tarreaue39cd132005-12-17 13:00:18 +01002481 if (t->flags & SN_CLDENY) {
2482 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002483 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002484 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002485 if (!(t->flags & SN_ERR_MASK))
2486 t->flags |= SN_ERR_PRXCOND;
2487 if (!(t->flags & SN_FINST_MASK))
2488 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002489 return 1;
2490 }
2491
willy tarreau5cbea6f2005-12-17 12:48:26 +01002492 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002493 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2494 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002495 }
willy tarreau0f7af912005-12-17 12:21:26 +01002496
willy tarreau9fe663a2005-12-17 13:02:59 +01002497 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002498 if (t->cli_addr.ss_family == AF_INET) {
2499 unsigned char *pn;
2500 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
2501 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2502 pn[0], pn[1], pn[2], pn[3]);
2503 buffer_replace2(req, req->h, req->h, trash, len);
2504 }
2505 else if (t->cli_addr.ss_family == AF_INET6) {
2506 char pn[INET6_ADDRSTRLEN];
2507 inet_ntop(AF_INET6,
2508 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2509 pn, sizeof(pn));
2510 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
2511 buffer_replace2(req, req->h, req->h, trash, len);
2512 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002513 }
2514
willy tarreau25c4ea52005-12-18 00:49:49 +01002515 /* add a "connection: close" line if needed */
2516 if (t->proxy->options & PR_O_HTTP_CLOSE)
2517 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
2518
willy tarreaucd878942005-12-17 13:27:43 +01002519 if (!memcmp(req->data, "POST ", 5))
2520 t->flags |= SN_POST; /* this is a POST request */
2521
willy tarreau5cbea6f2005-12-17 12:48:26 +01002522 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002523 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002524
willy tarreau750a4722005-12-17 13:21:24 +01002525 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002526 /* FIXME: we'll set the client in a wait state while we try to
2527 * connect to the server. Is this really needed ? wouldn't it be
2528 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002529 //FD_CLR(t->cli_fd, StaticReadEvent);
2530 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002531
2532 /* FIXME: if we break here (as up to 1.1.23), having the client
2533 * shutdown its connection can lead to an abort further.
2534 * it's better to either return 1 or even jump directly to the
2535 * data state which will save one schedule.
2536 */
2537 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002538
2539 if (!t->proxy->clitimeout ||
2540 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2541 /* If the client has no timeout, or if the server is not ready yet,
2542 * and we know for sure that it can expire, then it's cleaner to
2543 * disable the timeout on the client side so that too low values
2544 * cannot make the sessions abort too early.
2545 */
2546 tv_eternity(&t->crexpire);
2547
willy tarreau197e8ec2005-12-17 14:10:59 +01002548 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002549 }
willy tarreau0f7af912005-12-17 12:21:26 +01002550
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2552 if (ptr > req->r - 2) {
2553 /* this is a partial header, let's wait for more to come */
2554 req->lr = ptr;
2555 break;
2556 }
willy tarreau0f7af912005-12-17 12:21:26 +01002557
willy tarreau5cbea6f2005-12-17 12:48:26 +01002558 /* now we know that *ptr is either \r or \n,
2559 * and that there are at least 1 char after it.
2560 */
2561 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2562 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2563 else
2564 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002565
willy tarreau5cbea6f2005-12-17 12:48:26 +01002566 /*
2567 * now we know that we have a full header ; we can do whatever
2568 * we want with these pointers :
2569 * req->h = beginning of header
2570 * ptr = end of header (first \r or \n)
2571 * req->lr = beginning of next line (next rep->h)
2572 * req->r = end of data (not used at this stage)
2573 */
willy tarreau0f7af912005-12-17 12:21:26 +01002574
willy tarreau8337c6b2005-12-17 13:41:01 +01002575 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002576 /* we have a complete HTTP request that we must log */
2577 int urilen;
2578
willy tarreaua1598082005-12-17 13:08:06 +01002579 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002580 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002581 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002582 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002583 if (!(t->flags & SN_ERR_MASK))
2584 t->flags |= SN_ERR_PRXCOND;
2585 if (!(t->flags & SN_FINST_MASK))
2586 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002587 return 1;
2588 }
2589
2590 urilen = ptr - req->h;
2591 if (urilen >= REQURI_LEN)
2592 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002593 memcpy(t->logs.uri, req->h, urilen);
2594 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002595
willy tarreaua1598082005-12-17 13:08:06 +01002596 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002597 sess_log(t);
2598 }
2599
willy tarreau5cbea6f2005-12-17 12:48:26 +01002600 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002601
willy tarreau9fe663a2005-12-17 13:02:59 +01002602 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002604 len = sprintf(trash, "%08x:%s.clihdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002605 max = ptr - req->h;
2606 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002607 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 trash[len++] = '\n';
2609 write(1, trash, len);
2610 }
willy tarreau0f7af912005-12-17 12:21:26 +01002611
willy tarreau25c4ea52005-12-18 00:49:49 +01002612
2613 /* remove "connection: " if needed */
2614 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
2615 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
2616 delete_header = 1;
2617 }
2618
willy tarreau5cbea6f2005-12-17 12:48:26 +01002619 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01002620 if (!delete_header && t->proxy->req_exp != NULL
2621 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002622 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002623 char term;
2624
2625 term = *ptr;
2626 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002627 exp = t->proxy->req_exp;
2628 do {
2629 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2630 switch (exp->action) {
2631 case ACT_ALLOW:
2632 if (!(t->flags & SN_CLDENY))
2633 t->flags |= SN_CLALLOW;
2634 break;
2635 case ACT_REPLACE:
2636 if (!(t->flags & SN_CLDENY)) {
2637 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2638 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2639 }
2640 break;
2641 case ACT_REMOVE:
2642 if (!(t->flags & SN_CLDENY))
2643 delete_header = 1;
2644 break;
2645 case ACT_DENY:
2646 if (!(t->flags & SN_CLALLOW))
2647 t->flags |= SN_CLDENY;
2648 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002649 case ACT_PASS: /* we simply don't deny this one */
2650 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002651 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002652 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002653 }
willy tarreaue39cd132005-12-17 13:00:18 +01002654 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002655 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002656 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002657
willy tarreau240afa62005-12-17 13:14:35 +01002658 /* Now look for cookies. Conforming to RFC2109, we have to support
2659 * attributes whose name begin with a '$', and associate them with
2660 * the right cookie, if we want to delete this cookie.
2661 * So there are 3 cases for each cookie read :
2662 * 1) it's a special attribute, beginning with a '$' : ignore it.
2663 * 2) it's a server id cookie that we *MAY* want to delete : save
2664 * some pointers on it (last semi-colon, beginning of cookie...)
2665 * 3) it's an application cookie : we *MAY* have to delete a previous
2666 * "special" cookie.
2667 * At the end of loop, if a "special" cookie remains, we may have to
2668 * remove it. If no application cookie persists in the header, we
2669 * *MUST* delete it
2670 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002671 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002672 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01002673 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002674 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002675 char *del_colon, *del_cookie, *colon;
2676 int app_cookies;
2677
willy tarreau5cbea6f2005-12-17 12:48:26 +01002678 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002679 colon = p1;
2680 /* del_cookie == NULL => nothing to be deleted */
2681 del_colon = del_cookie = NULL;
2682 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002683
2684 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002685 /* skip spaces and colons, but keep an eye on these ones */
2686 while (p1 < ptr) {
2687 if (*p1 == ';' || *p1 == ',')
2688 colon = p1;
2689 else if (!isspace((int)*p1))
2690 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002691 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002692 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002693
2694 if (p1 == ptr)
2695 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002696
2697 /* p1 is at the beginning of the cookie name */
2698 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002699 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002700 p2++;
2701
2702 if (p2 == ptr)
2703 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002704
2705 p3 = p2 + 1; /* skips the '=' sign */
2706 if (p3 == ptr)
2707 break;
2708
willy tarreau240afa62005-12-17 13:14:35 +01002709 p4 = p3;
2710 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711 p4++;
2712
2713 /* here, we have the cookie name between p1 and p2,
2714 * and its value between p3 and p4.
2715 * we can process it.
2716 */
2717
willy tarreau240afa62005-12-17 13:14:35 +01002718 if (*p1 == '$') {
2719 /* skip this one */
2720 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002721 else {
2722 /* first, let's see if we want to capture it */
2723 if (t->proxy->capture_name != NULL &&
2724 t->logs.cli_cookie == NULL &&
2725 (p4 - p1 >= t->proxy->capture_namelen) &&
2726 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2727 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002728
willy tarreau8337c6b2005-12-17 13:41:01 +01002729 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2730 Alert("HTTP logging : out of memory.\n");
2731 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002732
willy tarreau8337c6b2005-12-17 13:41:01 +01002733 if (log_len > t->proxy->capture_len)
2734 log_len = t->proxy->capture_len;
2735 memcpy(t->logs.cli_cookie, p1, log_len);
2736 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002737 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002738
2739 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2740 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2741 /* Cool... it's the right one */
2742 struct server *srv = t->proxy->srv;
2743
2744 while (srv &&
2745 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2746 srv = srv->next;
2747 }
2748
willy tarreau036e1ce2005-12-17 13:46:33 +01002749 if (!srv) {
2750 t->flags &= ~SN_CK_MASK;
2751 t->flags |= SN_CK_INVALID;
2752 }
2753 else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002754 /* we found the server and it's usable */
willy tarreau036e1ce2005-12-17 13:46:33 +01002755 t->flags &= ~SN_CK_MASK;
2756 t->flags |= SN_CK_VALID | SN_DIRECT;
willy tarreau8337c6b2005-12-17 13:41:01 +01002757 t->srv = srv;
2758 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002759 else {
2760 t->flags &= ~SN_CK_MASK;
2761 t->flags |= SN_CK_DOWN;
2762 }
2763
willy tarreau8337c6b2005-12-17 13:41:01 +01002764 /* if this cookie was set in insert+indirect mode, then it's better that the
2765 * server never sees it.
2766 */
2767 if (del_cookie == NULL &&
2768 (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 +01002769 del_cookie = p1;
2770 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002771 }
willy tarreau240afa62005-12-17 13:14:35 +01002772 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002773 else {
2774 /* now we know that we must keep this cookie since it's
2775 * not ours. But if we wanted to delete our cookie
2776 * earlier, we cannot remove the complete header, but we
2777 * can remove the previous block itself.
2778 */
2779 app_cookies++;
2780
2781 if (del_cookie != NULL) {
2782 buffer_replace2(req, del_cookie, p1, NULL, 0);
2783 p4 -= (p1 - del_cookie);
2784 ptr -= (p1 - del_cookie);
2785 del_cookie = del_colon = NULL;
2786 }
willy tarreau240afa62005-12-17 13:14:35 +01002787 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002788 }
willy tarreau240afa62005-12-17 13:14:35 +01002789
willy tarreau5cbea6f2005-12-17 12:48:26 +01002790 /* we'll have to look for another cookie ... */
2791 p1 = p4;
2792 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002793
2794 /* There's no more cookie on this line.
2795 * We may have marked the last one(s) for deletion.
2796 * We must do this now in two ways :
2797 * - if there is no app cookie, we simply delete the header ;
2798 * - if there are app cookies, we must delete the end of the
2799 * string properly, including the colon/semi-colon before
2800 * the cookie name.
2801 */
2802 if (del_cookie != NULL) {
2803 if (app_cookies) {
2804 buffer_replace2(req, del_colon, ptr, NULL, 0);
2805 /* WARNING! <ptr> becomes invalid for now. If some code
2806 * below needs to rely on it before the end of the global
2807 * header loop, we need to correct it with this code :
2808 * ptr = del_colon;
2809 */
2810 }
2811 else
2812 delete_header = 1;
2813 }
2814 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002815
2816 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002817 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002818 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002819 }
willy tarreau240afa62005-12-17 13:14:35 +01002820 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2821
willy tarreau5cbea6f2005-12-17 12:48:26 +01002822 req->h = req->lr;
2823 } /* while (req->lr < req->r) */
2824
2825 /* end of header processing (even if incomplete) */
2826
willy tarreauef900ab2005-12-17 12:52:52 +01002827 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2828 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2829 * full. We cannot loop here since event_cli_read will disable it only if
2830 * req->l == rlim-data
2831 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002832 FD_SET(t->cli_fd, StaticReadEvent);
2833 if (t->proxy->clitimeout)
2834 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2835 else
2836 tv_eternity(&t->crexpire);
2837 }
2838
willy tarreaue39cd132005-12-17 13:00:18 +01002839 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002840 * won't be able to free more later, so the session will never terminate.
2841 */
willy tarreaue39cd132005-12-17 13:00:18 +01002842 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002843 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01002844 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01002845 if (!(t->flags & SN_ERR_MASK))
2846 t->flags |= SN_ERR_PRXCOND;
2847 if (!(t->flags & SN_FINST_MASK))
2848 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002849 return 1;
2850 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002851 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002852 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002853 tv_eternity(&t->crexpire);
2854 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002855 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002856 if (!(t->flags & SN_ERR_MASK))
2857 t->flags |= SN_ERR_CLICL;
2858 if (!(t->flags & SN_FINST_MASK))
2859 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002860 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002861 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002862 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2863
2864 /* read timeout : give up with an error message.
2865 */
2866 t->logs.status = 408;
2867 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01002868 if (!(t->flags & SN_ERR_MASK))
2869 t->flags |= SN_ERR_CLITO;
2870 if (!(t->flags & SN_FINST_MASK))
2871 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01002872 return 1;
2873 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002874
2875 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002876 }
2877 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01002878 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01002879 /* FIXME: this error handling is partly buggy because we always report
2880 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2881 * or HEADER phase. BTW, it's not logical to expire the client while
2882 * we're waiting for the server to connect.
2883 */
willy tarreau0f7af912005-12-17 12:21:26 +01002884 /* read or write error */
2885 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002886 tv_eternity(&t->crexpire);
2887 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002888 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002889 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002890 if (!(t->flags & SN_ERR_MASK))
2891 t->flags |= SN_ERR_CLICL;
2892 if (!(t->flags & SN_FINST_MASK))
2893 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002894 return 1;
2895 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002896 /* last read, or end of server write */
2897 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002898 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002899 tv_eternity(&t->crexpire);
2900 shutdown(t->cli_fd, SHUT_RD);
2901 t->cli_state = CL_STSHUTR;
2902 return 1;
2903 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002904 /* last server read and buffer empty */
2905 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002906 FD_CLR(t->cli_fd, StaticWriteEvent);
2907 tv_eternity(&t->cwexpire);
2908 shutdown(t->cli_fd, SHUT_WR);
2909 t->cli_state = CL_STSHUTW;
2910 return 1;
2911 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002912 /* read timeout */
2913 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2914 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01002915 tv_eternity(&t->crexpire);
2916 shutdown(t->cli_fd, SHUT_RD);
2917 t->cli_state = CL_STSHUTR;
2918 if (!(t->flags & SN_ERR_MASK))
2919 t->flags |= SN_ERR_CLITO;
2920 if (!(t->flags & SN_FINST_MASK))
2921 t->flags |= SN_FINST_D;
2922 return 1;
2923 }
2924 /* write timeout */
2925 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2926 FD_CLR(t->cli_fd, StaticWriteEvent);
2927 tv_eternity(&t->cwexpire);
2928 shutdown(t->cli_fd, SHUT_WR);
2929 t->cli_state = CL_STSHUTW;
2930 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01002931 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01002932 if (!(t->flags & SN_FINST_MASK))
2933 t->flags |= SN_FINST_D;
2934 return 1;
2935 }
willy tarreau0f7af912005-12-17 12:21:26 +01002936
willy tarreauc58fc692005-12-17 14:13:08 +01002937 if (req->l >= req->rlim - req->data) {
2938 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002939 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002940 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002941 FD_CLR(t->cli_fd, StaticReadEvent);
2942 tv_eternity(&t->crexpire);
2943 }
2944 }
2945 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002946 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002947 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2948 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01002949 if (!t->proxy->clitimeout ||
2950 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2951 /* If the client has no timeout, or if the server not ready yet, and we
2952 * know for sure that it can expire, then it's cleaner to disable the
2953 * timeout on the client side so that too low values cannot make the
2954 * sessions abort too early.
2955 */
willy tarreau0f7af912005-12-17 12:21:26 +01002956 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01002957 else
2958 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01002959 }
2960 }
2961
2962 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01002963 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002964 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2965 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2966 tv_eternity(&t->cwexpire);
2967 }
2968 }
2969 else { /* buffer not empty */
2970 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2971 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002972 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002973 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002974 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2975 t->crexpire = t->cwexpire;
2976 }
willy tarreau0f7af912005-12-17 12:21:26 +01002977 else
2978 tv_eternity(&t->cwexpire);
2979 }
2980 }
2981 return 0; /* other cases change nothing */
2982 }
2983 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002984 if (t->res_cw == RES_ERROR) {
2985 tv_eternity(&t->cwexpire);
2986 fd_delete(t->cli_fd);
2987 t->cli_state = CL_STCLOSE;
2988 if (!(t->flags & SN_ERR_MASK))
2989 t->flags |= SN_ERR_CLICL;
2990 if (!(t->flags & SN_FINST_MASK))
2991 t->flags |= SN_FINST_D;
2992 return 1;
2993 }
2994 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002995 tv_eternity(&t->cwexpire);
2996 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002997 t->cli_state = CL_STCLOSE;
2998 return 1;
2999 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003000 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3001 tv_eternity(&t->cwexpire);
3002 fd_delete(t->cli_fd);
3003 t->cli_state = CL_STCLOSE;
3004 if (!(t->flags & SN_ERR_MASK))
3005 t->flags |= SN_ERR_CLITO;
3006 if (!(t->flags & SN_FINST_MASK))
3007 t->flags |= SN_FINST_D;
3008 return 1;
3009 }
willy tarreau0f7af912005-12-17 12:21:26 +01003010 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003011 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003012 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3013 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3014 tv_eternity(&t->cwexpire);
3015 }
3016 }
3017 else { /* buffer not empty */
3018 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3019 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003020 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003021 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003022 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3023 t->crexpire = t->cwexpire;
3024 }
willy tarreau0f7af912005-12-17 12:21:26 +01003025 else
3026 tv_eternity(&t->cwexpire);
3027 }
3028 }
3029 return 0;
3030 }
3031 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003032 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003033 tv_eternity(&t->crexpire);
3034 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003035 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003036 if (!(t->flags & SN_ERR_MASK))
3037 t->flags |= SN_ERR_CLICL;
3038 if (!(t->flags & SN_FINST_MASK))
3039 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003040 return 1;
3041 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003042 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3043 tv_eternity(&t->crexpire);
3044 fd_delete(t->cli_fd);
3045 t->cli_state = CL_STCLOSE;
3046 return 1;
3047 }
3048 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3049 tv_eternity(&t->crexpire);
3050 fd_delete(t->cli_fd);
3051 t->cli_state = CL_STCLOSE;
3052 if (!(t->flags & SN_ERR_MASK))
3053 t->flags |= SN_ERR_CLITO;
3054 if (!(t->flags & SN_FINST_MASK))
3055 t->flags |= SN_FINST_D;
3056 return 1;
3057 }
willy tarreauef900ab2005-12-17 12:52:52 +01003058 else if (req->l >= req->rlim - req->data) {
3059 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003060 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003061 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003062 FD_CLR(t->cli_fd, StaticReadEvent);
3063 tv_eternity(&t->crexpire);
3064 }
3065 }
3066 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003067 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003068 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3069 FD_SET(t->cli_fd, StaticReadEvent);
3070 if (t->proxy->clitimeout)
3071 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3072 else
3073 tv_eternity(&t->crexpire);
3074 }
3075 }
3076 return 0;
3077 }
3078 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003079 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003080 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003081 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003082 write(1, trash, len);
3083 }
3084 return 0;
3085 }
3086 return 0;
3087}
3088
3089
3090/*
3091 * manages the server FSM and its socket. It returns 1 if a state has changed
3092 * (and a resync may be needed), 0 else.
3093 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003094int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003095 int s = t->srv_state;
3096 int c = t->cli_state;
3097 struct buffer *req = t->req;
3098 struct buffer *rep = t->rep;
3099
willy tarreau750a4722005-12-17 13:21:24 +01003100#ifdef DEBUG_FULL
3101 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3102#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3104 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3105 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3106 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003107 if (s == SV_STIDLE) {
3108 if (c == CL_STHEADERS)
3109 return 0; /* stay in idle, waiting for data to reach the client side */
3110 else if (c == CL_STCLOSE ||
3111 c == CL_STSHUTW ||
3112 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3113 tv_eternity(&t->cnexpire);
3114 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003115 if (!(t->flags & SN_ERR_MASK))
3116 t->flags |= SN_ERR_CLICL;
3117 if (!(t->flags & SN_FINST_MASK))
3118 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003119 return 1;
3120 }
3121 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003122 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003123 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3124 t->srv_state = SV_STCONN;
3125 }
3126 else { /* try again */
3127 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003128 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003129 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003130 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003131 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3132 t->flags &= ~SN_CK_MASK;
3133 t->flags |= SN_CK_DOWN;
3134 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003135 }
3136
3137 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003138 t->srv_state = SV_STCONN;
3139 break;
3140 }
3141 }
3142 if (t->conn_retries < 0) {
3143 /* if conn_retries < 0 or other error, let's abort */
3144 tv_eternity(&t->cnexpire);
3145 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003146 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003147 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003148 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003149 if (!(t->flags & SN_ERR_MASK))
3150 t->flags |= SN_ERR_SRVCL;
3151 if (!(t->flags & SN_FINST_MASK))
3152 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003153 }
3154 }
3155 return 1;
3156 }
3157 }
3158 else if (s == SV_STCONN) { /* connection in progress */
3159 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3160 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3161 return 0; /* nothing changed */
3162 }
3163 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3164 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3165 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003166 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003167 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003168 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003169 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003170 if (t->conn_retries >= 0) {
3171 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003172 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003173 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003174 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3175 t->flags &= ~SN_CK_MASK;
3176 t->flags |= SN_CK_DOWN;
3177 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003178 }
3179 if (connect_server(t) == 0)
3180 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003181 }
3182 /* if conn_retries < 0 or other error, let's abort */
3183 tv_eternity(&t->cnexpire);
3184 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003185 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003186 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003187 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003188 if (!(t->flags & SN_ERR_MASK))
3189 t->flags |= SN_ERR_SRVCL;
3190 if (!(t->flags & SN_FINST_MASK))
3191 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003192 return 1;
3193 }
3194 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003195 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003196
willy tarreau0f7af912005-12-17 12:21:26 +01003197 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003198 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003199 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003200 tv_eternity(&t->swexpire);
3201 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003202 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003203 if (t->proxy->srvtimeout) {
3204 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3205 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3206 t->srexpire = t->swexpire;
3207 }
3208 else
3209 tv_eternity(&t->swexpire);
3210 }
willy tarreau0f7af912005-12-17 12:21:26 +01003211
3212 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3213 FD_SET(t->srv_fd, StaticReadEvent);
3214 if (t->proxy->srvtimeout)
3215 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3216 else
3217 tv_eternity(&t->srexpire);
3218
3219 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003220 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01003221
3222 /* if the user wants to log as soon as possible, without counting
3223 bytes from the server, then this is the right moment. */
3224 if (!(t->logs.logwait & LW_BYTES)) {
3225 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
3226 sess_log(t);
3227 }
willy tarreau0f7af912005-12-17 12:21:26 +01003228 }
willy tarreauef900ab2005-12-17 12:52:52 +01003229 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003230 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003231 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3232 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003233 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003234 return 1;
3235 }
3236 }
3237 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003238 /* now parse the partial (or complete) headers */
3239 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3240 char *ptr;
3241 int delete_header;
3242
3243 ptr = rep->lr;
3244
3245 /* look for the end of the current header */
3246 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3247 ptr++;
3248
3249 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003250 int line, len;
3251
3252 /* we can only get here after an end of headers */
3253 /* we'll have something else to do here : add new headers ... */
3254
willy tarreaucd878942005-12-17 13:27:43 +01003255 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3256 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003257 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003258 * insert a set-cookie here, except if we want to insert only on POST
3259 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003260 */
willy tarreau750a4722005-12-17 13:21:24 +01003261 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003262 t->proxy->cookie_name,
3263 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003264
willy tarreau036e1ce2005-12-17 13:46:33 +01003265 t->flags |= SN_SCK_INSERTED;
3266
willy tarreau750a4722005-12-17 13:21:24 +01003267 /* Here, we will tell an eventual cache on the client side that we don't
3268 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3269 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3270 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3271 */
willy tarreau240afa62005-12-17 13:14:35 +01003272 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003273 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3274 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003275
willy tarreau750a4722005-12-17 13:21:24 +01003276 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003277 }
3278
3279 /* headers to be added */
3280 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003281 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3282 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003283 }
3284
willy tarreau25c4ea52005-12-18 00:49:49 +01003285 /* add a "connection: close" line if needed */
3286 if (t->proxy->options & PR_O_HTTP_CLOSE)
3287 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
3288
willy tarreau5cbea6f2005-12-17 12:48:26 +01003289 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003290 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003291 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01003292
3293 /* if the user wants to log as soon as possible, without counting
3294 bytes from the server, then this is the right moment. */
3295 if (!(t->logs.logwait & LW_BYTES)) {
3296 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
3297 t->logs.bytes = rep->h - rep->data;
3298 sess_log(t);
3299 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003300 break;
3301 }
3302
3303 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3304 if (ptr > rep->r - 2) {
3305 /* this is a partial header, let's wait for more to come */
3306 rep->lr = ptr;
3307 break;
3308 }
3309
3310 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3311 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3312
3313 /* now we know that *ptr is either \r or \n,
3314 * and that there are at least 1 char after it.
3315 */
3316 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3317 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3318 else
3319 rep->lr = ptr + 2; /* \r\n or \n\r */
3320
3321 /*
3322 * now we know that we have a full header ; we can do whatever
3323 * we want with these pointers :
3324 * rep->h = beginning of header
3325 * ptr = end of header (first \r or \n)
3326 * rep->lr = beginning of next line (next rep->h)
3327 * rep->r = end of data (not used at this stage)
3328 */
3329
willy tarreaua1598082005-12-17 13:08:06 +01003330
3331 if (t->logs.logwait & LW_RESP) {
3332 t->logs.logwait &= ~LW_RESP;
3333 t->logs.status = atoi(rep->h + 9);
3334 }
3335
willy tarreau5cbea6f2005-12-17 12:48:26 +01003336 delete_header = 0;
3337
willy tarreau9fe663a2005-12-17 13:02:59 +01003338 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003339 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003340 len = sprintf(trash, "%08x:%s.srvhdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003341 max = ptr - rep->h;
3342 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003343 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344 trash[len++] = '\n';
3345 write(1, trash, len);
3346 }
3347
willy tarreau25c4ea52005-12-18 00:49:49 +01003348 /* remove "connection: " if needed */
3349 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3350 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
3351 delete_header = 1;
3352 }
3353
willy tarreau5cbea6f2005-12-17 12:48:26 +01003354 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003355 if (!delete_header && t->proxy->rsp_exp != NULL
3356 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003357 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003358 char term;
3359
3360 term = *ptr;
3361 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003362 exp = t->proxy->rsp_exp;
3363 do {
3364 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3365 switch (exp->action) {
3366 case ACT_ALLOW:
3367 if (!(t->flags & SN_SVDENY))
3368 t->flags |= SN_SVALLOW;
3369 break;
3370 case ACT_REPLACE:
3371 if (!(t->flags & SN_SVDENY)) {
3372 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3373 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3374 }
3375 break;
3376 case ACT_REMOVE:
3377 if (!(t->flags & SN_SVDENY))
3378 delete_header = 1;
3379 break;
3380 case ACT_DENY:
3381 if (!(t->flags & SN_SVALLOW))
3382 t->flags |= SN_SVDENY;
3383 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003384 case ACT_PASS: /* we simply don't deny this one */
3385 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003386 }
3387 break;
3388 }
willy tarreaue39cd132005-12-17 13:00:18 +01003389 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003390 *ptr = term; /* restore the string terminator */
3391 }
3392
3393 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003394 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3395 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
3396 && (ptr >= rep->h + 12)
willy tarreau906b2682005-12-17 13:49:52 +01003397 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003398 char *p1, *p2, *p3, *p4;
3399
3400 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3401
3402 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003403 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003404 p1++;
3405
3406 if (p1 == ptr || *p1 == ';') /* end of cookie */
3407 break;
3408
3409 /* p1 is at the beginning of the cookie name */
3410 p2 = p1;
3411
3412 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3413 p2++;
3414
3415 if (p2 == ptr || *p2 == ';') /* next cookie */
3416 break;
3417
3418 p3 = p2 + 1; /* skips the '=' sign */
3419 if (p3 == ptr)
3420 break;
3421
3422 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003423 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003424 p4++;
3425
3426 /* here, we have the cookie name between p1 and p2,
3427 * and its value between p3 and p4.
3428 * we can process it.
3429 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003430
3431 /* first, let's see if we want to capture it */
3432 if (t->proxy->capture_name != NULL &&
3433 t->logs.srv_cookie == NULL &&
3434 (p4 - p1 >= t->proxy->capture_namelen) &&
3435 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3436 int log_len = p4 - p1;
3437
3438 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3439 Alert("HTTP logging : out of memory.\n");
3440 }
3441
3442 if (log_len > t->proxy->capture_len)
3443 log_len = t->proxy->capture_len;
3444 memcpy(t->logs.srv_cookie, p1, log_len);
3445 t->logs.srv_cookie[log_len] = 0;
3446 }
3447
3448 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3449 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003450 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003451 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003452
3453 /* If the cookie is in insert mode on a known server, we'll delete
3454 * this occurrence because we'll insert another one later.
3455 * We'll delete it too if the "indirect" option is set and we're in
3456 * a direct access. */
3457 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003458 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003459 /* this header must be deleted */
3460 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003461 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003462 }
3463 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3464 /* replace bytes p3->p4 with the cookie name associated
3465 * with this server since we know it.
3466 */
3467 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003468 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003469 }
3470 break;
3471 }
3472 else {
3473 // fprintf(stderr,"Ignoring unknown cookie : ");
3474 // write(2, p1, p2-p1);
3475 // fprintf(stderr," = ");
3476 // write(2, p3, p4-p3);
3477 // fprintf(stderr,"\n");
3478 }
3479 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3480 } /* we're now at the end of the cookie value */
3481 } /* end of cookie processing */
3482
3483 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003484 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003485 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003486
willy tarreau5cbea6f2005-12-17 12:48:26 +01003487 rep->h = rep->lr;
3488 } /* while (rep->lr < rep->r) */
3489
3490 /* end of header processing (even if incomplete) */
3491
willy tarreauef900ab2005-12-17 12:52:52 +01003492 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3493 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3494 * full. We cannot loop here since event_srv_read will disable it only if
3495 * rep->l == rlim-data
3496 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003497 FD_SET(t->srv_fd, StaticReadEvent);
3498 if (t->proxy->srvtimeout)
3499 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3500 else
3501 tv_eternity(&t->srexpire);
3502 }
willy tarreau0f7af912005-12-17 12:21:26 +01003503
willy tarreau8337c6b2005-12-17 13:41:01 +01003504 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003505 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003506 tv_eternity(&t->srexpire);
3507 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003508 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003509 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003510 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003511 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003512 if (!(t->flags & SN_ERR_MASK))
3513 t->flags |= SN_ERR_SRVCL;
3514 if (!(t->flags & SN_FINST_MASK))
3515 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003516 return 1;
3517 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003518 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003519 * since we are in header mode, if there's no space left for headers, we
3520 * won't be able to free more later, so the session will never terminate.
3521 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003522 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 +01003523 FD_CLR(t->srv_fd, StaticReadEvent);
3524 tv_eternity(&t->srexpire);
3525 shutdown(t->srv_fd, SHUT_RD);
3526 t->srv_state = SV_STSHUTR;
3527 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003528 }
3529 /* read timeout : return a 504 to the client.
3530 */
3531 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3532 tv_eternity(&t->srexpire);
3533 tv_eternity(&t->swexpire);
3534 fd_delete(t->srv_fd);
3535 t->srv_state = SV_STCLOSE;
3536 t->logs.status = 504;
3537 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003538 if (!(t->flags & SN_ERR_MASK))
3539 t->flags |= SN_ERR_SRVTO;
3540 if (!(t->flags & SN_FINST_MASK))
3541 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003542 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003543
3544 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003545 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003546 /* FIXME!!! here, we don't want to switch to SHUTW if the
3547 * client shuts read too early, because we may still have
3548 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01003549 * The side-effect is that if the client completely closes its
3550 * connection during SV_STHEADER, the connection to the server
3551 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01003552 */
willy tarreau036e1ce2005-12-17 13:46:33 +01003553 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003554 FD_CLR(t->srv_fd, StaticWriteEvent);
3555 tv_eternity(&t->swexpire);
3556 shutdown(t->srv_fd, SHUT_WR);
3557 t->srv_state = SV_STSHUTW;
3558 return 1;
3559 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003560 /* write timeout */
3561 /* FIXME!!! here, we don't want to switch to SHUTW if the
3562 * client shuts read too early, because we may still have
3563 * some work to do on the headers.
3564 */
3565 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3566 FD_CLR(t->srv_fd, StaticWriteEvent);
3567 tv_eternity(&t->swexpire);
3568 shutdown(t->srv_fd, SHUT_WR);
3569 t->srv_state = SV_STSHUTW;
3570 if (!(t->flags & SN_ERR_MASK))
3571 t->flags |= SN_ERR_SRVTO;
3572 if (!(t->flags & SN_FINST_MASK))
3573 t->flags |= SN_FINST_H;
3574 return 1;
3575 }
willy tarreau0f7af912005-12-17 12:21:26 +01003576
3577 if (req->l == 0) {
3578 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3579 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3580 tv_eternity(&t->swexpire);
3581 }
3582 }
3583 else { /* client buffer not empty */
3584 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3585 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003586 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003587 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003588 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3589 t->srexpire = t->swexpire;
3590 }
willy tarreau0f7af912005-12-17 12:21:26 +01003591 else
3592 tv_eternity(&t->swexpire);
3593 }
3594 }
3595
willy tarreau5cbea6f2005-12-17 12:48:26 +01003596 /* be nice with the client side which would like to send a complete header
3597 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3598 * would read all remaining data at once ! The client should not write past rep->lr
3599 * when the server is in header state.
3600 */
3601 //return header_processed;
3602 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003603 }
3604 else if (s == SV_STDATA) {
3605 /* read or write error */
3606 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003607 tv_eternity(&t->srexpire);
3608 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003609 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003610 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003611 if (!(t->flags & SN_ERR_MASK))
3612 t->flags |= SN_ERR_SRVCL;
3613 if (!(t->flags & SN_FINST_MASK))
3614 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003615 return 1;
3616 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003617 /* last read, or end of client write */
3618 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003619 FD_CLR(t->srv_fd, StaticReadEvent);
3620 tv_eternity(&t->srexpire);
3621 shutdown(t->srv_fd, SHUT_RD);
3622 t->srv_state = SV_STSHUTR;
3623 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01003624 }
3625 /* end of client read and no more data to send */
3626 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
3627 FD_CLR(t->srv_fd, StaticWriteEvent);
3628 tv_eternity(&t->swexpire);
3629 shutdown(t->srv_fd, SHUT_WR);
3630 t->srv_state = SV_STSHUTW;
3631 return 1;
3632 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003633 /* read timeout */
3634 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3635 FD_CLR(t->srv_fd, StaticReadEvent);
3636 tv_eternity(&t->srexpire);
3637 shutdown(t->srv_fd, SHUT_RD);
3638 t->srv_state = SV_STSHUTR;
3639 if (!(t->flags & SN_ERR_MASK))
3640 t->flags |= SN_ERR_SRVTO;
3641 if (!(t->flags & SN_FINST_MASK))
3642 t->flags |= SN_FINST_D;
3643 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003644 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003645 /* write timeout */
3646 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003647 FD_CLR(t->srv_fd, StaticWriteEvent);
3648 tv_eternity(&t->swexpire);
3649 shutdown(t->srv_fd, SHUT_WR);
3650 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01003651 if (!(t->flags & SN_ERR_MASK))
3652 t->flags |= SN_ERR_SRVTO;
3653 if (!(t->flags & SN_FINST_MASK))
3654 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003655 return 1;
3656 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003657
3658 /* recompute request time-outs */
3659 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003660 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3661 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3662 tv_eternity(&t->swexpire);
3663 }
3664 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003665 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01003666 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3667 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003668 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003669 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003670 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3671 t->srexpire = t->swexpire;
3672 }
willy tarreau0f7af912005-12-17 12:21:26 +01003673 else
3674 tv_eternity(&t->swexpire);
3675 }
3676 }
3677
willy tarreaub1ff9db2005-12-17 13:51:03 +01003678 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01003679 if (rep->l == BUFSIZE) { /* no room to read more data */
3680 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3681 FD_CLR(t->srv_fd, StaticReadEvent);
3682 tv_eternity(&t->srexpire);
3683 }
3684 }
3685 else {
3686 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3687 FD_SET(t->srv_fd, StaticReadEvent);
3688 if (t->proxy->srvtimeout)
3689 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3690 else
3691 tv_eternity(&t->srexpire);
3692 }
3693 }
3694
3695 return 0; /* other cases change nothing */
3696 }
3697 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003698 if (t->res_sw == RES_ERROR) {
3699 //FD_CLR(t->srv_fd, StaticWriteEvent);
3700 tv_eternity(&t->swexpire);
3701 fd_delete(t->srv_fd);
3702 //close(t->srv_fd);
3703 t->srv_state = SV_STCLOSE;
3704 if (!(t->flags & SN_ERR_MASK))
3705 t->flags |= SN_ERR_SRVCL;
3706 if (!(t->flags & SN_FINST_MASK))
3707 t->flags |= SN_FINST_D;
3708 return 1;
3709 }
3710 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003711 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003712 tv_eternity(&t->swexpire);
3713 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003714 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003715 t->srv_state = SV_STCLOSE;
3716 return 1;
3717 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003718 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3719 //FD_CLR(t->srv_fd, StaticWriteEvent);
3720 tv_eternity(&t->swexpire);
3721 fd_delete(t->srv_fd);
3722 //close(t->srv_fd);
3723 t->srv_state = SV_STCLOSE;
3724 if (!(t->flags & SN_ERR_MASK))
3725 t->flags |= SN_ERR_SRVTO;
3726 if (!(t->flags & SN_FINST_MASK))
3727 t->flags |= SN_FINST_D;
3728 return 1;
3729 }
willy tarreau0f7af912005-12-17 12:21:26 +01003730 else if (req->l == 0) {
3731 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3732 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3733 tv_eternity(&t->swexpire);
3734 }
3735 }
3736 else { /* buffer not empty */
3737 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3738 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003739 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003740 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003741 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3742 t->srexpire = t->swexpire;
3743 }
willy tarreau0f7af912005-12-17 12:21:26 +01003744 else
3745 tv_eternity(&t->swexpire);
3746 }
3747 }
3748 return 0;
3749 }
3750 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003751 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003752 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003753 tv_eternity(&t->srexpire);
3754 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003755 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003756 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003757 if (!(t->flags & SN_ERR_MASK))
3758 t->flags |= SN_ERR_SRVCL;
3759 if (!(t->flags & SN_FINST_MASK))
3760 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003761 return 1;
3762 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003763 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
3764 //FD_CLR(t->srv_fd, StaticReadEvent);
3765 tv_eternity(&t->srexpire);
3766 fd_delete(t->srv_fd);
3767 //close(t->srv_fd);
3768 t->srv_state = SV_STCLOSE;
3769 return 1;
3770 }
3771 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3772 //FD_CLR(t->srv_fd, StaticReadEvent);
3773 tv_eternity(&t->srexpire);
3774 fd_delete(t->srv_fd);
3775 //close(t->srv_fd);
3776 t->srv_state = SV_STCLOSE;
3777 if (!(t->flags & SN_ERR_MASK))
3778 t->flags |= SN_ERR_SRVTO;
3779 if (!(t->flags & SN_FINST_MASK))
3780 t->flags |= SN_FINST_D;
3781 return 1;
3782 }
willy tarreau0f7af912005-12-17 12:21:26 +01003783 else if (rep->l == BUFSIZE) { /* no room to read more data */
3784 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3785 FD_CLR(t->srv_fd, StaticReadEvent);
3786 tv_eternity(&t->srexpire);
3787 }
3788 }
3789 else {
3790 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3791 FD_SET(t->srv_fd, StaticReadEvent);
3792 if (t->proxy->srvtimeout)
3793 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3794 else
3795 tv_eternity(&t->srexpire);
3796 }
3797 }
3798 return 0;
3799 }
3800 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003801 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003802 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003803 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003804 write(1, trash, len);
3805 }
3806 return 0;
3807 }
3808 return 0;
3809}
3810
3811
willy tarreau5cbea6f2005-12-17 12:48:26 +01003812/* Processes the client and server jobs of a session task, then
3813 * puts it back to the wait queue in a clean state, or
3814 * cleans up its resources if it must be deleted. Returns
3815 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003816 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003817int process_session(struct task *t) {
3818 struct session *s = t->context;
3819 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003820
willy tarreau5cbea6f2005-12-17 12:48:26 +01003821 do {
3822 fsm_resync = 0;
3823 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3824 fsm_resync |= process_cli(s);
3825 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3826 fsm_resync |= process_srv(s);
3827 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3828 } while (fsm_resync);
3829
3830 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003831 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003832 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003833
willy tarreau5cbea6f2005-12-17 12:48:26 +01003834 tv_min(&min1, &s->crexpire, &s->cwexpire);
3835 tv_min(&min2, &s->srexpire, &s->swexpire);
3836 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003837 tv_min(&t->expire, &min1, &min2);
3838
3839 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003840 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003841
willy tarreau5cbea6f2005-12-17 12:48:26 +01003842 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003843 }
3844
willy tarreau5cbea6f2005-12-17 12:48:26 +01003845 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003846 actconn--;
3847
willy tarreau9fe663a2005-12-17 13:02:59 +01003848 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003849 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003850 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n", s->uniq_id, s->proxy->id, (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003851 write(1, trash, len);
3852 }
3853
willy tarreau750a4722005-12-17 13:21:24 +01003854 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003855 if (s->rep != NULL)
3856 s->logs.bytes = s->rep->total;
3857
willy tarreau9fe663a2005-12-17 13:02:59 +01003858 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003859 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003860 sess_log(s);
3861
willy tarreau0f7af912005-12-17 12:21:26 +01003862 /* the task MUST not be in the run queue anymore */
3863 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003864 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003865 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003866 return -1; /* rest in peace for eternity */
3867}
3868
3869
3870
3871/*
3872 * manages a server health-check. Returns
3873 * the time the task accepts to wait, or -1 for infinity.
3874 */
3875int process_chk(struct task *t) {
3876 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01003877 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003878 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003879
willy tarreauef900ab2005-12-17 12:52:52 +01003880 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003881
3882 if (fd < 0) { /* no check currently running */
3883 //fprintf(stderr, "process_chk: 2\n");
3884 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3885 task_queue(t); /* restore t to its place in the task list */
3886 return tv_remain(&now, &t->expire);
3887 }
3888
3889 /* we'll initiate a new check */
3890 s->result = 0; /* no result yet */
3891 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003892 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003893 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3894 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3895 //fprintf(stderr, "process_chk: 3\n");
3896
willy tarreaua41a8b42005-12-17 14:02:24 +01003897 /* we'll connect to the check port on the server */
3898 sa = s->addr;
3899 sa.sin_port = htons(s->check_port);
3900
willy tarreau036e1ce2005-12-17 13:46:33 +01003901 /* allow specific binding */
3902 if (s->proxy->options & PR_O_BIND_SRC &&
3903 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
3904 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
3905 close(fd);
3906 s->result = -1;
3907 }
willy tarreaua41a8b42005-12-17 14:02:24 +01003908 else if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 /* OK, connection in progress or established */
3910
3911 //fprintf(stderr, "process_chk: 4\n");
3912
3913 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3914 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003915 fdtab[fd].read = &event_srv_chk_r;
3916 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003917 fdtab[fd].state = FD_STCONN; /* connection in progress */
3918 FD_SET(fd, StaticWriteEvent); /* for connect status */
3919 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003920 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3921 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 task_queue(t); /* restore t to its place in the task list */
3923 return tv_remain(&now, &t->expire);
3924 }
3925 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3926 s->result = -1; /* a real error */
3927 }
3928 }
3929 //fprintf(stderr, "process_chk: 5\n");
3930 close(fd);
3931 }
3932
3933 if (!s->result) { /* nothing done */
3934 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003935 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003936 task_queue(t); /* restore t to its place in the task list */
3937 return tv_remain(&now, &t->expire);
3938 }
3939
3940 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003941 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003942 s->health--; /* still good */
3943 else {
willy tarreaudd07e972005-12-18 00:48:48 +01003944 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01003945 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01003946 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003947 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01003948
willy tarreaudd07e972005-12-18 00:48:48 +01003949 if (find_server(s->proxy) == NULL) {
3950 Alert("Proxy %s has no server available !\n", s->proxy->id);
3951 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
3952 }
3953 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003954 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003955 }
3956
3957 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003958 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3959 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003960 }
3961 else {
3962 //fprintf(stderr, "process_chk: 8\n");
3963 /* there was a test running */
3964 if (s->result > 0) { /* good server detected */
3965 //fprintf(stderr, "process_chk: 9\n");
3966 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003967 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003968 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01003969 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003970 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003971 }
willy tarreauef900ab2005-12-17 12:52:52 +01003972
willy tarreaue47c8d72005-12-17 12:55:52 +01003973 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003974 s->state |= SRV_RUNNING;
3975 }
willy tarreauef900ab2005-12-17 12:52:52 +01003976 s->curfd = -1; /* no check running anymore */
3977 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003978 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003979 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003980 }
3981 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3982 //fprintf(stderr, "process_chk: 10\n");
3983 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003984 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003985 s->health--; /* still good */
3986 else {
willy tarreaudd07e972005-12-18 00:48:48 +01003987 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01003988
willy tarreaudd07e972005-12-18 00:48:48 +01003989 if (s->health == s->rise) {
3990 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003991 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01003992
3993 if (find_server(s->proxy) == NULL) {
3994 Alert("Proxy %s has no server available !\n", s->proxy->id);
3995 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
3996 }
willy tarreau535ae7a2005-12-17 12:58:00 +01003997 }
willy tarreauef900ab2005-12-17 12:52:52 +01003998
willy tarreau5cbea6f2005-12-17 12:48:26 +01003999 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004000 }
4001 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01004002 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004003 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004004 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004005 }
4006 /* if result is 0 and there's no timeout, we have to wait again */
4007 }
4008 //fprintf(stderr, "process_chk: 11\n");
4009 s->result = 0;
4010 task_queue(t); /* restore t to its place in the task list */
4011 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01004012}
4013
4014
willy tarreau5cbea6f2005-12-17 12:48:26 +01004015
willy tarreau0f7af912005-12-17 12:21:26 +01004016#if STATTIME > 0
4017int stats(void);
4018#endif
4019
4020/*
4021 * Main select() loop.
4022 */
4023
4024void select_loop() {
4025 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01004026 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01004027 int status;
4028 int fd,i;
4029 struct timeval delta;
4030 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004031 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01004032
willy tarreau5cbea6f2005-12-17 12:48:26 +01004033 tv_now(&now);
4034
4035 while (1) {
4036 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01004037
willy tarreau5cbea6f2005-12-17 12:48:26 +01004038 /* look for expired tasks and add them to the run queue.
4039 */
4040 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4041 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4042 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01004043 if (t->state & TASK_RUNNING)
4044 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004045
4046 /* wakeup expired entries. It doesn't matter if they are
4047 * already running because of a previous event
4048 */
4049 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01004050 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004051 task_wakeup(&rq, t);
4052 }
4053 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004054 /* first non-runnable task. Use its expiration date as an upper bound */
4055 int temp_time = tv_remain(&now, &t->expire);
4056 if (temp_time)
4057 next_time = temp_time;
4058 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004059 break;
4060 }
4061 }
4062
4063 /* process each task in the run queue now. Each task may be deleted
4064 * since we only use tnext.
4065 */
4066 tnext = rq;
4067 while ((t = tnext) != NULL) {
4068 int temp_time;
4069
4070 tnext = t->rqnext;
4071 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01004072 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004073 temp_time = t->process(t);
4074 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01004075 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004076 }
4077
willy tarreauef900ab2005-12-17 12:52:52 +01004078 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01004079
4080 /* maintain all proxies in a consistent state. This should quickly become a task */
4081 time2 = maintain_proxies();
4082 next_time = MINTIME(time2, next_time);
4083
4084 /* stop when there's no connection left and we don't allow them anymore */
4085 if (!actconn && listeners == 0)
4086 break;
4087
willy tarreau0f7af912005-12-17 12:21:26 +01004088
4089#if STATTIME > 0
4090 time2 = stats();
4091 // fprintf(stderr," stats = %d\n", time2);
4092 next_time = MINTIME(time2, next_time);
4093#endif
4094
willy tarreau5cbea6f2005-12-17 12:48:26 +01004095 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01004096 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004097 /* to avoid eventual select loops due to timer precision */
4098 next_time += SCHEDULER_RESOLUTION;
4099 delta.tv_sec = next_time / 1000;
4100 delta.tv_usec = (next_time % 1000) * 1000;
4101 }
4102 else if (next_time == 0) { /* allow select to return immediately when needed */
4103 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004104 }
4105
4106
4107 /* let's restore fdset state */
4108
4109 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004110 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004111 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
4112 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
4113 }
4114
4115// /* just a verification code, needs to be removed for performance */
4116// for (i=0; i<maxfd; i++) {
4117// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
4118// abort();
4119// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
4120// abort();
4121//
4122// }
4123
willy tarreau197e8ec2005-12-17 14:10:59 +01004124 status = select(maxfd,
4125 readnotnull ? ReadEvent : NULL,
4126 writenotnull ? WriteEvent : NULL,
4127 NULL,
4128 (next_time >= 0) ? &delta : NULL);
willy tarreau0f7af912005-12-17 12:21:26 +01004129
willy tarreau5cbea6f2005-12-17 12:48:26 +01004130 /* this is an experiment on the separation of the select work */
4131 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4132 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4133
willy tarreau0f7af912005-12-17 12:21:26 +01004134 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004135
willy tarreau0f7af912005-12-17 12:21:26 +01004136 if (status > 0) { /* must proceed with events */
4137
4138 int fds;
4139 char count;
4140
4141 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
4142 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
4143 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
4144
willy tarreau5cbea6f2005-12-17 12:48:26 +01004145 /* if we specify read first, the accepts and zero reads will be
4146 * seen first. Moreover, system buffers will be flushed faster.
4147 */
willy tarreau0f7af912005-12-17 12:21:26 +01004148 if (fdtab[fd].state == FD_STCLOSE)
4149 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01004150
4151 if (FD_ISSET(fd, ReadEvent))
4152 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004153
willy tarreau5cbea6f2005-12-17 12:48:26 +01004154 if (FD_ISSET(fd, WriteEvent))
4155 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004156 }
4157 }
4158 else {
4159 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
4160 }
willy tarreau0f7af912005-12-17 12:21:26 +01004161 }
4162}
4163
4164
4165#if STATTIME > 0
4166/*
4167 * Display proxy statistics regularly. It is designed to be called from the
4168 * select_loop().
4169 */
4170int stats(void) {
4171 static int lines;
4172 static struct timeval nextevt;
4173 static struct timeval lastevt;
4174 static struct timeval starttime = {0,0};
4175 unsigned long totaltime, deltatime;
4176 int ret;
4177
willy tarreau750a4722005-12-17 13:21:24 +01004178 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01004179 deltatime = (tv_diff(&lastevt, &now)?:1);
4180 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01004181
willy tarreau9fe663a2005-12-17 13:02:59 +01004182 if (global.mode & MODE_STATS) {
4183 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004184 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004185 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
4186 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004187 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004188 actconn, totalconn,
4189 stats_tsk_new, stats_tsk_good,
4190 stats_tsk_left, stats_tsk_right,
4191 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
4192 }
4193 }
4194
4195 tv_delayfrom(&nextevt, &now, STATTIME);
4196
4197 lastevt=now;
4198 }
4199 ret = tv_remain(&now, &nextevt);
4200 return ret;
4201}
4202#endif
4203
4204
4205/*
4206 * this function enables proxies when there are enough free sessions,
4207 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01004208 * select_loop(). It returns the time left before next expiration event
4209 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01004210 */
4211static int maintain_proxies(void) {
4212 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01004213 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004214 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01004215
4216 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004217 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01004218
4219 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01004220 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01004221 while (p) {
4222 if (p->nbconn < p->maxconn) {
4223 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004224 for (l = p->listen; l != NULL; l = l->next) {
4225 FD_SET(l->fd, StaticReadEvent);
4226 }
willy tarreau0f7af912005-12-17 12:21:26 +01004227 p->state = PR_STRUN;
4228 }
4229 }
4230 else {
4231 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004232 for (l = p->listen; l != NULL; l = l->next) {
4233 FD_CLR(l->fd, StaticReadEvent);
4234 }
willy tarreau0f7af912005-12-17 12:21:26 +01004235 p->state = PR_STIDLE;
4236 }
4237 }
4238 p = p->next;
4239 }
4240 }
4241 else { /* block all proxies */
4242 while (p) {
4243 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004244 for (l = p->listen; l != NULL; l = l->next) {
4245 FD_CLR(l->fd, StaticReadEvent);
4246 }
willy tarreau0f7af912005-12-17 12:21:26 +01004247 p->state = PR_STIDLE;
4248 }
4249 p = p->next;
4250 }
4251 }
4252
willy tarreau5cbea6f2005-12-17 12:48:26 +01004253 if (stopping) {
4254 p = proxy;
4255 while (p) {
4256 if (p->state != PR_STDISABLED) {
4257 int t;
4258 t = tv_remain(&now, &p->stop_time);
4259 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004260 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004261 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004262
willy tarreaua41a8b42005-12-17 14:02:24 +01004263 for (l = p->listen; l != NULL; l = l->next) {
4264 fd_delete(l->fd);
4265 listeners--;
4266 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004267 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004268 }
4269 else {
4270 tleft = MINTIME(t, tleft);
4271 }
4272 }
4273 p = p->next;
4274 }
4275 }
4276 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004277}
4278
4279/*
4280 * this function disables health-check servers so that the process will quickly be ignored
4281 * by load balancers.
4282 */
4283static void soft_stop(void) {
4284 struct proxy *p;
4285
4286 stopping = 1;
4287 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004288 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004289 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004290 if (p->state != PR_STDISABLED) {
4291 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004292 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004293 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004294 }
willy tarreau0f7af912005-12-17 12:21:26 +01004295 p = p->next;
4296 }
4297}
4298
4299/*
4300 * upon SIGUSR1, let's have a soft stop.
4301 */
4302void sig_soft_stop(int sig) {
4303 soft_stop();
4304 signal(sig, SIG_IGN);
4305}
4306
4307
willy tarreau8337c6b2005-12-17 13:41:01 +01004308/*
4309 * this function dumps every server's state when the process receives SIGHUP.
4310 */
4311void sig_dump_state(int sig) {
4312 struct proxy *p = proxy;
4313
4314 Warning("SIGHUP received, dumping servers states.\n");
4315 while (p) {
4316 struct server *s = p->srv;
4317
4318 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4319 while (s) {
4320 if (s->state & SRV_RUNNING) {
4321 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4322 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4323 }
4324 else {
4325 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4326 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4327 }
4328 s = s->next;
4329 }
willy tarreaudd07e972005-12-18 00:48:48 +01004330
4331 if (find_server(p) == NULL) {
4332 Warning("SIGHUP: proxy %s has no server available !\n", p);
4333 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
4334 }
4335
willy tarreau8337c6b2005-12-17 13:41:01 +01004336 p = p->next;
4337 }
4338 signal(sig, sig_dump_state);
4339}
4340
willy tarreau0f7af912005-12-17 12:21:26 +01004341void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004342 struct task *t, *tnext;
4343 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004344
willy tarreau5cbea6f2005-12-17 12:48:26 +01004345 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4346 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4347 tnext = t->next;
4348 s = t->context;
4349 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4350 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4351 "req=%d, rep=%d, clifd=%d\n",
4352 s, tv_remain(&now, &t->expire),
4353 s->cli_state,
4354 s->srv_state,
4355 FD_ISSET(s->cli_fd, StaticReadEvent),
4356 FD_ISSET(s->cli_fd, StaticWriteEvent),
4357 FD_ISSET(s->srv_fd, StaticReadEvent),
4358 FD_ISSET(s->srv_fd, StaticWriteEvent),
4359 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4360 );
willy tarreau0f7af912005-12-17 12:21:26 +01004361 }
4362}
4363
willy tarreaue39cd132005-12-17 13:00:18 +01004364void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4365 struct hdr_exp *exp;
4366
4367 while (*head != NULL)
4368 head = &(*head)->next;
4369
4370 exp = calloc(1, sizeof(struct hdr_exp));
4371
4372 exp->preg = preg;
4373 exp->replace = replace;
4374 exp->action = action;
4375 *head = exp;
4376}
4377
willy tarreau9fe663a2005-12-17 13:02:59 +01004378
willy tarreau0f7af912005-12-17 12:21:26 +01004379/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004380 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004381 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004382int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004383
willy tarreau9fe663a2005-12-17 13:02:59 +01004384 if (!strcmp(args[0], "global")) { /* new section */
4385 /* no option, nothing special to do */
4386 return 0;
4387 }
4388 else if (!strcmp(args[0], "daemon")) {
4389 global.mode |= MODE_DAEMON;
4390 }
4391 else if (!strcmp(args[0], "debug")) {
4392 global.mode |= MODE_DEBUG;
4393 }
4394 else if (!strcmp(args[0], "quiet")) {
4395 global.mode |= MODE_QUIET;
4396 }
4397 else if (!strcmp(args[0], "stats")) {
4398 global.mode |= MODE_STATS;
4399 }
4400 else if (!strcmp(args[0], "uid")) {
4401 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004402 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004403 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004404 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004405 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004406 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004407 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004408 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004409 global.uid = atol(args[1]);
4410 }
4411 else if (!strcmp(args[0], "gid")) {
4412 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004413 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004414 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004415 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004416 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004417 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004418 return -1;
4419 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004420 global.gid = atol(args[1]);
4421 }
4422 else if (!strcmp(args[0], "nbproc")) {
4423 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004424 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004425 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004426 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004427 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004428 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004429 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004430 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004431 global.nbproc = atol(args[1]);
4432 }
4433 else if (!strcmp(args[0], "maxconn")) {
4434 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004435 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004436 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004437 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004438 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004439 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004440 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004441 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004442 global.maxconn = atol(args[1]);
4443 }
4444 else if (!strcmp(args[0], "chroot")) {
4445 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004446 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004447 return 0;
4448 }
4449 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004450 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004451 return -1;
4452 }
4453 global.chroot = strdup(args[1]);
4454 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01004455 else if (!strcmp(args[0], "pidfile")) {
4456 if (global.pidfile != NULL) {
4457 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
4458 return 0;
4459 }
4460 if (*(args[1]) == 0) {
4461 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
4462 return -1;
4463 }
4464 global.pidfile = strdup(args[1]);
4465 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004466 else if (!strcmp(args[0], "log")) { /* syslog server address */
4467 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004468 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004469
4470 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004471 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004472 return -1;
4473 }
4474
4475 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4476 if (!strcmp(log_facilities[facility], args[2]))
4477 break;
4478
4479 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004480 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004481 exit(1);
4482 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004483
4484 level = 7; /* max syslog level = debug */
4485 if (*(args[3])) {
4486 while (level >= 0 && strcmp(log_levels[level], args[3]))
4487 level--;
4488 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004489 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004490 exit(1);
4491 }
4492 }
4493
willy tarreau9fe663a2005-12-17 13:02:59 +01004494 sa = str2sa(args[1]);
4495 if (!sa->sin_port)
4496 sa->sin_port = htons(SYSLOG_PORT);
4497
4498 if (global.logfac1 == -1) {
4499 global.logsrv1 = *sa;
4500 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004501 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004502 }
4503 else if (global.logfac2 == -1) {
4504 global.logsrv2 = *sa;
4505 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004506 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004507 }
4508 else {
4509 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4510 return -1;
4511 }
4512
4513 }
4514 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004515 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004516 return -1;
4517 }
4518 return 0;
4519}
4520
4521
willy tarreaua41a8b42005-12-17 14:02:24 +01004522void init_default_instance() {
4523 memset(&defproxy, 0, sizeof(defproxy));
4524 defproxy.mode = PR_MODE_TCP;
4525 defproxy.state = PR_STNEW;
4526 defproxy.maxconn = cfg_maxpconn;
4527 defproxy.conn_retries = CONN_RETRIES;
4528 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
4529}
4530
willy tarreau9fe663a2005-12-17 13:02:59 +01004531/*
4532 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4533 */
4534int cfg_parse_listen(char *file, int linenum, char **args) {
4535 static struct proxy *curproxy = NULL;
4536 struct server *newsrv = NULL;
4537
4538 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01004539 if (!*args[1]) {
4540 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
4541 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004542 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004543 return -1;
4544 }
4545
4546 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004547 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004548 return -1;
4549 }
4550 curproxy->next = proxy;
4551 proxy = curproxy;
4552 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01004553 if (strchr(args[2], ':') != NULL)
4554 curproxy->listen = str2listener(args[2], curproxy->listen);
4555
willy tarreau9fe663a2005-12-17 13:02:59 +01004556 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01004557 curproxy->state = defproxy.state;
4558 curproxy->maxconn = defproxy.maxconn;
4559 curproxy->conn_retries = defproxy.conn_retries;
4560 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004561
4562 if (defproxy.check_req)
4563 curproxy->check_req = strdup(defproxy.check_req);
4564 curproxy->check_len = defproxy.check_len;
4565
4566 if (defproxy.cookie_name)
4567 curproxy->cookie_name = strdup(defproxy.cookie_name);
4568 curproxy->cookie_len = defproxy.cookie_len;
4569
4570 if (defproxy.capture_name)
4571 curproxy->capture_name = strdup(defproxy.capture_name);
4572 curproxy->capture_namelen = defproxy.capture_namelen;
4573 curproxy->capture_len = defproxy.capture_len;
4574
4575 if (defproxy.errmsg.msg400)
4576 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
4577 curproxy->errmsg.len400 = defproxy.errmsg.len400;
4578
4579 if (defproxy.errmsg.msg403)
4580 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
4581 curproxy->errmsg.len403 = defproxy.errmsg.len403;
4582
4583 if (defproxy.errmsg.msg408)
4584 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
4585 curproxy->errmsg.len408 = defproxy.errmsg.len408;
4586
4587 if (defproxy.errmsg.msg500)
4588 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
4589 curproxy->errmsg.len500 = defproxy.errmsg.len500;
4590
4591 if (defproxy.errmsg.msg502)
4592 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
4593 curproxy->errmsg.len502 = defproxy.errmsg.len502;
4594
4595 if (defproxy.errmsg.msg503)
4596 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
4597 curproxy->errmsg.len503 = defproxy.errmsg.len503;
4598
4599 if (defproxy.errmsg.msg504)
4600 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
4601 curproxy->errmsg.len504 = defproxy.errmsg.len504;
4602
willy tarreaua41a8b42005-12-17 14:02:24 +01004603 curproxy->clitimeout = defproxy.clitimeout;
4604 curproxy->contimeout = defproxy.contimeout;
4605 curproxy->srvtimeout = defproxy.srvtimeout;
4606 curproxy->mode = defproxy.mode;
4607 curproxy->logfac1 = defproxy.logfac1;
4608 curproxy->logsrv1 = defproxy.logsrv1;
4609 curproxy->loglev1 = defproxy.loglev1;
4610 curproxy->logfac2 = defproxy.logfac2;
4611 curproxy->logsrv2 = defproxy.logsrv2;
4612 curproxy->loglev2 = defproxy.loglev2;
4613 curproxy->to_log = defproxy.to_log;
4614 curproxy->grace = defproxy.grace;
4615 curproxy->source_addr = defproxy.source_addr;
4616 return 0;
4617 }
4618 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004619 /* some variables may have already been initialized earlier */
4620 if (defproxy.check_req) free(defproxy.check_req);
4621 if (defproxy.cookie_name) free(defproxy.cookie_name);
4622 if (defproxy.capture_name) free(defproxy.capture_name);
4623 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
4624 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
4625 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
4626 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
4627 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
4628 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
4629 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
4630
4631 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01004632 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01004633 return 0;
4634 }
4635 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004636 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004637 return -1;
4638 }
4639
willy tarreaua41a8b42005-12-17 14:02:24 +01004640 if (!strcmp(args[0], "bind")) { /* new listen addresses */
4641 if (curproxy == &defproxy) {
4642 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4643 return -1;
4644 }
4645
4646 if (strchr(args[1], ':') == NULL) {
4647 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
4648 file, linenum, args[0]);
4649 return -1;
4650 }
4651 curproxy->listen = str2listener(args[1], curproxy->listen);
4652 return 0;
4653 }
4654 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01004655 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
4656 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
4657 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
4658 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004659 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004660 return -1;
4661 }
4662 }
4663 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
4664 curproxy->state = PR_STDISABLED;
4665 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004666 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
4667 curproxy->state = PR_STNEW;
4668 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004669 else if (!strcmp(args[0], "cookie")) { /* cookie name */
4670 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004671// if (curproxy == &defproxy) {
4672// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4673// return -1;
4674// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004675
willy tarreau9fe663a2005-12-17 13:02:59 +01004676 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004677// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
4678// file, linenum);
4679// return 0;
4680 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004681 }
4682
4683 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004684 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
4685 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004686 return -1;
4687 }
4688 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004689 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004690
4691 cur_arg = 2;
4692 while (*(args[cur_arg])) {
4693 if (!strcmp(args[cur_arg], "rewrite")) {
4694 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01004695 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004696 else if (!strcmp(args[cur_arg], "indirect")) {
4697 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01004698 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004699 else if (!strcmp(args[cur_arg], "insert")) {
4700 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01004701 }
willy tarreau240afa62005-12-17 13:14:35 +01004702 else if (!strcmp(args[cur_arg], "nocache")) {
4703 curproxy->options |= PR_O_COOK_NOC;
4704 }
willy tarreaucd878942005-12-17 13:27:43 +01004705 else if (!strcmp(args[cur_arg], "postonly")) {
4706 curproxy->options |= PR_O_COOK_POST;
4707 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004708 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004709 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
4710 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004711 return -1;
4712 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004713 cur_arg++;
4714 }
4715 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004716 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004717 file, linenum);
4718 return -1;
4719 }
4720 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004721 else if (!strcmp(args[0], "capture")) { /* name of a cookie to capture */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004722// if (curproxy == &defproxy) {
4723// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4724// return -1;
4725// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004726
willy tarreau8337c6b2005-12-17 13:41:01 +01004727 if (curproxy->capture_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004728// Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4729// file, linenum, args[0]);
4730// return 0;
4731 free(curproxy->capture_name);
willy tarreau8337c6b2005-12-17 13:41:01 +01004732 }
4733
4734 if (*(args[4]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004735 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
4736 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004737 return -1;
4738 }
4739 curproxy->capture_name = strdup(args[2]);
4740 curproxy->capture_namelen = strlen(curproxy->capture_name);
4741 curproxy->capture_len = atol(args[4]);
4742 if (curproxy->capture_len >= CAPTURE_LEN) {
4743 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
4744 file, linenum, CAPTURE_LEN - 1);
4745 curproxy->capture_len = CAPTURE_LEN - 1;
4746 }
4747 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004748 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004749 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004750 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004751 return 0;
4752 }
4753 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004754 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4755 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004756 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004757 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004758 curproxy->contimeout = atol(args[1]);
4759 }
4760 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004761 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004762 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4763 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004764 return 0;
4765 }
4766 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004767 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4768 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004769 return -1;
4770 }
4771 curproxy->clitimeout = atol(args[1]);
4772 }
4773 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004774 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004775 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004776 return 0;
4777 }
4778 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004779 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4780 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004781 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004782 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004783 curproxy->srvtimeout = atol(args[1]);
4784 }
4785 else if (!strcmp(args[0], "retries")) { /* connection retries */
4786 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004787 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
4788 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004789 return -1;
4790 }
4791 curproxy->conn_retries = atol(args[1]);
4792 }
4793 else if (!strcmp(args[0], "option")) {
4794 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004795 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004796 return -1;
4797 }
4798 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004799 /* enable reconnections to dispatch */
4800 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004801#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004802 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004803 /* enable transparent proxy connections */
4804 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004805#endif
4806 else if (!strcmp(args[1], "keepalive"))
4807 /* enable keep-alive */
4808 curproxy->options |= PR_O_KEEPALIVE;
4809 else if (!strcmp(args[1], "forwardfor"))
4810 /* insert x-forwarded-for field */
4811 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01004812 else if (!strcmp(args[1], "logasap"))
4813 /* log as soon as possible, without waiting for the session to complete */
4814 curproxy->options |= PR_O_LOGASAP;
4815 else if (!strcmp(args[1], "httpclose"))
4816 /* force connection: close in both directions in HTTP mode */
4817 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreauc1cae632005-12-17 14:12:23 +01004818 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01004819 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01004820 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01004821 else if (!strcmp(args[1], "tcplog"))
4822 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01004823 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01004824 else if (!strcmp(args[1], "dontlognull")) {
4825 /* don't log empty requests */
4826 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004827 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004828 else if (!strcmp(args[1], "httpchk")) {
4829 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004830 if (curproxy->check_req != NULL) {
4831 free(curproxy->check_req);
4832 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004833 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004834 if (!*args[2]) { /* no argument */
4835 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
4836 curproxy->check_len = strlen(DEF_CHECK_REQ);
4837 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01004838 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
4839 curproxy->check_req = (char *)malloc(reqlen);
4840 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4841 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004842 } else { /* more arguments : METHOD URI [HTTP_VER] */
4843 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
4844 if (*args[4])
4845 reqlen += strlen(args[4]);
4846 else
4847 reqlen += strlen("HTTP/1.0");
4848
4849 curproxy->check_req = (char *)malloc(reqlen);
4850 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4851 "%s %s %s\r\n\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
willy tarreau2f6ba652005-12-17 13:57:42 +01004852 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004853 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004854 else if (!strcmp(args[1], "persist")) {
4855 /* persist on using the server specified by the cookie, even when it's down */
4856 curproxy->options |= PR_O_PERSIST;
4857 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004858 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004859 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004860 return -1;
4861 }
4862 return 0;
4863 }
4864 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4865 /* enable reconnections to dispatch */
4866 curproxy->options |= PR_O_REDISP;
4867 }
willy tarreaua1598082005-12-17 13:08:06 +01004868#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004869 else if (!strcmp(args[0], "transparent")) {
4870 /* enable transparent proxy connections */
4871 curproxy->options |= PR_O_TRANSP;
4872 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004873#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004874 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4875 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004876 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004877 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004878 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004879 curproxy->maxconn = atol(args[1]);
4880 }
4881 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4882 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004883 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004884 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004885 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004886 curproxy->grace = atol(args[1]);
4887 }
4888 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01004889 if (curproxy == &defproxy) {
4890 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4891 return -1;
4892 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004893 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004894 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004895 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004896 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004897 curproxy->dispatch_addr = *str2sa(args[1]);
4898 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004899 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01004900 if (*(args[1])) {
4901 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004902 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004903 }
4904 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004905 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004906 return -1;
4907 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004908 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004909 else /* if no option is set, use round-robin by default */
4910 curproxy->options |= PR_O_BALANCE_RR;
4911 }
4912 else if (!strcmp(args[0], "server")) { /* server address */
4913 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004914 char *rport;
4915 char *raddr;
4916 short realport;
4917 int do_check;
4918
4919 if (curproxy == &defproxy) {
4920 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4921 return -1;
4922 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004923
willy tarreaua41a8b42005-12-17 14:02:24 +01004924 if (!*args[2]) {
4925 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004926 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004927 return -1;
4928 }
4929 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4930 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4931 return -1;
4932 }
4933 newsrv->next = curproxy->srv;
4934 curproxy->srv = newsrv;
4935 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01004936
4937 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004938 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01004939 newsrv->id = strdup(args[1]);
4940
4941 /* several ways to check the port component :
4942 * - IP => port=+0, relative
4943 * - IP: => port=+0, relative
4944 * - IP:N => port=N, absolute
4945 * - IP:+N => port=+N, relative
4946 * - IP:-N => port=-N, relative
4947 */
4948 raddr = strdup(args[2]);
4949 rport = strchr(raddr, ':');
4950 if (rport) {
4951 *rport++ = 0;
4952 realport = atol(rport);
4953 if (!isdigit((int)*rport))
4954 newsrv->state |= SRV_MAPPORTS;
4955 } else {
4956 realport = 0;
4957 newsrv->state |= SRV_MAPPORTS;
4958 }
4959
4960 newsrv->addr = *str2sa(raddr);
4961 newsrv->addr.sin_port = htons(realport);
4962 free(raddr);
4963
willy tarreau9fe663a2005-12-17 13:02:59 +01004964 newsrv->curfd = -1; /* no health-check in progress */
4965 newsrv->inter = DEF_CHKINTR;
4966 newsrv->rise = DEF_RISETIME;
4967 newsrv->fall = DEF_FALLTIME;
4968 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4969 cur_arg = 3;
4970 while (*args[cur_arg]) {
4971 if (!strcmp(args[cur_arg], "cookie")) {
4972 newsrv->cookie = strdup(args[cur_arg + 1]);
4973 newsrv->cklen = strlen(args[cur_arg + 1]);
4974 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004975 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004976 else if (!strcmp(args[cur_arg], "rise")) {
4977 newsrv->rise = atol(args[cur_arg + 1]);
4978 newsrv->health = newsrv->rise;
4979 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004980 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004981 else if (!strcmp(args[cur_arg], "fall")) {
4982 newsrv->fall = atol(args[cur_arg + 1]);
4983 cur_arg += 2;
4984 }
4985 else if (!strcmp(args[cur_arg], "inter")) {
4986 newsrv->inter = atol(args[cur_arg + 1]);
4987 cur_arg += 2;
4988 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004989 else if (!strcmp(args[cur_arg], "port")) {
4990 newsrv->check_port = atol(args[cur_arg + 1]);
4991 cur_arg += 2;
4992 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004993 else if (!strcmp(args[cur_arg], "backup")) {
4994 newsrv->state |= SRV_BACKUP;
4995 cur_arg ++;
4996 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004997 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004998 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004999 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005000 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005001 else {
willy tarreaua41a8b42005-12-17 14:02:24 +01005002 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
5003 file, linenum, newsrv->id);
5004 return -1;
5005 }
5006 }
5007
5008 if (do_check) {
5009 struct task *t;
5010
5011 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
5012 newsrv->check_port = realport; /* by default */
5013 if (!newsrv->check_port) {
5014 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005015 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005016 return -1;
5017 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005018
5019 if ((t = pool_alloc(task)) == NULL) {
5020 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
5021 return -1;
5022 }
5023
5024 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
5025 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
5026 t->state = TASK_IDLE;
5027 t->process = process_chk;
5028 t->context = newsrv;
5029
5030 if (curproxy->state != PR_STDISABLED) {
5031 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
5032 task_queue(t);
5033 task_wakeup(&rq, t);
5034 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005035 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005036
willy tarreau9fe663a2005-12-17 13:02:59 +01005037 curproxy->nbservers++;
5038 }
5039 else if (!strcmp(args[0], "log")) { /* syslog server address */
5040 struct sockaddr_in *sa;
5041 int facility;
5042
5043 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
5044 curproxy->logfac1 = global.logfac1;
5045 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005046 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005047 curproxy->logfac2 = global.logfac2;
5048 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01005049 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01005050 }
5051 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01005052 int level;
5053
willy tarreau0f7af912005-12-17 12:21:26 +01005054 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5055 if (!strcmp(log_facilities[facility], args[2]))
5056 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01005057
willy tarreau0f7af912005-12-17 12:21:26 +01005058 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005059 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01005060 exit(1);
5061 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005062
willy tarreau8337c6b2005-12-17 13:41:01 +01005063 level = 7; /* max syslog level = debug */
5064 if (*(args[3])) {
5065 while (level >= 0 && strcmp(log_levels[level], args[3]))
5066 level--;
5067 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005068 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005069 exit(1);
5070 }
5071 }
5072
willy tarreau0f7af912005-12-17 12:21:26 +01005073 sa = str2sa(args[1]);
5074 if (!sa->sin_port)
5075 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01005076
willy tarreau0f7af912005-12-17 12:21:26 +01005077 if (curproxy->logfac1 == -1) {
5078 curproxy->logsrv1 = *sa;
5079 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005080 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005081 }
5082 else if (curproxy->logfac2 == -1) {
5083 curproxy->logsrv2 = *sa;
5084 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005085 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005086 }
5087 else {
5088 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005089 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005090 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005091 }
5092 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005093 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005094 file, linenum);
5095 return -1;
5096 }
5097 }
willy tarreaua1598082005-12-17 13:08:06 +01005098 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01005099 if (!*args[1]) {
5100 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005101 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01005102 return -1;
5103 }
5104
5105 curproxy->source_addr = *str2sa(args[1]);
5106 curproxy->options |= PR_O_BIND_SRC;
5107 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005108 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
5109 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005110 if (curproxy == &defproxy) {
5111 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5112 return -1;
5113 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005114
5115 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005116 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5117 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005118 return -1;
5119 }
5120
5121 preg = calloc(1, sizeof(regex_t));
5122 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005123 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005124 return -1;
5125 }
5126
5127 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5128 }
5129 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
5130 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005131 if (curproxy == &defproxy) {
5132 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5133 return -1;
5134 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005135
5136 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005137 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005138 return -1;
5139 }
5140
5141 preg = calloc(1, sizeof(regex_t));
5142 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005143 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005144 return -1;
5145 }
5146
5147 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5148 }
5149 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
5150 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005151 if (curproxy == &defproxy) {
5152 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5153 return -1;
5154 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005155
5156 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005157 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005158 return -1;
5159 }
5160
5161 preg = calloc(1, sizeof(regex_t));
5162 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005163 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005164 return -1;
5165 }
5166
5167 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5168 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005169 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
5170 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005171 if (curproxy == &defproxy) {
5172 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5173 return -1;
5174 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005175
5176 if (*(args[1]) == 0) {
5177 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5178 return -1;
5179 }
5180
5181 preg = calloc(1, sizeof(regex_t));
5182 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5183 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5184 return -1;
5185 }
5186
5187 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5188 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005189 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
5190 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005191 if (curproxy == &defproxy) {
5192 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5193 return -1;
5194 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005195
5196 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005197 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005198 return -1;
5199 }
5200
5201 preg = calloc(1, sizeof(regex_t));
5202 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005203 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005204 return -1;
5205 }
5206
5207 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5208 }
5209 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
5210 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005211 if (curproxy == &defproxy) {
5212 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5213 return -1;
5214 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005215
5216 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005217 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5218 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005219 return -1;
5220 }
5221
5222 preg = calloc(1, sizeof(regex_t));
5223 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005224 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005225 return -1;
5226 }
5227
5228 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5229 }
5230 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
5231 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005232 if (curproxy == &defproxy) {
5233 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5234 return -1;
5235 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005236
5237 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005238 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005239 return -1;
5240 }
5241
5242 preg = calloc(1, sizeof(regex_t));
5243 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005244 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005245 return -1;
5246 }
5247
5248 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5249 }
5250 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
5251 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005252 if (curproxy == &defproxy) {
5253 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5254 return -1;
5255 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005256
5257 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005258 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005259 return -1;
5260 }
5261
5262 preg = calloc(1, sizeof(regex_t));
5263 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005264 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005265 return -1;
5266 }
5267
5268 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5269 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005270 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
5271 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005272 if (curproxy == &defproxy) {
5273 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5274 return -1;
5275 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005276
5277 if (*(args[1]) == 0) {
5278 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5279 return -1;
5280 }
5281
5282 preg = calloc(1, sizeof(regex_t));
5283 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5284 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5285 return -1;
5286 }
5287
5288 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5289 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005290 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
5291 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005292 if (curproxy == &defproxy) {
5293 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5294 return -1;
5295 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005296
5297 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005298 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005299 return -1;
5300 }
5301
5302 preg = calloc(1, sizeof(regex_t));
5303 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005304 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005305 return -1;
5306 }
5307
5308 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5309 }
5310 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005311 if (curproxy == &defproxy) {
5312 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5313 return -1;
5314 }
5315
willy tarreau9fe663a2005-12-17 13:02:59 +01005316 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005317 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005318 return 0;
5319 }
5320
5321 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005322 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005323 return -1;
5324 }
5325
5326 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005327 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005328 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01005329 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01005330
5331 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005332 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5333 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005334 return -1;
5335 }
5336
5337 preg = calloc(1, sizeof(regex_t));
5338 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005339 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005340 return -1;
5341 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005342
5343 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5344 }
5345 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
5346 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005347 if (curproxy == &defproxy) {
5348 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5349 return -1;
5350 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005351
5352 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005353 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005354 return -1;
5355 }
willy tarreaue39cd132005-12-17 13:00:18 +01005356
willy tarreau9fe663a2005-12-17 13:02:59 +01005357 preg = calloc(1, sizeof(regex_t));
5358 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005359 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005360 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005361 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005362
5363 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5364 }
5365 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01005366 regex_t *preg;
5367 if (curproxy == &defproxy) {
5368 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5369 return -1;
5370 }
willy tarreaue39cd132005-12-17 13:00:18 +01005371
willy tarreaua41a8b42005-12-17 14:02:24 +01005372 if (*(args[1]) == 0 || *(args[2]) == 0) {
5373 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5374 file, linenum, args[0]);
5375 return -1;
5376 }
willy tarreaue39cd132005-12-17 13:00:18 +01005377
willy tarreaua41a8b42005-12-17 14:02:24 +01005378 preg = calloc(1, sizeof(regex_t));
5379 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5380 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5381 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005382 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005383
5384 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5385 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005386 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
5387 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005388 if (curproxy == &defproxy) {
5389 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5390 return -1;
5391 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005392
5393 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005394 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005395 return -1;
5396 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005397
willy tarreau9fe663a2005-12-17 13:02:59 +01005398 preg = calloc(1, sizeof(regex_t));
5399 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005400 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005401 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005402 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005403
5404 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5405 }
5406 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005407 if (curproxy == &defproxy) {
5408 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5409 return -1;
5410 }
5411
willy tarreau9fe663a2005-12-17 13:02:59 +01005412 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005413 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005414 return 0;
5415 }
5416
5417 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005418 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005419 return -1;
5420 }
5421
5422 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
5423 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005424 else if (!strcmp(args[0], "errorloc")) { /* error location */
5425 int errnum;
5426 char *err;
5427
willy tarreaueedaa9f2005-12-17 14:08:03 +01005428 // if (curproxy == &defproxy) {
5429 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5430 // return -1;
5431 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005432
willy tarreau8337c6b2005-12-17 13:41:01 +01005433 if (*(args[2]) == 0) {
5434 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
5435 return -1;
5436 }
5437
5438 errnum = atol(args[1]);
5439 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
5440 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
5441
5442 if (errnum == 400) {
5443 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005444 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005445 free(curproxy->errmsg.msg400);
5446 }
5447 curproxy->errmsg.msg400 = err;
5448 curproxy->errmsg.len400 = strlen(err);
5449 }
5450 else if (errnum == 403) {
5451 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005452 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005453 free(curproxy->errmsg.msg403);
5454 }
5455 curproxy->errmsg.msg403 = err;
5456 curproxy->errmsg.len403 = strlen(err);
5457 }
5458 else if (errnum == 408) {
5459 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005460 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005461 free(curproxy->errmsg.msg408);
5462 }
5463 curproxy->errmsg.msg408 = err;
5464 curproxy->errmsg.len408 = strlen(err);
5465 }
5466 else if (errnum == 500) {
5467 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005468 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005469 free(curproxy->errmsg.msg500);
5470 }
5471 curproxy->errmsg.msg500 = err;
5472 curproxy->errmsg.len500 = strlen(err);
5473 }
5474 else if (errnum == 502) {
5475 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005476 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005477 free(curproxy->errmsg.msg502);
5478 }
5479 curproxy->errmsg.msg502 = err;
5480 curproxy->errmsg.len502 = strlen(err);
5481 }
5482 else if (errnum == 503) {
5483 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005484 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005485 free(curproxy->errmsg.msg503);
5486 }
5487 curproxy->errmsg.msg503 = err;
5488 curproxy->errmsg.len503 = strlen(err);
5489 }
5490 else if (errnum == 504) {
5491 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005492 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005493 free(curproxy->errmsg.msg504);
5494 }
5495 curproxy->errmsg.msg504 = err;
5496 curproxy->errmsg.len504 = strlen(err);
5497 }
5498 else {
5499 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
5500 free(err);
5501 }
5502 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005503 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005504 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01005505 return -1;
5506 }
5507 return 0;
5508}
willy tarreaue39cd132005-12-17 13:00:18 +01005509
willy tarreau5cbea6f2005-12-17 12:48:26 +01005510
willy tarreau9fe663a2005-12-17 13:02:59 +01005511/*
5512 * This function reads and parses the configuration file given in the argument.
5513 * returns 0 if OK, -1 if error.
5514 */
5515int readcfgfile(char *file) {
5516 char thisline[256];
5517 char *line;
5518 FILE *f;
5519 int linenum = 0;
5520 char *end;
5521 char *args[MAX_LINE_ARGS];
5522 int arg;
5523 int cfgerr = 0;
5524 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01005525
willy tarreau9fe663a2005-12-17 13:02:59 +01005526 struct proxy *curproxy = NULL;
5527 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005528
willy tarreau9fe663a2005-12-17 13:02:59 +01005529 if ((f=fopen(file,"r")) == NULL)
5530 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005531
willy tarreaueedaa9f2005-12-17 14:08:03 +01005532 init_default_instance();
5533
willy tarreau9fe663a2005-12-17 13:02:59 +01005534 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
5535 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005536
willy tarreau9fe663a2005-12-17 13:02:59 +01005537 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005538
willy tarreau9fe663a2005-12-17 13:02:59 +01005539 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01005540 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01005541 line++;
5542
5543 arg = 0;
5544 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01005545
willy tarreau9fe663a2005-12-17 13:02:59 +01005546 while (*line && arg < MAX_LINE_ARGS) {
5547 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
5548 * C equivalent value. Other combinations left unchanged (eg: \1).
5549 */
5550 if (*line == '\\') {
5551 int skip = 0;
5552 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
5553 *line = line[1];
5554 skip = 1;
5555 }
5556 else if (line[1] == 'r') {
5557 *line = '\r';
5558 skip = 1;
5559 }
5560 else if (line[1] == 'n') {
5561 *line = '\n';
5562 skip = 1;
5563 }
5564 else if (line[1] == 't') {
5565 *line = '\t';
5566 skip = 1;
5567 }
5568 else if (line[1] == 'x' && (line + 3 < end )) {
5569 unsigned char hex1, hex2;
5570 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
5571 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
5572 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
5573 *line = (hex1<<4) + hex2;
5574 skip = 3;
5575 }
5576 if (skip) {
5577 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
5578 end -= skip;
5579 }
5580 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005581 }
willy tarreaua1598082005-12-17 13:08:06 +01005582 else if (*line == '#' || *line == '\n' || *line == '\r') {
5583 /* end of string, end of loop */
5584 *line = 0;
5585 break;
5586 }
willy tarreauc29948c2005-12-17 13:10:27 +01005587 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005588 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01005589 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01005590 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01005591 line++;
5592 args[++arg] = line;
5593 }
5594 else {
5595 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005596 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005597 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005598
willy tarreau9fe663a2005-12-17 13:02:59 +01005599 /* empty line */
5600 if (!**args)
5601 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01005602
willy tarreau9fe663a2005-12-17 13:02:59 +01005603 /* zero out remaining args */
5604 while (++arg < MAX_LINE_ARGS) {
5605 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005606 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005607
willy tarreaua41a8b42005-12-17 14:02:24 +01005608 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01005609 confsect = CFG_LISTEN;
5610 else if (!strcmp(args[0], "global")) /* global config */
5611 confsect = CFG_GLOBAL;
5612 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005613
willy tarreau9fe663a2005-12-17 13:02:59 +01005614 switch (confsect) {
5615 case CFG_LISTEN:
5616 if (cfg_parse_listen(file, linenum, args) < 0)
5617 return -1;
5618 break;
5619 case CFG_GLOBAL:
5620 if (cfg_parse_global(file, linenum, args) < 0)
5621 return -1;
5622 break;
5623 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01005624 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005625 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005626 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005627
5628
willy tarreau0f7af912005-12-17 12:21:26 +01005629 }
5630 fclose(f);
5631
5632 /*
5633 * Now, check for the integrity of all that we have collected.
5634 */
5635
5636 if ((curproxy = proxy) == NULL) {
5637 Alert("parsing %s : no <listen> line. Nothing to do !\n",
5638 file);
5639 return -1;
5640 }
5641
5642 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01005643 if (curproxy->state == PR_STDISABLED) {
5644 curproxy = curproxy->next;
5645 continue;
5646 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005647 if ((curproxy->mode != PR_MODE_HEALTH) &&
5648 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01005649 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005650 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
5651 file, curproxy->id);
5652 cfgerr++;
5653 }
5654 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
5655 if (curproxy->options & PR_O_TRANSP) {
5656 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
5657 file, curproxy->id);
5658 cfgerr++;
5659 }
5660 else if (curproxy->srv == NULL) {
5661 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
5662 file, curproxy->id);
5663 cfgerr++;
5664 }
willy tarreaua1598082005-12-17 13:08:06 +01005665 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005666 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
5667 file, curproxy->id);
5668 }
5669 }
5670 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01005671 if (curproxy->cookie_name != NULL) {
5672 Warning("parsing %s : cookie will be ignored for listener %s.\n",
5673 file, curproxy->id);
5674 }
5675 if ((newsrv = curproxy->srv) != NULL) {
5676 Warning("parsing %s : servers will be ignored for listener %s.\n",
5677 file, curproxy->id);
5678 }
willy tarreaue39cd132005-12-17 13:00:18 +01005679 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005680 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
5681 file, curproxy->id);
5682 }
willy tarreaue39cd132005-12-17 13:00:18 +01005683 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005684 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
5685 file, curproxy->id);
5686 }
5687 }
5688 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
5689 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
5690 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
5691 file, curproxy->id);
5692 cfgerr++;
5693 }
5694 else {
5695 while (newsrv != NULL) {
5696 /* nothing to check for now */
5697 newsrv = newsrv->next;
5698 }
5699 }
5700 }
willy tarreau25c4ea52005-12-18 00:49:49 +01005701
5702 if (curproxy->options & PR_O_LOGASAP)
5703 curproxy->to_log &= ~LW_BYTES;
5704
willy tarreau8337c6b2005-12-17 13:41:01 +01005705 if (curproxy->errmsg.msg400 == NULL) {
5706 curproxy->errmsg.msg400 = (char *)HTTP_400;
5707 curproxy->errmsg.len400 = strlen(HTTP_400);
5708 }
5709 if (curproxy->errmsg.msg403 == NULL) {
5710 curproxy->errmsg.msg403 = (char *)HTTP_403;
5711 curproxy->errmsg.len403 = strlen(HTTP_403);
5712 }
5713 if (curproxy->errmsg.msg408 == NULL) {
5714 curproxy->errmsg.msg408 = (char *)HTTP_408;
5715 curproxy->errmsg.len408 = strlen(HTTP_408);
5716 }
5717 if (curproxy->errmsg.msg500 == NULL) {
5718 curproxy->errmsg.msg500 = (char *)HTTP_500;
5719 curproxy->errmsg.len500 = strlen(HTTP_500);
5720 }
5721 if (curproxy->errmsg.msg502 == NULL) {
5722 curproxy->errmsg.msg502 = (char *)HTTP_502;
5723 curproxy->errmsg.len502 = strlen(HTTP_502);
5724 }
5725 if (curproxy->errmsg.msg503 == NULL) {
5726 curproxy->errmsg.msg503 = (char *)HTTP_503;
5727 curproxy->errmsg.len503 = strlen(HTTP_503);
5728 }
5729 if (curproxy->errmsg.msg504 == NULL) {
5730 curproxy->errmsg.msg504 = (char *)HTTP_504;
5731 curproxy->errmsg.len504 = strlen(HTTP_504);
5732 }
willy tarreau0f7af912005-12-17 12:21:26 +01005733 curproxy = curproxy->next;
5734 }
5735 if (cfgerr > 0) {
5736 Alert("Errors found in configuration file, aborting.\n");
5737 return -1;
5738 }
5739 else
5740 return 0;
5741}
5742
5743
5744/*
5745 * This function initializes all the necessary variables. It only returns
5746 * if everything is OK. If something fails, it exits.
5747 */
5748void init(int argc, char **argv) {
5749 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01005750 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01005751 char *old_argv = *argv;
5752 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01005753 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01005754 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01005755
5756 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01005757 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005758 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
5759 sizeof(int)*8);
5760 exit(1);
5761 }
5762
5763 pid = getpid();
5764 progname = *argv;
5765 while ((tmp = strchr(progname, '/')) != NULL)
5766 progname = tmp + 1;
5767
5768 argc--; argv++;
5769 while (argc > 0) {
5770 char *flag;
5771
5772 if (**argv == '-') {
5773 flag = *argv+1;
5774
5775 /* 1 arg */
5776 if (*flag == 'v') {
5777 display_version();
5778 exit(0);
5779 }
5780 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01005781 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01005782 else if (*flag == 'c')
5783 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01005784 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01005785 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005786 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01005787 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01005788#if STATTIME > 0
5789 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01005790 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01005791 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01005792 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01005793#endif
5794 else { /* >=2 args */
5795 argv++; argc--;
5796 if (argc == 0)
5797 usage(old_argv);
5798
5799 switch (*flag) {
5800 case 'n' : cfg_maxconn = atol(*argv); break;
5801 case 'N' : cfg_maxpconn = atol(*argv); break;
5802 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01005803 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01005804 default: usage(old_argv);
5805 }
5806 }
5807 }
5808 else
5809 usage(old_argv);
5810 argv++; argc--;
5811 }
5812
willy tarreaudd07e972005-12-18 00:48:48 +01005813 global.mode = (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG));
5814
willy tarreau0f7af912005-12-17 12:21:26 +01005815 if (!cfg_cfgfile)
5816 usage(old_argv);
5817
5818 gethostname(hostname, MAX_HOSTNAME_LEN);
5819
5820 if (readcfgfile(cfg_cfgfile) < 0) {
5821 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
5822 exit(1);
5823 }
5824
willy tarreaudd07e972005-12-18 00:48:48 +01005825 if (arg_mode & MODE_CHECK) {
5826 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
5827 exit(0);
5828 }
5829
willy tarreau9fe663a2005-12-17 13:02:59 +01005830 if (cfg_maxconn > 0)
5831 global.maxconn = cfg_maxconn;
5832
willy tarreaufe2c5c12005-12-17 14:14:34 +01005833 if (cfg_pidfile) {
5834 if (global.pidfile)
5835 free(global.pidfile);
5836 global.pidfile = strdup(cfg_pidfile);
5837 }
5838
willy tarreau9fe663a2005-12-17 13:02:59 +01005839 if (global.maxconn == 0)
5840 global.maxconn = DEFAULT_MAXCONN;
5841
5842 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
5843
5844 if (arg_mode & MODE_DEBUG) {
5845 /* command line debug mode inhibits configuration mode */
5846 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5847 }
willy tarreau750a4722005-12-17 13:21:24 +01005848 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01005849
5850 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
5851 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
5852 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5853 }
5854
5855 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
5856 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
5857 global.nbproc = 1;
5858 }
5859
5860 if (global.nbproc < 1)
5861 global.nbproc = 1;
5862
willy tarreau0f7af912005-12-17 12:21:26 +01005863 ReadEvent = (fd_set *)calloc(1,
5864 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005865 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005866 WriteEvent = (fd_set *)calloc(1,
5867 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005868 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005869 StaticReadEvent = (fd_set *)calloc(1,
5870 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005871 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005872 StaticWriteEvent = (fd_set *)calloc(1,
5873 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005874 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005875
5876 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01005877 sizeof(struct fdtab) * (global.maxsock));
5878 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01005879 fdtab[i].state = FD_STCLOSE;
5880 }
5881}
5882
5883/*
5884 * this function starts all the proxies. It returns 0 if OK, -1 if not.
5885 */
5886int start_proxies() {
5887 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01005888 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01005889 int fd;
5890
5891 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01005892 if (curproxy->state == PR_STDISABLED)
5893 continue;
5894
willy tarreaua41a8b42005-12-17 14:02:24 +01005895 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
5896 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01005897 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005898 Alert("cannot create listening socket for proxy %s. Aborting.\n",
5899 curproxy->id);
5900 return -1;
5901 }
willy tarreau0f7af912005-12-17 12:21:26 +01005902
willy tarreaua41a8b42005-12-17 14:02:24 +01005903 if (fd >= global.maxsock) {
5904 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
5905 curproxy->id);
5906 close(fd);
5907 return -1;
5908 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005909
willy tarreaua41a8b42005-12-17 14:02:24 +01005910 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
5911 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
5912 (char *) &one, sizeof(one)) == -1)) {
5913 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
5914 curproxy->id);
5915 close(fd);
5916 return -1;
5917 }
willy tarreau0f7af912005-12-17 12:21:26 +01005918
willy tarreaua41a8b42005-12-17 14:02:24 +01005919 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
5920 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
5921 curproxy->id);
5922 }
willy tarreau0f7af912005-12-17 12:21:26 +01005923
willy tarreaua41a8b42005-12-17 14:02:24 +01005924 if (bind(fd,
5925 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01005926 listener->addr.ss_family == AF_INET6 ?
5927 sizeof(struct sockaddr_in6) :
5928 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005929 Alert("cannot bind socket for proxy %s. Aborting.\n",
5930 curproxy->id);
5931 close(fd);
5932 return -1;
5933 }
willy tarreau0f7af912005-12-17 12:21:26 +01005934
willy tarreaua41a8b42005-12-17 14:02:24 +01005935 if (listen(fd, curproxy->maxconn) == -1) {
5936 Alert("cannot listen to socket for proxy %s. Aborting.\n",
5937 curproxy->id);
5938 close(fd);
5939 return -1;
5940 }
willy tarreau0f7af912005-12-17 12:21:26 +01005941
willy tarreaua41a8b42005-12-17 14:02:24 +01005942 /* the function for the accept() event */
5943 fdtab[fd].read = &event_accept;
5944 fdtab[fd].write = NULL; /* never called */
5945 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
5946 curproxy->state = PR_STRUN;
5947 fdtab[fd].state = FD_STLISTEN;
5948 FD_SET(fd, StaticReadEvent);
5949 fd_insert(fd);
5950 listeners++;
5951 }
willy tarreaua1598082005-12-17 13:08:06 +01005952 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005953 }
5954 return 0;
5955}
5956
5957
5958int main(int argc, char **argv) {
willy tarreaufe2c5c12005-12-17 14:14:34 +01005959 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01005960 init(argc, argv);
5961
willy tarreau9fe663a2005-12-17 13:02:59 +01005962 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01005963 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005964 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01005965 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01005966 }
5967
5968 signal(SIGQUIT, dump);
5969 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01005970 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005971
5972 /* on very high loads, a sigpipe sometimes happen just between the
5973 * getsockopt() which tells "it's OK to write", and the following write :-(
5974 */
willy tarreau3242e862005-12-17 12:27:53 +01005975#ifndef MSG_NOSIGNAL
5976 signal(SIGPIPE, SIG_IGN);
5977#endif
willy tarreau0f7af912005-12-17 12:21:26 +01005978
5979 if (start_proxies() < 0)
5980 exit(1);
5981
willy tarreaufe2c5c12005-12-17 14:14:34 +01005982 /* open log & pid files before the chroot */
5983 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
5984 int pidfd;
5985 unlink(global.pidfile);
5986 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
5987 if (pidfd < 0) {
5988 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
5989 exit(1);
5990 }
5991 pidfile = fdopen(pidfd, "w");
5992 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005993
5994 /* chroot if needed */
5995 if (global.chroot != NULL) {
5996 if (chroot(global.chroot) == -1) {
5997 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
5998 exit(1);
5999 }
6000 chdir("/");
6001 }
6002
6003 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01006004 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006005 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
6006 exit(1);
6007 }
6008
willy tarreau036e1ce2005-12-17 13:46:33 +01006009 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006010 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
6011 exit(1);
6012 }
6013
6014 if (global.mode & MODE_DAEMON) {
6015 int ret = 0;
6016 int proc;
6017
6018 /* the father launches the required number of processes */
6019 for (proc = 0; proc < global.nbproc; proc++) {
6020 ret = fork();
6021 if (ret < 0) {
6022 Alert("[%s.main()] Cannot fork.\n", argv[0]);
6023 exit(1); /* there has been an error */
6024 }
6025 else if (ret == 0) /* child breaks here */
6026 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006027 if (pidfile != NULL) {
6028 fprintf(pidfile, "%d\n", ret);
6029 fflush(pidfile);
6030 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006031 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006032 /* close the pidfile both in children and father */
6033 if (pidfile != NULL)
6034 fclose(pidfile);
6035 free(global.pidfile);
6036
willy tarreau9fe663a2005-12-17 13:02:59 +01006037 if (proc == global.nbproc)
6038 exit(0); /* parent must leave */
6039
willy tarreau750a4722005-12-17 13:21:24 +01006040 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
6041 * that we can detach from the TTY. We MUST NOT do it in other cases since
6042 * it would have already be done, and 0-2 would have been affected to listening
6043 * sockets
6044 */
6045 if (!(global.mode & MODE_QUIET)) {
6046 /* detach from the tty */
6047 fclose(stdin); fclose(stdout); fclose(stderr);
6048 close(0); close(1); close(2); /* close all fd's */
6049 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
6050 }
willy tarreaua1598082005-12-17 13:08:06 +01006051 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01006052 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01006053 }
6054
willy tarreau0f7af912005-12-17 12:21:26 +01006055 select_loop();
6056
6057 exit(0);
6058}