blob: 10bb3e031a2f4e3ce51c42fcd3950e66a1b8a0da [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau036e1ce2005-12-17 13:46:33 +01003 * 2000-2003 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
11 * RFC2965 for informations about cookies usage.
12 *
13 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010014 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
15 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010016 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010017 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
18 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010019 * - a proxy with an invalid config will prevent the startup even if disabled.
20 *
willy tarreau036e1ce2005-12-17 13:46:33 +010021 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010022 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010023 * TODO:
24 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010025 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010026 * - fix client/server state transition when server is in connect or headers state
27 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
28 * still handle HTTP headers.
willy tarreau0f7af912005-12-17 12:21:26 +010029 *
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <string.h>
36#include <ctype.h>
37#include <sys/time.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <netinet/tcp.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <netdb.h>
44#include <fcntl.h>
45#include <errno.h>
46#include <signal.h>
47#include <stdarg.h>
48#include <sys/resource.h>
49#include <time.h>
50#include <regex.h>
51#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010052#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010053#include <linux/netfilter_ipv4.h>
54#endif
willy tarreau0f7af912005-12-17 12:21:26 +010055
willy tarreau8a86dbf2005-12-18 00:45:59 +010056#define HAPROXY_VERSION "1.1.27-ipv6"
57#define HAPROXY_DATE "2003/11/09"
willy tarreau0f7af912005-12-17 12:21:26 +010058
59/* this is for libc5 for example */
60#ifndef TCP_NODELAY
61#define TCP_NODELAY 1
62#endif
63
64#ifndef SHUT_RD
65#define SHUT_RD 0
66#endif
67
68#ifndef SHUT_WR
69#define SHUT_WR 1
70#endif
71
willy tarreau535ae7a2005-12-17 12:58:00 +010072#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +010073
74// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +010075#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +010076#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +010077#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +010078
willy tarreau5cbea6f2005-12-17 12:48:26 +010079// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +010080#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +010081
willy tarreaue39cd132005-12-17 13:00:18 +010082// max # of added headers per request
83#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +010084
85// max # of matches per regexp
86#define MAX_MATCH 10
87
willy tarreau5cbea6f2005-12-17 12:48:26 +010088/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +010089#define COOKIENAME_LEN 16
90#define SERVERID_LEN 16
91#define CONN_RETRIES 3
92
willy tarreau5cbea6f2005-12-17 12:48:26 +010093#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +010094#define DEF_CHKINTR 2000
95#define DEF_FALLTIME 3
96#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +010097#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +010098
willy tarreau9fe663a2005-12-17 13:02:59 +010099/* default connections limit */
100#define DEFAULT_MAXCONN 2000
101
willy tarreau0f7af912005-12-17 12:21:26 +0100102/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
103#define INTBITS 5
104
105/* show stats this every millisecond, 0 to disable */
106#ifndef STATTIME
107#define STATTIME 2000
108#endif
109
willy tarreau5cbea6f2005-12-17 12:48:26 +0100110/* this reduces the number of calls to select() by choosing appropriate
111 * sheduler precision in milliseconds. It should be near the minimum
112 * time that is needed by select() to collect all events. All timeouts
113 * are rounded up by adding this value prior to pass it to select().
114 */
115#define SCHEDULER_RESOLUTION 9
116
willy tarreau0f7af912005-12-17 12:21:26 +0100117#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
118#define SETNOW(a) (*a=now)
119
willy tarreau9da061b2005-12-17 12:29:56 +0100120/****** string-specific macros and functions ******/
121/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
122#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
123
124/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
125#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
126
willy tarreau9da061b2005-12-17 12:29:56 +0100127/*
128 * copies at most <size-1> chars from <src> to <dst>. Last char is always
129 * set to 0, unless <size> is 0. The number of chars copied is returned
130 * (excluding the terminating zero).
131 * This code has been optimized for size and speed : on x86, it's 45 bytes
132 * long, uses only registers, and consumes only 4 cycles per char.
133 */
willy tarreau750a4722005-12-17 13:21:24 +0100134int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100135 char *orig = dst;
136 if (size) {
137 while (--size && (*dst = *src)) {
138 src++; dst++;
139 }
140 *dst = 0;
141 }
142 return dst - orig;
143}
willy tarreau9da061b2005-12-17 12:29:56 +0100144
willy tarreau0f7af912005-12-17 12:21:26 +0100145#define MEM_OPTIM
146#ifdef MEM_OPTIM
147/*
148 * Returns a pointer to type <type> taken from the
149 * pool <pool_type> or dynamically allocated. In the
150 * first case, <pool_type> is updated to point to the
151 * next element in the list.
152 */
153#define pool_alloc(type) ({ \
154 void *p; \
155 if ((p = pool_##type) == NULL) \
156 p = malloc(sizeof_##type); \
157 else { \
158 pool_##type = *(void **)pool_##type; \
159 } \
160 p; \
161})
162
163/*
164 * Puts a memory area back to the corresponding pool.
165 * Items are chained directly through a pointer that
166 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100167 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100168 * that each memory area is at least as big as one
169 * pointer.
170 */
171#define pool_free(type, ptr) ({ \
172 *(void **)ptr = (void *)pool_##type; \
173 pool_##type = (void *)ptr; \
174})
175
176#else
177#define pool_alloc(type) (calloc(1,sizeof_##type));
178#define pool_free(type, ptr) (free(ptr));
179#endif /* MEM_OPTIM */
180
willy tarreau5cbea6f2005-12-17 12:48:26 +0100181#define sizeof_task sizeof(struct task)
182#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100183#define sizeof_buffer sizeof(struct buffer)
184#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100185#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100186#define sizeof_capture CAPTURE_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100187
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define FD_STCLOSE 0
190#define FD_STLISTEN 1
191#define FD_STCONN 2
192#define FD_STREADY 3
193#define FD_STERROR 4
194
willy tarreau5cbea6f2005-12-17 12:48:26 +0100195/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100196#define TASK_IDLE 0
197#define TASK_RUNNING 1
198
willy tarreau5cbea6f2005-12-17 12:48:26 +0100199/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100200#define PR_STNEW 0
201#define PR_STIDLE 1
202#define PR_STRUN 2
203#define PR_STDISABLED 3
204
willy tarreau5cbea6f2005-12-17 12:48:26 +0100205/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100206#define PR_MODE_TCP 0
207#define PR_MODE_HTTP 1
208#define PR_MODE_HEALTH 2
209
willy tarreau5cbea6f2005-12-17 12:48:26 +0100210/* bits for proxy->options */
211#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
212#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
213#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
214#define PR_O_COOK_IND 8 /* keep only indirect cookies */
215#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
216#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
217#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
218#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100219#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
220#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100221#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
222#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100223#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100224#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100225#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
willy tarreau8337c6b2005-12-17 13:41:01 +0100226#define PR_O_PERSIST 8192 /* server persistence stays effective even when server is down */
willy tarreau9fe663a2005-12-17 13:02:59 +0100227
willy tarreau5cbea6f2005-12-17 12:48:26 +0100228
willy tarreaue39cd132005-12-17 13:00:18 +0100229/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100230#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
231#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
232#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
233#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
234#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
235#define SN_POST 0x00000020 /* the request was an HTTP POST */
236
237#define SN_CK_NONE 0x00000000 /* this session had no cookie */
238#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
239#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
240#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
241#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
242#define SN_CK_SHIFT 6 /* bit shift */
243
244#define SN_ERR_CLITO 0x00000100 /* client time-out */
245#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
246#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
247#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
248#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
249#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
250#define SN_ERR_SHIFT 8 /* bit shift */
251
252#define SN_FINST_R 0x00001000 /* session ended during client request */
253#define SN_FINST_C 0x00002000 /* session ended during server connect */
254#define SN_FINST_H 0x00003000 /* session ended during server headers */
255#define SN_FINST_D 0x00004000 /* session ended during data phase */
256#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
257#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
258#define SN_FINST_SHIFT 12 /* bit shift */
259
260#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
261#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
262#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
263#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
264#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
265#define SN_SCK_SHIFT 16 /* bit shift */
266
willy tarreau5cbea6f2005-12-17 12:48:26 +0100267
268/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100269#define CL_STHEADERS 0
270#define CL_STDATA 1
271#define CL_STSHUTR 2
272#define CL_STSHUTW 3
273#define CL_STCLOSE 4
274
willy tarreau5cbea6f2005-12-17 12:48:26 +0100275/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100276#define SV_STIDLE 0
277#define SV_STCONN 1
278#define SV_STHEADERS 2
279#define SV_STDATA 3
280#define SV_STSHUTR 4
281#define SV_STSHUTW 5
282#define SV_STCLOSE 6
283
284/* result of an I/O event */
285#define RES_SILENT 0 /* didn't happen */
286#define RES_DATA 1 /* data were sent or received */
287#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
288#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
289
willy tarreau9fe663a2005-12-17 13:02:59 +0100290/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100291#define MODE_DEBUG 1
292#define MODE_STATS 2
293#define MODE_LOG 4
294#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295#define MODE_QUIET 16
296
297/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100298#define SRV_RUNNING 1 /* the server is UP */
299#define SRV_BACKUP 2 /* this server is a backup server */
300#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0f7af912005-12-17 12:21:26 +0100301
willy tarreaue39cd132005-12-17 13:00:18 +0100302/* what to do when a header matches a regex */
303#define ACT_ALLOW 0 /* allow the request */
304#define ACT_REPLACE 1 /* replace the matching header */
305#define ACT_REMOVE 2 /* remove the matching header */
306#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100307#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100308
willy tarreau9fe663a2005-12-17 13:02:59 +0100309/* configuration sections */
310#define CFG_NONE 0
311#define CFG_GLOBAL 1
312#define CFG_LISTEN 2
313
willy tarreaua1598082005-12-17 13:08:06 +0100314/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100315#define LW_DATE 1 /* date */
316#define LW_CLIP 2 /* CLient IP */
317#define LW_SVIP 4 /* SerVer IP */
318#define LW_SVID 8 /* server ID */
319#define LW_REQ 16 /* http REQuest */
320#define LW_RESP 32 /* http RESPonse */
321#define LW_PXIP 64 /* proxy IP */
322#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100323#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100324
willy tarreau0f7af912005-12-17 12:21:26 +0100325/*********************************************************************/
326
327#define LIST_HEAD(a) ((void *)(&(a)))
328
329/*********************************************************************/
330
331struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100332 struct hdr_exp *next;
333 regex_t *preg; /* expression to look for */
334 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
335 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100336};
337
338struct buffer {
339 unsigned int l; /* data length */
340 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100341 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100342 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100343 char data[BUFSIZE];
344};
345
346struct server {
347 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100348 int state; /* server state (SRV_*) */
349 int cklen; /* the len of the cookie, to speed up checks */
350 char *cookie; /* the id set in the cookie */
351 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100352 struct sockaddr_in addr; /* the address to connect to */
willy tarreaua41a8b42005-12-17 14:02:24 +0100353 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100355 int rise, fall; /* time in iterations */
356 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100357 int result; /* 0 = connect OK, -1 = connect KO */
358 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100359 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100360};
361
willy tarreau5cbea6f2005-12-17 12:48:26 +0100362/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100363struct task {
364 struct task *next, *prev; /* chaining ... */
365 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100366 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100367 int state; /* task state : IDLE or RUNNING */
368 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100369 int (*process)(struct task *t); /* the function which processes the task */
370 void *context; /* the task's context */
371};
372
373/* WARNING: if new fields are added, they must be initialized in event_accept() */
374struct session {
375 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100376 /* application specific below */
377 struct timeval crexpire; /* expiration date for a client read */
378 struct timeval cwexpire; /* expiration date for a client write */
379 struct timeval srexpire; /* expiration date for a server read */
380 struct timeval swexpire; /* expiration date for a server write */
381 struct timeval cnexpire; /* expiration date for a connect */
382 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
383 struct proxy *proxy; /* the proxy this socket belongs to */
384 int cli_fd; /* the client side fd */
385 int srv_fd; /* the server side fd */
386 int cli_state; /* state of the client side */
387 int srv_state; /* state of the server side */
388 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100389 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100390 struct buffer *req; /* request buffer */
391 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100392 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100393 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100394 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100395 struct {
396 int logwait; /* log fields waiting to be collected : LW_* */
397 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
398 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
399 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
400 long t_data; /* delay before the first data byte from the server ... */
401 unsigned long t_close; /* total session duration */
402 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100403 char *cli_cookie; /* cookie presented by the client, in capture mode */
404 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100405 int status; /* HTTP status from the server, negative if from proxy */
406 long long bytes; /* number of bytes transferred from the server */
407 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100408 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100409};
410
willy tarreaua41a8b42005-12-17 14:02:24 +0100411struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100412 int fd; /* the listen socket */
413 struct sockaddr_storage addr; /* the address we listen to */
414 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100415};
416
417
willy tarreau0f7af912005-12-17 12:21:26 +0100418struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100419 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100420 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100421 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100422 struct server *srv, *cursrv; /* known servers, current server */
423 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100424 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100425 int cookie_len; /* strlen(cookie_len), computed only once */
426 char *capture_name; /* beginning of the name of the cookie to capture */
427 int capture_namelen; /* length of the cookie name to match */
428 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100429 int clitimeout; /* client I/O timeout (in milliseconds) */
430 int srvtimeout; /* server I/O timeout (in milliseconds) */
431 int contimeout; /* connect timeout (in milliseconds) */
432 char *id; /* proxy id */
433 int nbconn; /* # of active sessions */
434 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100435 int conn_retries; /* maximum number of connect retries */
436 int options; /* PR_O_REDISP, PR_O_TRANSP */
437 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100438 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100439 struct proxy *next;
440 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
441 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100442 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100443 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100444 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100445 int nb_reqadd, nb_rspadd;
446 struct hdr_exp *req_exp; /* regular expressions for request headers */
447 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
448 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100449 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100450 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
451 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100452 struct {
453 char *msg400; /* message for error 400 */
454 int len400; /* message length for error 400 */
455 char *msg403; /* message for error 403 */
456 int len403; /* message length for error 403 */
457 char *msg408; /* message for error 408 */
458 int len408; /* message length for error 408 */
459 char *msg500; /* message for error 500 */
460 int len500; /* message length for error 500 */
461 char *msg502; /* message for error 502 */
462 int len502; /* message length for error 502 */
463 char *msg503; /* message for error 503 */
464 int len503; /* message length for error 503 */
465 char *msg504; /* message for error 504 */
466 int len504; /* message length for error 504 */
467 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100468};
469
470/* info about one given fd */
471struct fdtab {
472 int (*read)(int fd); /* read function */
473 int (*write)(int fd); /* write function */
474 struct task *owner; /* the session (or proxy) associated with this fd */
475 int state; /* the state of this fd */
476};
477
478/*********************************************************************/
479
willy tarreau0f7af912005-12-17 12:21:26 +0100480int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100481char *cfg_cfgfile = NULL; /* configuration file */
482char *progname = NULL; /* program name */
483int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100484
485/* global options */
486static struct {
487 int uid;
488 int gid;
489 int nbproc;
490 int maxconn;
491 int maxsock; /* max # of sockets */
492 int mode;
493 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100494 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100495 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100496 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100497 struct sockaddr_in logsrv1, logsrv2;
498} global = {
499 logfac1 : -1,
500 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100501 loglev1 : 7, /* max syslog level : debug */
502 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100503 /* others NULL OK */
504};
505
willy tarreau0f7af912005-12-17 12:21:26 +0100506/*********************************************************************/
507
508fd_set *ReadEvent,
509 *WriteEvent,
510 *StaticReadEvent,
511 *StaticWriteEvent;
512
513void **pool_session = NULL,
514 **pool_buffer = NULL,
515 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100516 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100517 **pool_task = NULL,
518 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100519
520struct proxy *proxy = NULL; /* list of all existing proxies */
521struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100522struct task *rq = NULL; /* global run queue */
523struct task wait_queue = { /* global wait queue */
524 prev:LIST_HEAD(wait_queue),
525 next:LIST_HEAD(wait_queue)
526};
willy tarreau0f7af912005-12-17 12:21:26 +0100527
willy tarreau0f7af912005-12-17 12:21:26 +0100528static int totalconn = 0; /* total # of terminated sessions */
529static int actconn = 0; /* # of active sessions */
530static int maxfd = 0; /* # of the highest fd + 1 */
531static int listeners = 0; /* # of listeners */
532static int stopping = 0; /* non zero means stopping in progress */
533static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100534static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100535
536static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100537/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100538static char trash[BUFSIZE];
539
540/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100541 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100542 */
543
544#define MAX_SYSLOG_LEN 1024
545#define NB_LOG_FACILITIES 24
546const char *log_facilities[NB_LOG_FACILITIES] = {
547 "kern", "user", "mail", "daemon",
548 "auth", "syslog", "lpr", "news",
549 "uucp", "cron", "auth2", "ftp",
550 "ntp", "audit", "alert", "cron2",
551 "local0", "local1", "local2", "local3",
552 "local4", "local5", "local6", "local7"
553};
554
555
556#define NB_LOG_LEVELS 8
557const char *log_levels[NB_LOG_LEVELS] = {
558 "emerg", "alert", "crit", "err",
559 "warning", "notice", "info", "debug"
560};
561
562#define SYSLOG_PORT 514
563
564const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
565 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100566
567const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
568const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
569const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
570const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
571 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
572 unknown, Set-cookie Rewritten */
573
willy tarreau0f7af912005-12-17 12:21:26 +0100574#define MAX_HOSTNAME_LEN 32
575static char hostname[MAX_HOSTNAME_LEN] = "";
576
willy tarreau8337c6b2005-12-17 13:41:01 +0100577const char *HTTP_302 =
578 "HTTP/1.0 302 Found\r\n"
579 "Cache-Control: no-cache\r\n"
580 "Connection: close\r\n"
581 "Location: "; /* not terminated since it will be concatenated with the URL */
582
willy tarreaua1598082005-12-17 13:08:06 +0100583const char *HTTP_400 =
584 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100585 "Cache-Control: no-cache\r\n"
586 "Connection: close\r\n"
587 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100588 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100589
willy tarreaua1598082005-12-17 13:08:06 +0100590const char *HTTP_403 =
591 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100592 "Cache-Control: no-cache\r\n"
593 "Connection: close\r\n"
594 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100595 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
596
willy tarreau8337c6b2005-12-17 13:41:01 +0100597const char *HTTP_408 =
598 "HTTP/1.0 408 Request Time-out\r\n"
599 "Cache-Control: no-cache\r\n"
600 "Connection: close\r\n"
601 "\r\n"
602 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
603
willy tarreau750a4722005-12-17 13:21:24 +0100604const char *HTTP_500 =
605 "HTTP/1.0 500 Server Error\r\n"
606 "Cache-Control: no-cache\r\n"
607 "Connection: close\r\n"
608 "\r\n"
609 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100610
611const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100612 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100613 "Cache-Control: no-cache\r\n"
614 "Connection: close\r\n"
615 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100616 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
617
618const char *HTTP_503 =
619 "HTTP/1.0 503 Service Unavailable\r\n"
620 "Cache-Control: no-cache\r\n"
621 "Connection: close\r\n"
622 "\r\n"
623 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
624
625const char *HTTP_504 =
626 "HTTP/1.0 504 Gateway Time-out\r\n"
627 "Cache-Control: no-cache\r\n"
628 "Connection: close\r\n"
629 "\r\n"
630 "<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 +0100631
willy tarreau0f7af912005-12-17 12:21:26 +0100632/*********************************************************************/
633/* statistics ******************************************************/
634/*********************************************************************/
635
willy tarreau750a4722005-12-17 13:21:24 +0100636#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100637static int stats_tsk_lsrch, stats_tsk_rsrch,
638 stats_tsk_good, stats_tsk_right, stats_tsk_left,
639 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100640#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100641
642
643/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100644/* debugging *******************************************************/
645/*********************************************************************/
646#ifdef DEBUG_FULL
647static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
648static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
649#endif
650
651/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100652/* function prototypes *********************************************/
653/*********************************************************************/
654
655int event_accept(int fd);
656int event_cli_read(int fd);
657int event_cli_write(int fd);
658int event_srv_read(int fd);
659int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100660int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100661
662/*********************************************************************/
663/* general purpose functions ***************************************/
664/*********************************************************************/
665
666void display_version() {
667 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreauc1cae632005-12-17 14:12:23 +0100668 printf("Copyright 2000-2003 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100669}
670
671/*
672 * This function prints the command line usage and exits
673 */
674void usage(char *name) {
675 display_version();
676 fprintf(stderr,
677 "Usage : %s -f <cfgfile> [ -vd"
678#if STATTIME > 0
679 "sl"
680#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100681 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100682 " -v displays version\n"
683 " -d enters debug mode\n"
684#if STATTIME > 0
685 " -s enables statistics output\n"
686 " -l enables long statistics format\n"
687#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100688 " -D goes daemon ; implies -q\n"
689 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100690 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100691 " -N sets the default, per-proxy maximum # of connections (%d)\n"
692 " -p writes pids of all children to this file\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100693 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100694 exit(1);
695}
696
697
698/*
699 * Displays the message on stderr with the date and pid.
700 */
701void Alert(char *fmt, ...) {
702 va_list argp;
703 struct timeval tv;
704 struct tm *tm;
705
willy tarreau9fe663a2005-12-17 13:02:59 +0100706 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100707 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100708
willy tarreau5cbea6f2005-12-17 12:48:26 +0100709 gettimeofday(&tv, NULL);
710 tm=localtime(&tv.tv_sec);
711 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100712 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100713 vfprintf(stderr, fmt, argp);
714 fflush(stderr);
715 va_end(argp);
716 }
willy tarreau0f7af912005-12-17 12:21:26 +0100717}
718
719
720/*
721 * Displays the message on stderr with the date and pid.
722 */
723void Warning(char *fmt, ...) {
724 va_list argp;
725 struct timeval tv;
726 struct tm *tm;
727
willy tarreau9fe663a2005-12-17 13:02:59 +0100728 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100729 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100730
willy tarreau5cbea6f2005-12-17 12:48:26 +0100731 gettimeofday(&tv, NULL);
732 tm=localtime(&tv.tv_sec);
733 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100734 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100735 vfprintf(stderr, fmt, argp);
736 fflush(stderr);
737 va_end(argp);
738 }
739}
740
741/*
742 * Displays the message on <out> only if quiet mode is not set.
743 */
744void qfprintf(FILE *out, char *fmt, ...) {
745 va_list argp;
746
willy tarreau9fe663a2005-12-17 13:02:59 +0100747 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100748 va_start(argp, fmt);
749 vfprintf(out, fmt, argp);
750 fflush(out);
751 va_end(argp);
752 }
willy tarreau0f7af912005-12-17 12:21:26 +0100753}
754
755
756/*
757 * converts <str> to a struct sockaddr_in* which is locally allocated.
758 * The format is "addr:port", where "addr" can be empty or "*" to indicate
759 * INADDR_ANY.
760 */
761struct sockaddr_in *str2sa(char *str) {
762 static struct sockaddr_in sa;
763 char *c;
764 int port;
765
willy tarreaua1598082005-12-17 13:08:06 +0100766 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100767 str=strdup(str);
768
769 if ((c=strrchr(str,':')) != NULL) {
770 *c++=0;
771 port=atol(c);
772 }
773 else
774 port=0;
775
776 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
777 sa.sin_addr.s_addr = INADDR_ANY;
778 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100779 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100780 struct hostent *he;
781
782 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100783 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100784 }
785 else
786 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
787 }
788 sa.sin_port=htons(port);
789 sa.sin_family=AF_INET;
790
791 free(str);
792 return &sa;
793}
794
willy tarreau9fe663a2005-12-17 13:02:59 +0100795
796/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100797 * converts <str> to a list of listeners which are dynamically allocated.
798 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
799 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
800 * - <port> is a numerical port from 1 to 65535 ;
801 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
802 * This can be repeated as many times as necessary, separated by a coma.
803 * The <tail> argument is a pointer to a current list which should be appended
804 * to the tail of the new list. The pointer to the new list is returned.
805 */
806struct listener *str2listener(char *str, struct listener *tail) {
807 struct listener *l;
808 char *c, *next, *range, *dupstr;
809 int port, end;
810
811 next = dupstr = strdup(str);
willy tarreaua41a8b42005-12-17 14:02:24 +0100812 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100813 struct sockaddr_storage ss;
814
willy tarreaua41a8b42005-12-17 14:02:24 +0100815 str = next;
816 /* 1) look for the end of the first address */
817 if ((next = strrchr(str, ',')) != NULL) {
818 *next++ = 0;
819 }
820
willy tarreau8a86dbf2005-12-18 00:45:59 +0100821 /* 2) look for the addr/port delimiter, it's the last colon. */
822 if ((range = strrchr(str, ':')) == NULL) {
823 Alert("Missing port number: '%s'\n", str);
824 }
825
826 *range++ = 0;
827
828 if (strrchr(str, ':') != NULL) {
829 /* IPv6 address contains ':' */
830 memset(&ss, 0, sizeof(ss));
831 ss.ss_family = AF_INET6;
832
833 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
834 Alert("Invalid server address: '%s'\n", str);
835 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100836 }
837 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100838 memset(&ss, 0, sizeof(ss));
839 ss.ss_family = AF_INET;
840
841 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
842 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
843 }
844 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
845 struct hostent *he;
846
847 if ((he = gethostbyname(str)) == NULL) {
848 Alert("Invalid server name: '%s'\n", str);
849 }
850 else
851 ((struct sockaddr_in *)&ss)->sin_addr =
852 *(struct in_addr *) *(he->h_addr_list);
853 }
854 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100855
856 /* 3) look for the port-end delimiter */
857 if ((c = strchr(range, '-')) != NULL) {
858 *c++ = 0;
859 end = atol(c);
860 }
861 else {
862 end = atol(range);
863 }
864
865 for (port = atol(range); port <= end; port++) {
866 l = (struct listener *)calloc(1, sizeof(struct listener));
867 l->next = tail;
868 tail = l;
869
willy tarreau8a86dbf2005-12-18 00:45:59 +0100870 l->addr = ss;
871 if (ss.ss_family == AF_INET6)
872 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
873 else
874 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
875
willy tarreaua41a8b42005-12-17 14:02:24 +0100876 } /* end for(port) */
877 } /* end while(next) */
878 free(dupstr);
879 return tail;
880}
881
882
883/*
willy tarreau9fe663a2005-12-17 13:02:59 +0100884 * This function sends a syslog message to both log servers of a proxy,
885 * or to global log servers if the proxy is NULL.
886 * It also tries not to waste too much time computing the message header.
887 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100888 */
889void send_log(struct proxy *p, int level, char *message, ...) {
890 static int logfd = -1; /* syslog UDP socket */
891 static long tvsec = -1; /* to force the string to be initialized */
892 struct timeval tv;
893 va_list argp;
894 static char logmsg[MAX_SYSLOG_LEN];
895 static char *dataptr = NULL;
896 int fac_level;
897 int hdr_len, data_len;
898 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +0100899 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +0100900 int nbloggers = 0;
901 char *log_ptr;
902
903 if (logfd < 0) {
904 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
905 return;
906 }
907
908 if (level < 0 || progname == NULL || message == NULL)
909 return;
910
911 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100912 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100913 /* this string is rebuild only once a second */
914 struct tm *tm = localtime(&tv.tv_sec);
915 tvsec = tv.tv_sec;
916
willy tarreauc29948c2005-12-17 13:10:27 +0100917 hdr_len = snprintf(logmsg, sizeof(logmsg),
918 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
919 monthname[tm->tm_mon],
920 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
921 progname, pid);
922 /* WARNING: depending upon implementations, snprintf may return
923 * either -1 or the number of bytes that would be needed to store
924 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100925 */
willy tarreauc29948c2005-12-17 13:10:27 +0100926 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
927 hdr_len = sizeof(logmsg);
928
929 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100930 }
931
932 va_start(argp, message);
933 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100934 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
935 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100936 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100937 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100938
939 if (p == NULL) {
940 if (global.logfac1 >= 0) {
941 sa[nbloggers] = &global.logsrv1;
942 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100943 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100944 nbloggers++;
945 }
946 if (global.logfac2 >= 0) {
947 sa[nbloggers] = &global.logsrv2;
948 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100949 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100950 nbloggers++;
951 }
952 } else {
953 if (p->logfac1 >= 0) {
954 sa[nbloggers] = &p->logsrv1;
955 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100956 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100957 nbloggers++;
958 }
959 if (p->logfac2 >= 0) {
960 sa[nbloggers] = &p->logsrv2;
961 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100962 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100963 nbloggers++;
964 }
965 }
966
967 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +0100968 /* we can filter the level of the messages that are sent to each logger */
969 if (level > loglevel[nbloggers])
970 continue;
971
willy tarreauc29948c2005-12-17 13:10:27 +0100972 /* For each target, we may have a different facility.
973 * We can also have a different log level for each message.
974 * This induces variations in the message header length.
975 * Since we don't want to recompute it each time, nor copy it every
976 * time, we only change the facility in the pre-computed header,
977 * and we change the pointer to the header accordingly.
978 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100979 fac_level = (facilities[nbloggers] << 3) + level;
980 log_ptr = logmsg + 3; /* last digit of the log level */
981 do {
982 *log_ptr = '0' + fac_level % 10;
983 fac_level /= 10;
984 log_ptr--;
985 } while (fac_level && log_ptr > logmsg);
986 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100987
willy tarreauc29948c2005-12-17 13:10:27 +0100988 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100989
990#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100991 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100992 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
993#else
willy tarreauc29948c2005-12-17 13:10:27 +0100994 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100995 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
996#endif
997 }
willy tarreau0f7af912005-12-17 12:21:26 +0100998}
999
1000
1001/* sets <tv> to the current time */
1002static inline struct timeval *tv_now(struct timeval *tv) {
1003 if (tv)
1004 gettimeofday(tv, NULL);
1005 return tv;
1006}
1007
1008/*
1009 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1010 */
1011static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1012 if (!tv || !from)
1013 return NULL;
1014 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1015 tv->tv_sec = from->tv_sec + (ms/1000);
1016 while (tv->tv_usec >= 1000000) {
1017 tv->tv_usec -= 1000000;
1018 tv->tv_sec++;
1019 }
1020 return tv;
1021}
1022
1023/*
1024 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1025 */
1026static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001027 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001028 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001029 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001030 return 1;
1031 else if (tv1->tv_usec < tv2->tv_usec)
1032 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001033 else if (tv1->tv_usec > tv2->tv_usec)
1034 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001035 else
1036 return 0;
1037}
1038
1039/*
1040 * returns the absolute difference, in ms, between tv1 and tv2
1041 */
1042unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1043 int cmp;
1044 unsigned long ret;
1045
1046
willy tarreauef900ab2005-12-17 12:52:52 +01001047 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001048 if (!cmp)
1049 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001050 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001051 struct timeval *tmp = tv1;
1052 tv1 = tv2;
1053 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001054 }
willy tarreauef900ab2005-12-17 12:52:52 +01001055 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001056 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001057 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001058 else
willy tarreauef900ab2005-12-17 12:52:52 +01001059 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001060 return (unsigned long) ret;
1061}
1062
1063/*
willy tarreau750a4722005-12-17 13:21:24 +01001064 * returns the difference, in ms, between tv1 and tv2
1065 */
1066static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1067 unsigned long ret;
1068
willy tarreau6e682ce2005-12-17 13:26:49 +01001069 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1070 if (tv2->tv_usec > tv1->tv_usec)
1071 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001072 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001073 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001074 return (unsigned long) ret;
1075}
1076
1077/*
willy tarreau0f7af912005-12-17 12:21:26 +01001078 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1079 */
1080static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001081 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001082 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001083 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001084 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1085 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001086 else
1087 return 0;
1088 }
willy tarreau0f7af912005-12-17 12:21:26 +01001089 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001090 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001091 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001092 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1093 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1094 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001095 else
1096 return 0;
1097}
1098
1099/*
1100 * returns the remaining time between tv1=now and event=tv2
1101 * if tv2 is passed, 0 is returned.
1102 */
1103static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1104 unsigned long ret;
1105
willy tarreau0f7af912005-12-17 12:21:26 +01001106 if (tv_cmp_ms(tv1, tv2) >= 0)
1107 return 0; /* event elapsed */
1108
willy tarreauef900ab2005-12-17 12:52:52 +01001109 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001110 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001111 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001112 else
willy tarreauef900ab2005-12-17 12:52:52 +01001113 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001114 return (unsigned long) ret;
1115}
1116
1117
1118/*
1119 * zeroes a struct timeval
1120 */
1121
1122static inline struct timeval *tv_eternity(struct timeval *tv) {
1123 tv->tv_sec = tv->tv_usec = 0;
1124 return tv;
1125}
1126
1127/*
1128 * returns 1 if tv is null, else 0
1129 */
1130static inline int tv_iseternity(struct timeval *tv) {
1131 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1132 return 1;
1133 else
1134 return 0;
1135}
1136
1137/*
1138 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1139 * considering that 0 is the eternity.
1140 */
1141static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1142 if (tv_iseternity(tv1))
1143 if (tv_iseternity(tv2))
1144 return 0; /* same */
1145 else
1146 return 1; /* tv1 later than tv2 */
1147 else if (tv_iseternity(tv2))
1148 return -1; /* tv2 later than tv1 */
1149
1150 if (tv1->tv_sec > tv2->tv_sec)
1151 return 1;
1152 else if (tv1->tv_sec < tv2->tv_sec)
1153 return -1;
1154 else if (tv1->tv_usec > tv2->tv_usec)
1155 return 1;
1156 else if (tv1->tv_usec < tv2->tv_usec)
1157 return -1;
1158 else
1159 return 0;
1160}
1161
1162/*
1163 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1164 * considering that 0 is the eternity.
1165 */
1166static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1167 if (tv_iseternity(tv1))
1168 if (tv_iseternity(tv2))
1169 return 0; /* same */
1170 else
1171 return 1; /* tv1 later than tv2 */
1172 else if (tv_iseternity(tv2))
1173 return -1; /* tv2 later than tv1 */
1174
willy tarreauefae1842005-12-17 12:51:03 +01001175 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001176 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001177 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001178 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001179 return -1;
1180 else
1181 return 0;
1182 }
1183 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001184 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001185 return 1;
1186 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001187 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001188 return -1;
1189 else
1190 return 0;
1191}
1192
1193/*
1194 * returns the first event between tv1 and tv2 into tvmin.
1195 * a zero tv is ignored. tvmin is returned.
1196 */
1197static inline struct timeval *tv_min(struct timeval *tvmin,
1198 struct timeval *tv1, struct timeval *tv2) {
1199
1200 if (tv_cmp2(tv1, tv2) <= 0)
1201 *tvmin = *tv1;
1202 else
1203 *tvmin = *tv2;
1204
1205 return tvmin;
1206}
1207
1208
1209
1210/***********************************************************/
1211/* fd management ***************************************/
1212/***********************************************************/
1213
1214
1215
willy tarreau5cbea6f2005-12-17 12:48:26 +01001216/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1217 * The file descriptor is also closed.
1218 */
willy tarreau0f7af912005-12-17 12:21:26 +01001219static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001220 FD_CLR(fd, StaticReadEvent);
1221 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001222 close(fd);
1223 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001224
1225 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1226 maxfd--;
1227}
1228
1229/* recomputes the maxfd limit from the fd */
1230static inline void fd_insert(int fd) {
1231 if (fd+1 > maxfd)
1232 maxfd = fd+1;
1233}
1234
1235/*************************************************************/
1236/* task management ***************************************/
1237/*************************************************************/
1238
willy tarreau5cbea6f2005-12-17 12:48:26 +01001239/* puts the task <t> in run queue <q>, and returns <t> */
1240static inline struct task *task_wakeup(struct task **q, struct task *t) {
1241 if (t->state == TASK_RUNNING)
1242 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001243 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001244 t->rqnext = *q;
1245 t->state = TASK_RUNNING;
1246 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001247 }
1248}
1249
willy tarreau5cbea6f2005-12-17 12:48:26 +01001250/* removes the task <t> from the queue <q>
1251 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001252 * set the run queue to point to the next one, and return it
1253 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001254static inline struct task *task_sleep(struct task **q, struct task *t) {
1255 if (t->state == TASK_RUNNING) {
1256 *q = t->rqnext;
1257 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001258 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001259 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001260}
1261
1262/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001263 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001264 * from the run queue. A pointer to the task itself is returned.
1265 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001266static inline struct task *task_delete(struct task *t) {
1267 t->prev->next = t->next;
1268 t->next->prev = t->prev;
1269 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001270}
1271
1272/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001273 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001274 */
1275static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001276 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001277}
1278
willy tarreau5cbea6f2005-12-17 12:48:26 +01001279/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001280 * may be only moved or left where it was, depending on its timing requirements.
1281 * <task> is returned.
1282 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001283struct task *task_queue(struct task *task) {
1284 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001285 struct task *start_from;
1286
1287 /* first, test if the task was already in a list */
1288 if (task->prev == NULL) {
1289 // start_from = list;
1290 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001291#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001292 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001293#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001294 /* insert the unlinked <task> into the list, searching back from the last entry */
1295 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1296 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001297#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001298 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001299#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001300 }
1301
1302 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1303 // start_from = start_from->next;
1304 // stats_tsk_nsrch++;
1305 // }
1306 }
1307 else if (task->prev == list ||
1308 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1309 start_from = task->next;
1310 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001311#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001312 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001313#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001314 return task; /* it's already in the right place */
1315 }
1316
willy tarreau750a4722005-12-17 13:21:24 +01001317#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001318 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001319#endif
1320
1321 /* if the task is not at the right place, there's little chance that
1322 * it has only shifted a bit, and it will nearly always be queued
1323 * at the end of the list because of constant timeouts
1324 * (observed in real case).
1325 */
1326#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1327 start_from = list->prev; /* assume we'll queue to the end of the list */
1328 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1329 start_from = start_from->prev;
1330#if STATTIME > 0
1331 stats_tsk_lsrch++;
1332#endif
1333 }
1334#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001335 /* insert the unlinked <task> into the list, searching after position <start_from> */
1336 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1337 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001338#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001339 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001340#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001341 }
willy tarreau750a4722005-12-17 13:21:24 +01001342#endif /* WE_REALLY_... */
1343
willy tarreau0f7af912005-12-17 12:21:26 +01001344 /* we need to unlink it now */
1345 task_delete(task);
1346 }
1347 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001348#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001349 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001350#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001351#ifdef LEFT_TO_TOP /* not very good */
1352 start_from = list;
1353 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1354 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001355#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001356 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001357#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001358 }
1359#else
1360 start_from = task->prev->prev; /* valid because of the previous test above */
1361 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1362 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001363#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001364 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001365#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001366 }
1367#endif
1368 /* we need to unlink it now */
1369 task_delete(task);
1370 }
1371 task->prev = start_from;
1372 task->next = start_from->next;
1373 task->next->prev = task;
1374 start_from->next = task;
1375 return task;
1376}
1377
1378
1379/*********************************************************************/
1380/* more specific functions ***************************************/
1381/*********************************************************************/
1382
1383/* some prototypes */
1384static int maintain_proxies(void);
1385
willy tarreau5cbea6f2005-12-17 12:48:26 +01001386/* this either returns the sockname or the original destination address. Code
1387 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1388 */
1389static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001390#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001391 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1392#else
willy tarreaua1598082005-12-17 13:08:06 +01001393#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001394 return getsockname(fd, (struct sockaddr *)sa, salen);
1395#else
1396 return -1;
1397#endif
1398#endif
1399}
1400
1401/*
1402 * frees the context associated to a session. It must have been removed first.
1403 */
1404static inline void session_free(struct session *s) {
1405 if (s->req)
1406 pool_free(buffer, s->req);
1407 if (s->rep)
1408 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001409 if (s->logs.uri)
1410 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001411 if (s->logs.cli_cookie)
1412 pool_free(capture, s->logs.cli_cookie);
1413 if (s->logs.srv_cookie)
1414 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001415
willy tarreau5cbea6f2005-12-17 12:48:26 +01001416 pool_free(session, s);
1417}
1418
willy tarreau0f7af912005-12-17 12:21:26 +01001419
1420/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001421 * This function tries to find a running server for the proxy <px>. A first
1422 * pass looks for active servers, and if none is found, a second pass also
1423 * looks for backup servers.
1424 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1425 */
1426static inline struct server *find_server(struct proxy *px) {
1427 struct server *srv = px->cursrv;
1428 int ignore_backup = 1;
1429
1430 do {
1431 do {
1432 if (srv == NULL)
1433 srv = px->srv;
1434 if (srv->state & SRV_RUNNING
1435 && !((srv->state & SRV_BACKUP) && ignore_backup))
1436 return srv;
1437 srv = srv->next;
1438 } while (srv != px->cursrv);
1439 } while (ignore_backup--);
1440 return NULL;
1441}
1442
1443/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001444 * This function initiates a connection to the current server (s->srv) if (s->direct)
1445 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001446 * it's OK, -1 if it's impossible.
1447 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001448int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001449 int one = 1;
1450 int fd;
1451
1452 // fprintf(stderr,"connect_server : s=%p\n",s);
1453
willy tarreaue39cd132005-12-17 13:00:18 +01001454 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001455 s->srv_addr = s->srv->addr;
1456 }
1457 else if (s->proxy->options & PR_O_BALANCE) {
1458 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001459 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001460
willy tarreau8337c6b2005-12-17 13:41:01 +01001461 srv = find_server(s->proxy);
1462
1463 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001464 return -1;
1465
willy tarreau8337c6b2005-12-17 13:41:01 +01001466 s->srv_addr = srv->addr;
1467 s->srv = srv;
1468 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001469 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001470 else /* unknown balancing algorithm */
1471 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001472 }
willy tarreaua1598082005-12-17 13:08:06 +01001473 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001474 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001475 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001476 }
1477 else if (s->proxy->options & PR_O_TRANSP) {
1478 /* in transparent mode, use the original dest addr if no dispatch specified */
1479 int salen = sizeof(struct sockaddr_in);
1480 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1481 qfprintf(stderr, "Cannot get original server address.\n");
1482 return -1;
1483 }
1484 }
willy tarreau0f7af912005-12-17 12:21:26 +01001485
willy tarreaua41a8b42005-12-17 14:02:24 +01001486 /* if this server remaps proxied ports, we'll use
1487 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001488 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001489 struct sockaddr_in sockname;
1490 int namelen;
1491
1492 namelen = sizeof(sockname);
1493 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1494 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1495 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1496 }
1497
willy tarreau0f7af912005-12-17 12:21:26 +01001498 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001499 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001500 return -1;
1501 }
1502
willy tarreau9fe663a2005-12-17 13:02:59 +01001503 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001504 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1505 close(fd);
1506 return -1;
1507 }
1508
willy tarreau0f7af912005-12-17 12:21:26 +01001509 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1510 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001511 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001512 close(fd);
1513 return -1;
1514 }
1515
willy tarreaua1598082005-12-17 13:08:06 +01001516 /* allow specific binding */
1517 if (s->proxy->options & PR_O_BIND_SRC &&
1518 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1519 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1520 close(fd);
1521 return -1;
1522 }
1523
willy tarreau0f7af912005-12-17 12:21:26 +01001524 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1525 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001526 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001527 close(fd);
1528 return -1;
1529 }
1530 else if (errno != EALREADY && errno != EISCONN) {
1531 close(fd);
1532 return -1;
1533 }
1534 }
1535
willy tarreau5cbea6f2005-12-17 12:48:26 +01001536 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001537 fdtab[fd].read = &event_srv_read;
1538 fdtab[fd].write = &event_srv_write;
1539 fdtab[fd].state = FD_STCONN; /* connection in progress */
1540
1541 FD_SET(fd, StaticWriteEvent); /* for connect status */
1542
1543 fd_insert(fd);
1544
1545 if (s->proxy->contimeout)
1546 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1547 else
1548 tv_eternity(&s->cnexpire);
1549 return 0;
1550}
1551
1552/*
1553 * this function is called on a read event from a client socket.
1554 * It returns 0.
1555 */
1556int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001557 struct task *t = fdtab[fd].owner;
1558 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001559 struct buffer *b = s->req;
1560 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001561
1562 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1563
willy tarreau0f7af912005-12-17 12:21:26 +01001564 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001565 while (1) {
1566 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1567 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001568 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001569 }
1570 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001571 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001572 }
1573 else {
1574 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001575 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1576 * since it means that the rewrite protection has been removed. This
1577 * implies that the if statement can be removed.
1578 */
1579 if (max > b->rlim - b->data)
1580 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001581 }
1582
1583 if (max == 0) { /* not anymore room to store data */
1584 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001585 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001586 }
1587
willy tarreau3242e862005-12-17 12:27:53 +01001588#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001589 {
1590 int skerr, lskerr;
1591
1592 lskerr = sizeof(skerr);
1593 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1594 if (skerr)
1595 ret = -1;
1596 else
1597 ret = recv(fd, b->r, max, 0);
1598 }
willy tarreau3242e862005-12-17 12:27:53 +01001599#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001600 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001601#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001602 if (ret > 0) {
1603 b->r += ret;
1604 b->l += ret;
1605 s->res_cr = RES_DATA;
1606
1607 if (b->r == b->data + BUFSIZE) {
1608 b->r = b->data; /* wrap around the buffer */
1609 }
willy tarreaua1598082005-12-17 13:08:06 +01001610
1611 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001612 /* we hope to read more data or to get a close on next round */
1613 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001614 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001615 else if (ret == 0) {
1616 s->res_cr = RES_NULL;
1617 break;
1618 }
1619 else if (errno == EAGAIN) {/* ignore EAGAIN */
1620 break;
1621 }
1622 else {
1623 s->res_cr = RES_ERROR;
1624 fdtab[fd].state = FD_STERROR;
1625 break;
1626 }
1627 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001628 }
1629 else {
1630 s->res_cr = RES_ERROR;
1631 fdtab[fd].state = FD_STERROR;
1632 }
1633
willy tarreau5cbea6f2005-12-17 12:48:26 +01001634 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001635 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001636 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1637 else
1638 tv_eternity(&s->crexpire);
1639
1640 task_wakeup(&rq, t);
1641 }
willy tarreau0f7af912005-12-17 12:21:26 +01001642
willy tarreau0f7af912005-12-17 12:21:26 +01001643 return 0;
1644}
1645
1646
1647/*
1648 * this function is called on a read event from a server socket.
1649 * It returns 0.
1650 */
1651int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001652 struct task *t = fdtab[fd].owner;
1653 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001654 struct buffer *b = s->rep;
1655 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001656
1657 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1658
willy tarreau0f7af912005-12-17 12:21:26 +01001659 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001660 while (1) {
1661 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1662 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001663 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001664 }
1665 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001666 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001667 }
1668 else {
1669 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001670 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1671 * since it means that the rewrite protection has been removed. This
1672 * implies that the if statement can be removed.
1673 */
1674 if (max > b->rlim - b->data)
1675 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001676 }
1677
1678 if (max == 0) { /* not anymore room to store data */
1679 FD_CLR(fd, StaticReadEvent);
1680 break;
1681 }
1682
willy tarreau3242e862005-12-17 12:27:53 +01001683#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001684 {
1685 int skerr, lskerr;
1686
1687 lskerr = sizeof(skerr);
1688 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1689 if (skerr)
1690 ret = -1;
1691 else
1692 ret = recv(fd, b->r, max, 0);
1693 }
willy tarreau3242e862005-12-17 12:27:53 +01001694#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001695 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001696#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 if (ret > 0) {
1698 b->r += ret;
1699 b->l += ret;
1700 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001701
willy tarreau5cbea6f2005-12-17 12:48:26 +01001702 if (b->r == b->data + BUFSIZE) {
1703 b->r = b->data; /* wrap around the buffer */
1704 }
willy tarreaua1598082005-12-17 13:08:06 +01001705
1706 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001707 /* we hope to read more data or to get a close on next round */
1708 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001709 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001710 else if (ret == 0) {
1711 s->res_sr = RES_NULL;
1712 break;
1713 }
1714 else if (errno == EAGAIN) {/* ignore EAGAIN */
1715 break;
1716 }
1717 else {
1718 s->res_sr = RES_ERROR;
1719 fdtab[fd].state = FD_STERROR;
1720 break;
1721 }
1722 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001723 }
1724 else {
1725 s->res_sr = RES_ERROR;
1726 fdtab[fd].state = FD_STERROR;
1727 }
1728
willy tarreau5cbea6f2005-12-17 12:48:26 +01001729 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001730 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001731 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1732 else
1733 tv_eternity(&s->srexpire);
1734
1735 task_wakeup(&rq, t);
1736 }
willy tarreau0f7af912005-12-17 12:21:26 +01001737
willy tarreau0f7af912005-12-17 12:21:26 +01001738 return 0;
1739}
1740
1741/*
1742 * this function is called on a write event from a client socket.
1743 * It returns 0.
1744 */
1745int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001746 struct task *t = fdtab[fd].owner;
1747 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001748 struct buffer *b = s->rep;
1749 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001750
1751 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1752
1753 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001754 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001755 // max = BUFSIZE; BUG !!!!
1756 max = 0;
1757 }
1758 else if (b->r > b->w) {
1759 max = b->r - b->w;
1760 }
1761 else
1762 max = b->data + BUFSIZE - b->w;
1763
willy tarreau0f7af912005-12-17 12:21:26 +01001764 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001765#ifndef MSG_NOSIGNAL
1766 int skerr, lskerr;
1767#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001768
1769 if (max == 0) {
1770 s->res_cw = RES_NULL;
1771 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001772 tv_eternity(&s->cwexpire);
1773 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001774 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001775 }
1776
willy tarreau3242e862005-12-17 12:27:53 +01001777#ifndef MSG_NOSIGNAL
1778 lskerr=sizeof(skerr);
1779 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1780 if (skerr)
1781 ret = -1;
1782 else
1783 ret = send(fd, b->w, max, MSG_DONTWAIT);
1784#else
willy tarreau0f7af912005-12-17 12:21:26 +01001785 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001786#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001787
1788 if (ret > 0) {
1789 b->l -= ret;
1790 b->w += ret;
1791
1792 s->res_cw = RES_DATA;
1793
1794 if (b->w == b->data + BUFSIZE) {
1795 b->w = b->data; /* wrap around the buffer */
1796 }
1797 }
1798 else if (ret == 0) {
1799 /* nothing written, just make as if we were never called */
1800// s->res_cw = RES_NULL;
1801 return 0;
1802 }
1803 else if (errno == EAGAIN) /* ignore EAGAIN */
1804 return 0;
1805 else {
1806 s->res_cw = RES_ERROR;
1807 fdtab[fd].state = FD_STERROR;
1808 }
1809 }
1810 else {
1811 s->res_cw = RES_ERROR;
1812 fdtab[fd].state = FD_STERROR;
1813 }
1814
willy tarreaub1ff9db2005-12-17 13:51:03 +01001815 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001816 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001817 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
1818 s->crexpire = s->cwexpire;
1819 }
willy tarreau0f7af912005-12-17 12:21:26 +01001820 else
1821 tv_eternity(&s->cwexpire);
1822
willy tarreau5cbea6f2005-12-17 12:48:26 +01001823 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001824 return 0;
1825}
1826
1827
1828/*
1829 * this function is called on a write event from a server socket.
1830 * It returns 0.
1831 */
1832int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001833 struct task *t = fdtab[fd].owner;
1834 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001835 struct buffer *b = s->req;
1836 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001837
1838 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1839
1840 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001841 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001842 // max = BUFSIZE; BUG !!!!
1843 max = 0;
1844 }
1845 else if (b->r > b->w) {
1846 max = b->r - b->w;
1847 }
1848 else
1849 max = b->data + BUFSIZE - b->w;
1850
willy tarreau0f7af912005-12-17 12:21:26 +01001851 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001852#ifndef MSG_NOSIGNAL
1853 int skerr, lskerr;
1854#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001855 if (max == 0) {
1856 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001857 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001858 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001859 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01001860 tv_eternity(&s->swexpire);
1861 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01001862 return 0;
1863 }
1864
willy tarreauef900ab2005-12-17 12:52:52 +01001865
willy tarreau3242e862005-12-17 12:27:53 +01001866#ifndef MSG_NOSIGNAL
1867 lskerr=sizeof(skerr);
1868 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1869 if (skerr)
1870 ret = -1;
1871 else
1872 ret = send(fd, b->w, max, MSG_DONTWAIT);
1873#else
willy tarreau0f7af912005-12-17 12:21:26 +01001874 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001875#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001876 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001877 if (ret > 0) {
1878 b->l -= ret;
1879 b->w += ret;
1880
1881 s->res_sw = RES_DATA;
1882
1883 if (b->w == b->data + BUFSIZE) {
1884 b->w = b->data; /* wrap around the buffer */
1885 }
1886 }
1887 else if (ret == 0) {
1888 /* nothing written, just make as if we were never called */
1889 // s->res_sw = RES_NULL;
1890 return 0;
1891 }
1892 else if (errno == EAGAIN) /* ignore EAGAIN */
1893 return 0;
1894 else {
1895 s->res_sw = RES_ERROR;
1896 fdtab[fd].state = FD_STERROR;
1897 }
1898 }
1899 else {
1900 s->res_sw = RES_ERROR;
1901 fdtab[fd].state = FD_STERROR;
1902 }
1903
willy tarreaub1ff9db2005-12-17 13:51:03 +01001904 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01001905 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001906 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
1907 s->srexpire = s->swexpire;
1908 }
willy tarreau0f7af912005-12-17 12:21:26 +01001909 else
1910 tv_eternity(&s->swexpire);
1911
willy tarreau5cbea6f2005-12-17 12:48:26 +01001912 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001913 return 0;
1914}
1915
1916
1917/*
willy tarreaue39cd132005-12-17 13:00:18 +01001918 * returns a message to the client ; the connection is shut down for read,
1919 * and the request is cleared so that no server connection can be initiated.
1920 * The client must be in a valid state for this (HEADER, DATA ...).
1921 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01001922 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001923 */
1924void client_retnclose(struct session *s, int len, const char *msg) {
1925 FD_CLR(s->cli_fd, StaticReadEvent);
1926 FD_SET(s->cli_fd, StaticWriteEvent);
1927 tv_eternity(&s->crexpire);
1928 shutdown(s->cli_fd, SHUT_RD);
1929 s->cli_state = CL_STSHUTR;
1930 strcpy(s->rep->data, msg);
1931 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001932 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001933 s->rep->r += len;
1934 s->req->l = 0;
1935}
1936
1937
1938/*
1939 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01001940 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001941 */
1942void client_return(struct session *s, int len, const char *msg) {
1943 strcpy(s->rep->data, msg);
1944 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001945 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001946 s->rep->r += len;
1947 s->req->l = 0;
1948}
1949
willy tarreau9fe663a2005-12-17 13:02:59 +01001950/*
1951 * send a log for the session when we have enough info about it
1952 */
1953void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001954 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01001955 struct proxy *p = s->proxy;
1956 int log;
1957 char *uri;
1958 char *pxid;
1959 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01001960 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01001961
1962 /* This is a first attempt at a better logging system.
1963 * For now, we rely on send_log() to provide the date, although it obviously
1964 * is the date of the log and not of the request, and most fields are not
1965 * computed.
1966 */
1967
willy tarreaua1598082005-12-17 13:08:06 +01001968 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001969
willy tarreau8a86dbf2005-12-18 00:45:59 +01001970 if (s->cli_addr.ss_family == AF_INET)
1971 inet_ntop(AF_INET,
1972 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1973 pn, sizeof(pn));
1974 else
1975 inet_ntop(AF_INET6,
1976 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
1977 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01001978
willy tarreauc1cae632005-12-17 14:12:23 +01001979 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01001980 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01001981 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01001982
willy tarreauc1cae632005-12-17 14:12:23 +01001983 tm = localtime(&s->logs.tv_accept.tv_sec);
1984 if (p->to_log & LW_REQ) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001985 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
1986 pn,
1987 (s->cli_addr.ss_family == AF_INET) ?
1988 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
1989 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01001990 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1991 tm->tm_hour, tm->tm_min, tm->tm_sec,
1992 pxid, srv,
1993 s->logs.t_request,
1994 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1995 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1996 s->logs.t_close,
1997 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001998 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1999 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002000 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2001 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2002 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2003 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua1598082005-12-17 13:08:06 +01002004 uri);
2005 }
2006 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002007 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d %lld %c%c\n",
2008 pn,
2009 (s->cli_addr.ss_family == AF_INET) ?
2010 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2011 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002012 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2013 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002014 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002015 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreaua1598082005-12-17 13:08:06 +01002016 s->logs.t_close,
willy tarreauc1cae632005-12-17 14:12:23 +01002017 s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002018 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01002019 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01002020 }
2021
2022 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002023}
2024
willy tarreaue39cd132005-12-17 13:00:18 +01002025
2026/*
willy tarreau0f7af912005-12-17 12:21:26 +01002027 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002028 * to an accept. It tries to accept as many connections as possible.
2029 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002030 */
2031int event_accept(int fd) {
2032 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002033 struct session *s;
2034 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002035 int cfd;
2036 int one = 1;
2037
willy tarreau5cbea6f2005-12-17 12:48:26 +01002038 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002039 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002040 int laddr = sizeof(addr);
2041 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2042 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002043
willy tarreau5cbea6f2005-12-17 12:48:26 +01002044 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2045 Alert("out of memory in event_accept().\n");
2046 FD_CLR(fd, StaticReadEvent);
2047 p->state = PR_STIDLE;
2048 close(cfd);
2049 return 0;
2050 }
willy tarreau0f7af912005-12-17 12:21:26 +01002051
willy tarreau5cbea6f2005-12-17 12:48:26 +01002052 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2053 Alert("out of memory in event_accept().\n");
2054 FD_CLR(fd, StaticReadEvent);
2055 p->state = PR_STIDLE;
2056 close(cfd);
2057 pool_free(session, s);
2058 return 0;
2059 }
willy tarreau0f7af912005-12-17 12:21:26 +01002060
willy tarreau5cbea6f2005-12-17 12:48:26 +01002061 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002062 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002063 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2064 close(cfd);
2065 pool_free(task, t);
2066 pool_free(session, s);
2067 return 0;
2068 }
willy tarreau0f7af912005-12-17 12:21:26 +01002069
willy tarreau5cbea6f2005-12-17 12:48:26 +01002070 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2071 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2072 (char *) &one, sizeof(one)) == -1)) {
2073 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2074 close(cfd);
2075 pool_free(task, t);
2076 pool_free(session, s);
2077 return 0;
2078 }
willy tarreau0f7af912005-12-17 12:21:26 +01002079
willy tarreau9fe663a2005-12-17 13:02:59 +01002080 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2081 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2082 t->state = TASK_IDLE;
2083 t->process = process_session;
2084 t->context = s;
2085
2086 s->task = t;
2087 s->proxy = p;
2088 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2089 s->srv_state = SV_STIDLE;
2090 s->req = s->rep = NULL; /* will be allocated later */
2091 s->flags = 0;
2092 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2093 s->cli_fd = cfd;
2094 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002095 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002096 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002097
2098 s->logs.logwait = p->to_log;
2099 s->logs.tv_accept = now;
2100 s->logs.t_request = -1;
2101 s->logs.t_connect = -1;
2102 s->logs.t_data = -1;
2103 s->logs.t_close = 0;
2104 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002105 s->logs.cli_cookie = NULL;
2106 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002107 s->logs.status = -1;
2108 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002109
willy tarreau2f6ba652005-12-17 13:57:42 +01002110 s->uniq_id = totalconn;
2111
willy tarreau5cbea6f2005-12-17 12:48:26 +01002112 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2113 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002114 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002115 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002116
willy tarreau5cbea6f2005-12-17 12:48:26 +01002117 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002118 if (addr.ss_family != AF_INET ||
2119 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002120 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002121
willy tarreau9fe663a2005-12-17 13:02:59 +01002122 if (p->to_log) {
2123 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002124 if (s->logs.logwait & LW_CLIP)
2125 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002126 sess_log(s);
2127 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002128 else if (s->cli_addr.ss_family == AF_INET) {
2129 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2130 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2131 sn, sizeof(sn)) &&
2132 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2133 pn, sizeof(pn))) {
2134 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2135 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2136 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2137 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2138 }
2139 }
2140 else {
2141 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2142 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2143 sn, sizeof(sn)) &&
2144 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2145 pn, sizeof(pn))) {
2146 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2147 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2148 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2149 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2150 }
2151 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002152 }
willy tarreau0f7af912005-12-17 12:21:26 +01002153
willy tarreau9fe663a2005-12-17 13:02:59 +01002154 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002155 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002156 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002157 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002158 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002159 if (addr.ss_family != AF_INET ||
2160 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002161 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002162
willy tarreau8a86dbf2005-12-18 00:45:59 +01002163 if (s->cli_addr.ss_family == AF_INET) {
2164 char pn[INET_ADDRSTRLEN];
2165 inet_ntop(AF_INET,
2166 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2167 pn, sizeof(pn));
2168
2169 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2170 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2171 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2172 }
2173 else {
2174 char pn[INET6_ADDRSTRLEN];
2175 inet_ntop(AF_INET6,
2176 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2177 pn, sizeof(pn));
2178
2179 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2180 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2181 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2182 }
2183
willy tarreauef900ab2005-12-17 12:52:52 +01002184 write(1, trash, len);
2185 }
willy tarreau0f7af912005-12-17 12:21:26 +01002186
willy tarreau5cbea6f2005-12-17 12:48:26 +01002187 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2188 close(cfd); /* nothing can be done for this fd without memory */
2189 pool_free(task, t);
2190 pool_free(session, s);
2191 return 0;
2192 }
2193 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002194 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002195 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2196 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002197 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002198 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002199
willy tarreau5cbea6f2005-12-17 12:48:26 +01002200 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2201 pool_free(buffer, s->req);
2202 close(cfd); /* nothing can be done for this fd without memory */
2203 pool_free(task, t);
2204 pool_free(session, s);
2205 return 0;
2206 }
2207 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002208 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002209 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 +01002210
willy tarreau5cbea6f2005-12-17 12:48:26 +01002211 fdtab[cfd].read = &event_cli_read;
2212 fdtab[cfd].write = &event_cli_write;
2213 fdtab[cfd].owner = t;
2214 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002215
willy tarreau5cbea6f2005-12-17 12:48:26 +01002216 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002217 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2218 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2219 else
2220 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002221 }
2222 else {
2223 FD_SET(cfd, StaticReadEvent);
2224 }
2225
2226 fd_insert(cfd);
2227
2228 tv_eternity(&s->cnexpire);
2229 tv_eternity(&s->srexpire);
2230 tv_eternity(&s->swexpire);
2231 tv_eternity(&s->cwexpire);
2232
2233 if (s->proxy->clitimeout)
2234 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2235 else
2236 tv_eternity(&s->crexpire);
2237
2238 t->expire = s->crexpire;
2239
2240 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002241
2242 if (p->mode != PR_MODE_HEALTH)
2243 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002244
2245 p->nbconn++;
2246 actconn++;
2247 totalconn++;
2248
2249 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2250 } /* end of while (p->nbconn < p->maxconn) */
2251 return 0;
2252}
willy tarreau0f7af912005-12-17 12:21:26 +01002253
willy tarreau0f7af912005-12-17 12:21:26 +01002254
willy tarreau5cbea6f2005-12-17 12:48:26 +01002255/*
2256 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002257 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2258 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002259 * or -1 if an error occured.
2260 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002261int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002262 struct task *t = fdtab[fd].owner;
2263 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002264
willy tarreau5cbea6f2005-12-17 12:48:26 +01002265 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002266 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002267 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002268 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002269 if (skerr)
2270 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002271 else {
2272 if (s->proxy->options & PR_O_HTTP_CHK) {
2273 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002274 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002275 * so we'll send the request, and won't wake the checker up now.
2276 */
2277#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002278 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002279#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002280 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002281#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002282 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002283 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2284 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2285 return 0;
2286 }
2287 else
2288 s->result = -1;
2289 }
2290 else {
2291 /* good TCP connection is enough */
2292 s->result = 1;
2293 }
2294 }
2295
2296 task_wakeup(&rq, t);
2297 return 0;
2298}
2299
willy tarreau0f7af912005-12-17 12:21:26 +01002300
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002301/*
2302 * This function is used only for server health-checks. It handles
2303 * the server's reply to an HTTP request. It returns 1 if the server replies
2304 * 2xx or 3xx (valid responses), or -1 in other cases.
2305 */
2306int event_srv_chk_r(int fd) {
2307 char reply[64];
2308 int len;
2309 struct task *t = fdtab[fd].owner;
2310 struct server *s = t->context;
2311
2312 int skerr, lskerr;
2313 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002314
2315 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002316#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002317 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2318 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002319 len = recv(fd, reply, sizeof(reply), 0);
2320#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002321 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2322 * but the connection was closed on the remote end. Fortunately, recv still
2323 * works correctly and we don't need to do the getsockopt() on linux.
2324 */
2325 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002326#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002327 if ((len >= sizeof("HTTP/1.0 000")) &&
2328 !memcmp(reply, "HTTP/1.", 7) &&
2329 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2330 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002331
2332 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002333 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002334 return 0;
2335}
2336
2337
2338/*
2339 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2340 * and moves <end> just after the end of <str>.
2341 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2342 * the shift value (positive or negative) is returned.
2343 * If there's no space left, the move is not done.
2344 *
2345 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002346int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002347 int delta;
2348 int len;
2349
2350 len = strlen(str);
2351 delta = len - (end - pos);
2352
2353 if (delta + b->r >= b->data + BUFSIZE)
2354 return 0; /* no space left */
2355
2356 /* first, protect the end of the buffer */
2357 memmove(end + delta, end, b->data + b->l - end);
2358
2359 /* now, copy str over pos */
2360 memcpy(pos, str,len);
2361
willy tarreau5cbea6f2005-12-17 12:48:26 +01002362 /* we only move data after the displaced zone */
2363 if (b->r > pos) b->r += delta;
2364 if (b->w > pos) b->w += delta;
2365 if (b->h > pos) b->h += delta;
2366 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002367 b->l += delta;
2368
2369 return delta;
2370}
2371
willy tarreau8337c6b2005-12-17 13:41:01 +01002372/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002373 * len is 0.
2374 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002375int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002376 int delta;
2377
2378 delta = len - (end - pos);
2379
2380 if (delta + b->r >= b->data + BUFSIZE)
2381 return 0; /* no space left */
2382
2383 /* first, protect the end of the buffer */
2384 memmove(end + delta, end, b->data + b->l - end);
2385
2386 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002387 if (len)
2388 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002389
willy tarreau5cbea6f2005-12-17 12:48:26 +01002390 /* we only move data after the displaced zone */
2391 if (b->r > pos) b->r += delta;
2392 if (b->w > pos) b->w += delta;
2393 if (b->h > pos) b->h += delta;
2394 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002395 b->l += delta;
2396
2397 return delta;
2398}
2399
2400
2401int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2402 char *old_dst = dst;
2403
2404 while (*str) {
2405 if (*str == '\\') {
2406 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002407 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002408 int len, num;
2409
2410 num = *str - '0';
2411 str++;
2412
willy tarreau8a86dbf2005-12-18 00:45:59 +01002413 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002414 len = matches[num].rm_eo - matches[num].rm_so;
2415 memcpy(dst, src + matches[num].rm_so, len);
2416 dst += len;
2417 }
2418
2419 }
2420 else if (*str == 'x') {
2421 unsigned char hex1, hex2;
2422 str++;
2423
2424 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2425
2426 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2427 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2428 *dst++ = (hex1<<4) + hex2;
2429 }
2430 else
2431 *dst++ = *str++;
2432 }
2433 else
2434 *dst++ = *str++;
2435 }
2436 *dst = 0;
2437 return dst - old_dst;
2438}
2439
willy tarreau9fe663a2005-12-17 13:02:59 +01002440
willy tarreau0f7af912005-12-17 12:21:26 +01002441/*
2442 * manages the client FSM and its socket. BTW, it also tries to handle the
2443 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2444 * 0 else.
2445 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002446int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002447 int s = t->srv_state;
2448 int c = t->cli_state;
2449 struct buffer *req = t->req;
2450 struct buffer *rep = t->rep;
2451
willy tarreau750a4722005-12-17 13:21:24 +01002452#ifdef DEBUG_FULL
2453 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2454#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002455 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2456 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2457 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2458 //);
2459 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002460 /* now parse the partial (or complete) headers */
2461 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2462 char *ptr;
2463 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002464
willy tarreau5cbea6f2005-12-17 12:48:26 +01002465 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002466
willy tarreau0f7af912005-12-17 12:21:26 +01002467 /* look for the end of the current header */
2468 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2469 ptr++;
2470
willy tarreau5cbea6f2005-12-17 12:48:26 +01002471 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002472 int line, len;
2473 /* we can only get here after an end of headers */
2474 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002475
willy tarreaue39cd132005-12-17 13:00:18 +01002476 if (t->flags & SN_CLDENY) {
2477 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002478 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002479 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002480 if (!(t->flags & SN_ERR_MASK))
2481 t->flags |= SN_ERR_PRXCOND;
2482 if (!(t->flags & SN_FINST_MASK))
2483 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002484 return 1;
2485 }
2486
willy tarreau5cbea6f2005-12-17 12:48:26 +01002487 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002488 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2489 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002490 }
willy tarreau0f7af912005-12-17 12:21:26 +01002491
willy tarreau9fe663a2005-12-17 13:02:59 +01002492 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002493 if (t->cli_addr.ss_family == AF_INET) {
2494 unsigned char *pn;
2495 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
2496 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2497 pn[0], pn[1], pn[2], pn[3]);
2498 buffer_replace2(req, req->h, req->h, trash, len);
2499 }
2500 else if (t->cli_addr.ss_family == AF_INET6) {
2501 char pn[INET6_ADDRSTRLEN];
2502 inet_ntop(AF_INET6,
2503 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2504 pn, sizeof(pn));
2505 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
2506 buffer_replace2(req, req->h, req->h, trash, len);
2507 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002508 }
2509
willy tarreaucd878942005-12-17 13:27:43 +01002510 if (!memcmp(req->data, "POST ", 5))
2511 t->flags |= SN_POST; /* this is a POST request */
2512
willy tarreau5cbea6f2005-12-17 12:48:26 +01002513 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002514 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002515
willy tarreau750a4722005-12-17 13:21:24 +01002516 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002517 /* FIXME: we'll set the client in a wait state while we try to
2518 * connect to the server. Is this really needed ? wouldn't it be
2519 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002520 //FD_CLR(t->cli_fd, StaticReadEvent);
2521 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002522
2523 /* FIXME: if we break here (as up to 1.1.23), having the client
2524 * shutdown its connection can lead to an abort further.
2525 * it's better to either return 1 or even jump directly to the
2526 * data state which will save one schedule.
2527 */
2528 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002529
2530 if (!t->proxy->clitimeout ||
2531 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2532 /* If the client has no timeout, or if the server is not ready yet,
2533 * and we know for sure that it can expire, then it's cleaner to
2534 * disable the timeout on the client side so that too low values
2535 * cannot make the sessions abort too early.
2536 */
2537 tv_eternity(&t->crexpire);
2538
willy tarreau197e8ec2005-12-17 14:10:59 +01002539 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002540 }
willy tarreau0f7af912005-12-17 12:21:26 +01002541
willy tarreau5cbea6f2005-12-17 12:48:26 +01002542 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2543 if (ptr > req->r - 2) {
2544 /* this is a partial header, let's wait for more to come */
2545 req->lr = ptr;
2546 break;
2547 }
willy tarreau0f7af912005-12-17 12:21:26 +01002548
willy tarreau5cbea6f2005-12-17 12:48:26 +01002549 /* now we know that *ptr is either \r or \n,
2550 * and that there are at least 1 char after it.
2551 */
2552 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2553 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2554 else
2555 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002556
willy tarreau5cbea6f2005-12-17 12:48:26 +01002557 /*
2558 * now we know that we have a full header ; we can do whatever
2559 * we want with these pointers :
2560 * req->h = beginning of header
2561 * ptr = end of header (first \r or \n)
2562 * req->lr = beginning of next line (next rep->h)
2563 * req->r = end of data (not used at this stage)
2564 */
willy tarreau0f7af912005-12-17 12:21:26 +01002565
willy tarreau8337c6b2005-12-17 13:41:01 +01002566 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002567 /* we have a complete HTTP request that we must log */
2568 int urilen;
2569
willy tarreaua1598082005-12-17 13:08:06 +01002570 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002571 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002572 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002573 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002574 if (!(t->flags & SN_ERR_MASK))
2575 t->flags |= SN_ERR_PRXCOND;
2576 if (!(t->flags & SN_FINST_MASK))
2577 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002578 return 1;
2579 }
2580
2581 urilen = ptr - req->h;
2582 if (urilen >= REQURI_LEN)
2583 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002584 memcpy(t->logs.uri, req->h, urilen);
2585 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002586
willy tarreaua1598082005-12-17 13:08:06 +01002587 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002588 sess_log(t);
2589 }
2590
willy tarreau5cbea6f2005-12-17 12:48:26 +01002591 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002592
willy tarreau9fe663a2005-12-17 13:02:59 +01002593 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002595 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 +01002596 max = ptr - req->h;
2597 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002598 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002599 trash[len++] = '\n';
2600 write(1, trash, len);
2601 }
willy tarreau0f7af912005-12-17 12:21:26 +01002602
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002604 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2605 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002606 char term;
2607
2608 term = *ptr;
2609 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002610 exp = t->proxy->req_exp;
2611 do {
2612 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2613 switch (exp->action) {
2614 case ACT_ALLOW:
2615 if (!(t->flags & SN_CLDENY))
2616 t->flags |= SN_CLALLOW;
2617 break;
2618 case ACT_REPLACE:
2619 if (!(t->flags & SN_CLDENY)) {
2620 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2621 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2622 }
2623 break;
2624 case ACT_REMOVE:
2625 if (!(t->flags & SN_CLDENY))
2626 delete_header = 1;
2627 break;
2628 case ACT_DENY:
2629 if (!(t->flags & SN_CLALLOW))
2630 t->flags |= SN_CLDENY;
2631 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01002632 case ACT_PASS: /* we simply don't deny this one */
2633 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002634 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002635 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002636 }
willy tarreaue39cd132005-12-17 13:00:18 +01002637 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002638 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002639 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640
willy tarreau240afa62005-12-17 13:14:35 +01002641 /* Now look for cookies. Conforming to RFC2109, we have to support
2642 * attributes whose name begin with a '$', and associate them with
2643 * the right cookie, if we want to delete this cookie.
2644 * So there are 3 cases for each cookie read :
2645 * 1) it's a special attribute, beginning with a '$' : ignore it.
2646 * 2) it's a server id cookie that we *MAY* want to delete : save
2647 * some pointers on it (last semi-colon, beginning of cookie...)
2648 * 3) it's an application cookie : we *MAY* have to delete a previous
2649 * "special" cookie.
2650 * At the end of loop, if a "special" cookie remains, we may have to
2651 * remove it. If no application cookie persists in the header, we
2652 * *MUST* delete it
2653 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002654 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002655 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01002656 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002657 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002658 char *del_colon, *del_cookie, *colon;
2659 int app_cookies;
2660
willy tarreau5cbea6f2005-12-17 12:48:26 +01002661 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002662 colon = p1;
2663 /* del_cookie == NULL => nothing to be deleted */
2664 del_colon = del_cookie = NULL;
2665 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002666
2667 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002668 /* skip spaces and colons, but keep an eye on these ones */
2669 while (p1 < ptr) {
2670 if (*p1 == ';' || *p1 == ',')
2671 colon = p1;
2672 else if (!isspace((int)*p1))
2673 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002674 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002675 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002676
2677 if (p1 == ptr)
2678 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002679
2680 /* p1 is at the beginning of the cookie name */
2681 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002682 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002683 p2++;
2684
2685 if (p2 == ptr)
2686 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002687
2688 p3 = p2 + 1; /* skips the '=' sign */
2689 if (p3 == ptr)
2690 break;
2691
willy tarreau240afa62005-12-17 13:14:35 +01002692 p4 = p3;
2693 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002694 p4++;
2695
2696 /* here, we have the cookie name between p1 and p2,
2697 * and its value between p3 and p4.
2698 * we can process it.
2699 */
2700
willy tarreau240afa62005-12-17 13:14:35 +01002701 if (*p1 == '$') {
2702 /* skip this one */
2703 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002704 else {
2705 /* first, let's see if we want to capture it */
2706 if (t->proxy->capture_name != NULL &&
2707 t->logs.cli_cookie == NULL &&
2708 (p4 - p1 >= t->proxy->capture_namelen) &&
2709 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2710 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711
willy tarreau8337c6b2005-12-17 13:41:01 +01002712 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2713 Alert("HTTP logging : out of memory.\n");
2714 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002715
willy tarreau8337c6b2005-12-17 13:41:01 +01002716 if (log_len > t->proxy->capture_len)
2717 log_len = t->proxy->capture_len;
2718 memcpy(t->logs.cli_cookie, p1, log_len);
2719 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002720 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002721
2722 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2723 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2724 /* Cool... it's the right one */
2725 struct server *srv = t->proxy->srv;
2726
2727 while (srv &&
2728 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2729 srv = srv->next;
2730 }
2731
willy tarreau036e1ce2005-12-17 13:46:33 +01002732 if (!srv) {
2733 t->flags &= ~SN_CK_MASK;
2734 t->flags |= SN_CK_INVALID;
2735 }
2736 else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002737 /* we found the server and it's usable */
willy tarreau036e1ce2005-12-17 13:46:33 +01002738 t->flags &= ~SN_CK_MASK;
2739 t->flags |= SN_CK_VALID | SN_DIRECT;
willy tarreau8337c6b2005-12-17 13:41:01 +01002740 t->srv = srv;
2741 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002742 else {
2743 t->flags &= ~SN_CK_MASK;
2744 t->flags |= SN_CK_DOWN;
2745 }
2746
willy tarreau8337c6b2005-12-17 13:41:01 +01002747 /* if this cookie was set in insert+indirect mode, then it's better that the
2748 * server never sees it.
2749 */
2750 if (del_cookie == NULL &&
2751 (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 +01002752 del_cookie = p1;
2753 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002754 }
willy tarreau240afa62005-12-17 13:14:35 +01002755 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002756 else {
2757 /* now we know that we must keep this cookie since it's
2758 * not ours. But if we wanted to delete our cookie
2759 * earlier, we cannot remove the complete header, but we
2760 * can remove the previous block itself.
2761 */
2762 app_cookies++;
2763
2764 if (del_cookie != NULL) {
2765 buffer_replace2(req, del_cookie, p1, NULL, 0);
2766 p4 -= (p1 - del_cookie);
2767 ptr -= (p1 - del_cookie);
2768 del_cookie = del_colon = NULL;
2769 }
willy tarreau240afa62005-12-17 13:14:35 +01002770 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002771 }
willy tarreau240afa62005-12-17 13:14:35 +01002772
willy tarreau5cbea6f2005-12-17 12:48:26 +01002773 /* we'll have to look for another cookie ... */
2774 p1 = p4;
2775 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002776
2777 /* There's no more cookie on this line.
2778 * We may have marked the last one(s) for deletion.
2779 * We must do this now in two ways :
2780 * - if there is no app cookie, we simply delete the header ;
2781 * - if there are app cookies, we must delete the end of the
2782 * string properly, including the colon/semi-colon before
2783 * the cookie name.
2784 */
2785 if (del_cookie != NULL) {
2786 if (app_cookies) {
2787 buffer_replace2(req, del_colon, ptr, NULL, 0);
2788 /* WARNING! <ptr> becomes invalid for now. If some code
2789 * below needs to rely on it before the end of the global
2790 * header loop, we need to correct it with this code :
2791 * ptr = del_colon;
2792 */
2793 }
2794 else
2795 delete_header = 1;
2796 }
2797 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002798
2799 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002800 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002801 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002802 }
willy tarreau240afa62005-12-17 13:14:35 +01002803 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2804
willy tarreau5cbea6f2005-12-17 12:48:26 +01002805 req->h = req->lr;
2806 } /* while (req->lr < req->r) */
2807
2808 /* end of header processing (even if incomplete) */
2809
willy tarreauef900ab2005-12-17 12:52:52 +01002810 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2811 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2812 * full. We cannot loop here since event_cli_read will disable it only if
2813 * req->l == rlim-data
2814 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002815 FD_SET(t->cli_fd, StaticReadEvent);
2816 if (t->proxy->clitimeout)
2817 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2818 else
2819 tv_eternity(&t->crexpire);
2820 }
2821
willy tarreaue39cd132005-12-17 13:00:18 +01002822 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002823 * won't be able to free more later, so the session will never terminate.
2824 */
willy tarreaue39cd132005-12-17 13:00:18 +01002825 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002826 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01002827 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01002828 if (!(t->flags & SN_ERR_MASK))
2829 t->flags |= SN_ERR_PRXCOND;
2830 if (!(t->flags & SN_FINST_MASK))
2831 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002832 return 1;
2833 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002834 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002835 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002836 tv_eternity(&t->crexpire);
2837 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002838 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002839 if (!(t->flags & SN_ERR_MASK))
2840 t->flags |= SN_ERR_CLICL;
2841 if (!(t->flags & SN_FINST_MASK))
2842 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002843 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002844 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002845 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2846
2847 /* read timeout : give up with an error message.
2848 */
2849 t->logs.status = 408;
2850 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01002851 if (!(t->flags & SN_ERR_MASK))
2852 t->flags |= SN_ERR_CLITO;
2853 if (!(t->flags & SN_FINST_MASK))
2854 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01002855 return 1;
2856 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002857
2858 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002859 }
2860 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01002861 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01002862 /* FIXME: this error handling is partly buggy because we always report
2863 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2864 * or HEADER phase. BTW, it's not logical to expire the client while
2865 * we're waiting for the server to connect.
2866 */
willy tarreau0f7af912005-12-17 12:21:26 +01002867 /* read or write error */
2868 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002869 tv_eternity(&t->crexpire);
2870 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002871 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002872 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01002873 if (!(t->flags & SN_ERR_MASK))
2874 t->flags |= SN_ERR_CLICL;
2875 if (!(t->flags & SN_FINST_MASK))
2876 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01002877 return 1;
2878 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002879 /* last read, or end of server write */
2880 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002881 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002882 tv_eternity(&t->crexpire);
2883 shutdown(t->cli_fd, SHUT_RD);
2884 t->cli_state = CL_STSHUTR;
2885 return 1;
2886 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002887 /* last server read and buffer empty */
2888 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002889 FD_CLR(t->cli_fd, StaticWriteEvent);
2890 tv_eternity(&t->cwexpire);
2891 shutdown(t->cli_fd, SHUT_WR);
2892 t->cli_state = CL_STSHUTW;
2893 return 1;
2894 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002895 /* read timeout */
2896 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2897 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01002898 tv_eternity(&t->crexpire);
2899 shutdown(t->cli_fd, SHUT_RD);
2900 t->cli_state = CL_STSHUTR;
2901 if (!(t->flags & SN_ERR_MASK))
2902 t->flags |= SN_ERR_CLITO;
2903 if (!(t->flags & SN_FINST_MASK))
2904 t->flags |= SN_FINST_D;
2905 return 1;
2906 }
2907 /* write timeout */
2908 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2909 FD_CLR(t->cli_fd, StaticWriteEvent);
2910 tv_eternity(&t->cwexpire);
2911 shutdown(t->cli_fd, SHUT_WR);
2912 t->cli_state = CL_STSHUTW;
2913 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01002914 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01002915 if (!(t->flags & SN_FINST_MASK))
2916 t->flags |= SN_FINST_D;
2917 return 1;
2918 }
willy tarreau0f7af912005-12-17 12:21:26 +01002919
willy tarreauc58fc692005-12-17 14:13:08 +01002920 if (req->l >= req->rlim - req->data) {
2921 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002922 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002923 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002924 FD_CLR(t->cli_fd, StaticReadEvent);
2925 tv_eternity(&t->crexpire);
2926 }
2927 }
2928 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002929 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002930 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2931 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01002932 if (!t->proxy->clitimeout ||
2933 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2934 /* If the client has no timeout, or if the server not ready yet, and we
2935 * know for sure that it can expire, then it's cleaner to disable the
2936 * timeout on the client side so that too low values cannot make the
2937 * sessions abort too early.
2938 */
willy tarreau0f7af912005-12-17 12:21:26 +01002939 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01002940 else
2941 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01002942 }
2943 }
2944
2945 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01002946 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002947 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2948 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2949 tv_eternity(&t->cwexpire);
2950 }
2951 }
2952 else { /* buffer not empty */
2953 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2954 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002955 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002956 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002957 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2958 t->crexpire = t->cwexpire;
2959 }
willy tarreau0f7af912005-12-17 12:21:26 +01002960 else
2961 tv_eternity(&t->cwexpire);
2962 }
2963 }
2964 return 0; /* other cases change nothing */
2965 }
2966 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01002967 if (t->res_cw == RES_ERROR) {
2968 tv_eternity(&t->cwexpire);
2969 fd_delete(t->cli_fd);
2970 t->cli_state = CL_STCLOSE;
2971 if (!(t->flags & SN_ERR_MASK))
2972 t->flags |= SN_ERR_CLICL;
2973 if (!(t->flags & SN_FINST_MASK))
2974 t->flags |= SN_FINST_D;
2975 return 1;
2976 }
2977 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002978 tv_eternity(&t->cwexpire);
2979 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002980 t->cli_state = CL_STCLOSE;
2981 return 1;
2982 }
willy tarreau036e1ce2005-12-17 13:46:33 +01002983 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
2984 tv_eternity(&t->cwexpire);
2985 fd_delete(t->cli_fd);
2986 t->cli_state = CL_STCLOSE;
2987 if (!(t->flags & SN_ERR_MASK))
2988 t->flags |= SN_ERR_CLITO;
2989 if (!(t->flags & SN_FINST_MASK))
2990 t->flags |= SN_FINST_D;
2991 return 1;
2992 }
willy tarreau0f7af912005-12-17 12:21:26 +01002993 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002994 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002995 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2996 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2997 tv_eternity(&t->cwexpire);
2998 }
2999 }
3000 else { /* buffer not empty */
3001 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3002 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003003 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003004 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003005 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3006 t->crexpire = t->cwexpire;
3007 }
willy tarreau0f7af912005-12-17 12:21:26 +01003008 else
3009 tv_eternity(&t->cwexpire);
3010 }
3011 }
3012 return 0;
3013 }
3014 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003015 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003016 tv_eternity(&t->crexpire);
3017 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003018 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003019 if (!(t->flags & SN_ERR_MASK))
3020 t->flags |= SN_ERR_CLICL;
3021 if (!(t->flags & SN_FINST_MASK))
3022 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003023 return 1;
3024 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003025 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3026 tv_eternity(&t->crexpire);
3027 fd_delete(t->cli_fd);
3028 t->cli_state = CL_STCLOSE;
3029 return 1;
3030 }
3031 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3032 tv_eternity(&t->crexpire);
3033 fd_delete(t->cli_fd);
3034 t->cli_state = CL_STCLOSE;
3035 if (!(t->flags & SN_ERR_MASK))
3036 t->flags |= SN_ERR_CLITO;
3037 if (!(t->flags & SN_FINST_MASK))
3038 t->flags |= SN_FINST_D;
3039 return 1;
3040 }
willy tarreauef900ab2005-12-17 12:52:52 +01003041 else if (req->l >= req->rlim - req->data) {
3042 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003043 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003044 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003045 FD_CLR(t->cli_fd, StaticReadEvent);
3046 tv_eternity(&t->crexpire);
3047 }
3048 }
3049 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003050 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003051 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3052 FD_SET(t->cli_fd, StaticReadEvent);
3053 if (t->proxy->clitimeout)
3054 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3055 else
3056 tv_eternity(&t->crexpire);
3057 }
3058 }
3059 return 0;
3060 }
3061 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003062 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003063 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003064 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 +01003065 write(1, trash, len);
3066 }
3067 return 0;
3068 }
3069 return 0;
3070}
3071
3072
3073/*
3074 * manages the server FSM and its socket. It returns 1 if a state has changed
3075 * (and a resync may be needed), 0 else.
3076 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003077int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003078 int s = t->srv_state;
3079 int c = t->cli_state;
3080 struct buffer *req = t->req;
3081 struct buffer *rep = t->rep;
3082
willy tarreau750a4722005-12-17 13:21:24 +01003083#ifdef DEBUG_FULL
3084 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3085#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003086 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3087 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3088 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3089 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003090 if (s == SV_STIDLE) {
3091 if (c == CL_STHEADERS)
3092 return 0; /* stay in idle, waiting for data to reach the client side */
3093 else if (c == CL_STCLOSE ||
3094 c == CL_STSHUTW ||
3095 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3096 tv_eternity(&t->cnexpire);
3097 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003098 if (!(t->flags & SN_ERR_MASK))
3099 t->flags |= SN_ERR_CLICL;
3100 if (!(t->flags & SN_FINST_MASK))
3101 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003102 return 1;
3103 }
3104 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003106 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3107 t->srv_state = SV_STCONN;
3108 }
3109 else { /* try again */
3110 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003111 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003112 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003113 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003114 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3115 t->flags &= ~SN_CK_MASK;
3116 t->flags |= SN_CK_DOWN;
3117 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003118 }
3119
3120 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003121 t->srv_state = SV_STCONN;
3122 break;
3123 }
3124 }
3125 if (t->conn_retries < 0) {
3126 /* if conn_retries < 0 or other error, let's abort */
3127 tv_eternity(&t->cnexpire);
3128 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003129 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003130 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003131 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003132 if (!(t->flags & SN_ERR_MASK))
3133 t->flags |= SN_ERR_SRVCL;
3134 if (!(t->flags & SN_FINST_MASK))
3135 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003136 }
3137 }
3138 return 1;
3139 }
3140 }
3141 else if (s == SV_STCONN) { /* connection in progress */
3142 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3143 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3144 return 0; /* nothing changed */
3145 }
3146 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3147 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3148 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003149 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003150 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003151 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003152 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003153 if (t->conn_retries >= 0) {
3154 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003155 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003156 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003157 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3158 t->flags &= ~SN_CK_MASK;
3159 t->flags |= SN_CK_DOWN;
3160 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003161 }
3162 if (connect_server(t) == 0)
3163 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003164 }
3165 /* if conn_retries < 0 or other error, let's abort */
3166 tv_eternity(&t->cnexpire);
3167 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003168 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003169 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003170 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003171 if (!(t->flags & SN_ERR_MASK))
3172 t->flags |= SN_ERR_SRVCL;
3173 if (!(t->flags & SN_FINST_MASK))
3174 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003175 return 1;
3176 }
3177 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003178 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003179
willy tarreau0f7af912005-12-17 12:21:26 +01003180 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003181 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003182 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003183 tv_eternity(&t->swexpire);
3184 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003185 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003186 if (t->proxy->srvtimeout) {
3187 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3188 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3189 t->srexpire = t->swexpire;
3190 }
3191 else
3192 tv_eternity(&t->swexpire);
3193 }
willy tarreau0f7af912005-12-17 12:21:26 +01003194
3195 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3196 FD_SET(t->srv_fd, StaticReadEvent);
3197 if (t->proxy->srvtimeout)
3198 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3199 else
3200 tv_eternity(&t->srexpire);
3201
3202 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003203 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003204 }
willy tarreauef900ab2005-12-17 12:52:52 +01003205 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003206 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003207 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3208 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003209 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003210 return 1;
3211 }
3212 }
3213 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003214 /* now parse the partial (or complete) headers */
3215 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3216 char *ptr;
3217 int delete_header;
3218
3219 ptr = rep->lr;
3220
3221 /* look for the end of the current header */
3222 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3223 ptr++;
3224
3225 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003226 int line, len;
3227
3228 /* we can only get here after an end of headers */
3229 /* we'll have something else to do here : add new headers ... */
3230
willy tarreaucd878942005-12-17 13:27:43 +01003231 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3232 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003233 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003234 * insert a set-cookie here, except if we want to insert only on POST
3235 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003236 */
willy tarreau750a4722005-12-17 13:21:24 +01003237 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003238 t->proxy->cookie_name,
3239 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003240
willy tarreau036e1ce2005-12-17 13:46:33 +01003241 t->flags |= SN_SCK_INSERTED;
3242
willy tarreau750a4722005-12-17 13:21:24 +01003243 /* Here, we will tell an eventual cache on the client side that we don't
3244 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3245 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3246 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3247 */
willy tarreau240afa62005-12-17 13:14:35 +01003248 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003249 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3250 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003251
willy tarreau750a4722005-12-17 13:21:24 +01003252 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003253 }
3254
3255 /* headers to be added */
3256 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003257 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3258 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003259 }
3260
3261 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003262 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003263 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003264 break;
3265 }
3266
3267 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3268 if (ptr > rep->r - 2) {
3269 /* this is a partial header, let's wait for more to come */
3270 rep->lr = ptr;
3271 break;
3272 }
3273
3274 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3275 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3276
3277 /* now we know that *ptr is either \r or \n,
3278 * and that there are at least 1 char after it.
3279 */
3280 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3281 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3282 else
3283 rep->lr = ptr + 2; /* \r\n or \n\r */
3284
3285 /*
3286 * now we know that we have a full header ; we can do whatever
3287 * we want with these pointers :
3288 * rep->h = beginning of header
3289 * ptr = end of header (first \r or \n)
3290 * rep->lr = beginning of next line (next rep->h)
3291 * rep->r = end of data (not used at this stage)
3292 */
3293
willy tarreaua1598082005-12-17 13:08:06 +01003294
3295 if (t->logs.logwait & LW_RESP) {
3296 t->logs.logwait &= ~LW_RESP;
3297 t->logs.status = atoi(rep->h + 9);
3298 }
3299
willy tarreau5cbea6f2005-12-17 12:48:26 +01003300 delete_header = 0;
3301
willy tarreau9fe663a2005-12-17 13:02:59 +01003302 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003303 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003304 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 +01003305 max = ptr - rep->h;
3306 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003307 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003308 trash[len++] = '\n';
3309 write(1, trash, len);
3310 }
3311
3312 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01003313 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
3314 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003315 char term;
3316
3317 term = *ptr;
3318 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003319 exp = t->proxy->rsp_exp;
3320 do {
3321 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3322 switch (exp->action) {
3323 case ACT_ALLOW:
3324 if (!(t->flags & SN_SVDENY))
3325 t->flags |= SN_SVALLOW;
3326 break;
3327 case ACT_REPLACE:
3328 if (!(t->flags & SN_SVDENY)) {
3329 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3330 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3331 }
3332 break;
3333 case ACT_REMOVE:
3334 if (!(t->flags & SN_SVDENY))
3335 delete_header = 1;
3336 break;
3337 case ACT_DENY:
3338 if (!(t->flags & SN_SVALLOW))
3339 t->flags |= SN_SVDENY;
3340 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003341 case ACT_PASS: /* we simply don't deny this one */
3342 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003343 }
3344 break;
3345 }
willy tarreaue39cd132005-12-17 13:00:18 +01003346 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003347 *ptr = term; /* restore the string terminator */
3348 }
3349
3350 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003351 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3352 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
3353 && (ptr >= rep->h + 12)
willy tarreau906b2682005-12-17 13:49:52 +01003354 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003355 char *p1, *p2, *p3, *p4;
3356
3357 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3358
3359 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003360 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003361 p1++;
3362
3363 if (p1 == ptr || *p1 == ';') /* end of cookie */
3364 break;
3365
3366 /* p1 is at the beginning of the cookie name */
3367 p2 = p1;
3368
3369 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3370 p2++;
3371
3372 if (p2 == ptr || *p2 == ';') /* next cookie */
3373 break;
3374
3375 p3 = p2 + 1; /* skips the '=' sign */
3376 if (p3 == ptr)
3377 break;
3378
3379 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003380 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003381 p4++;
3382
3383 /* here, we have the cookie name between p1 and p2,
3384 * and its value between p3 and p4.
3385 * we can process it.
3386 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003387
3388 /* first, let's see if we want to capture it */
3389 if (t->proxy->capture_name != NULL &&
3390 t->logs.srv_cookie == NULL &&
3391 (p4 - p1 >= t->proxy->capture_namelen) &&
3392 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3393 int log_len = p4 - p1;
3394
3395 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3396 Alert("HTTP logging : out of memory.\n");
3397 }
3398
3399 if (log_len > t->proxy->capture_len)
3400 log_len = t->proxy->capture_len;
3401 memcpy(t->logs.srv_cookie, p1, log_len);
3402 t->logs.srv_cookie[log_len] = 0;
3403 }
3404
3405 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3406 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003407 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01003408 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003409
3410 /* If the cookie is in insert mode on a known server, we'll delete
3411 * this occurrence because we'll insert another one later.
3412 * We'll delete it too if the "indirect" option is set and we're in
3413 * a direct access. */
3414 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003415 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003416 /* this header must be deleted */
3417 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01003418 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003419 }
3420 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3421 /* replace bytes p3->p4 with the cookie name associated
3422 * with this server since we know it.
3423 */
3424 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01003425 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003426 }
3427 break;
3428 }
3429 else {
3430 // fprintf(stderr,"Ignoring unknown cookie : ");
3431 // write(2, p1, p2-p1);
3432 // fprintf(stderr," = ");
3433 // write(2, p3, p4-p3);
3434 // fprintf(stderr,"\n");
3435 }
3436 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3437 } /* we're now at the end of the cookie value */
3438 } /* end of cookie processing */
3439
3440 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003441 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003442 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003443
willy tarreau5cbea6f2005-12-17 12:48:26 +01003444 rep->h = rep->lr;
3445 } /* while (rep->lr < rep->r) */
3446
3447 /* end of header processing (even if incomplete) */
3448
willy tarreauef900ab2005-12-17 12:52:52 +01003449 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3450 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3451 * full. We cannot loop here since event_srv_read will disable it only if
3452 * rep->l == rlim-data
3453 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003454 FD_SET(t->srv_fd, StaticReadEvent);
3455 if (t->proxy->srvtimeout)
3456 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3457 else
3458 tv_eternity(&t->srexpire);
3459 }
willy tarreau0f7af912005-12-17 12:21:26 +01003460
willy tarreau8337c6b2005-12-17 13:41:01 +01003461 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003462 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003463 tv_eternity(&t->srexpire);
3464 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003465 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003466 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003467 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003468 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01003469 if (!(t->flags & SN_ERR_MASK))
3470 t->flags |= SN_ERR_SRVCL;
3471 if (!(t->flags & SN_FINST_MASK))
3472 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01003473 return 1;
3474 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003475 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003476 * since we are in header mode, if there's no space left for headers, we
3477 * won't be able to free more later, so the session will never terminate.
3478 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003479 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 +01003480 FD_CLR(t->srv_fd, StaticReadEvent);
3481 tv_eternity(&t->srexpire);
3482 shutdown(t->srv_fd, SHUT_RD);
3483 t->srv_state = SV_STSHUTR;
3484 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003485 }
3486 /* read timeout : return a 504 to the client.
3487 */
3488 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3489 tv_eternity(&t->srexpire);
3490 tv_eternity(&t->swexpire);
3491 fd_delete(t->srv_fd);
3492 t->srv_state = SV_STCLOSE;
3493 t->logs.status = 504;
3494 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01003495 if (!(t->flags & SN_ERR_MASK))
3496 t->flags |= SN_ERR_SRVTO;
3497 if (!(t->flags & SN_FINST_MASK))
3498 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01003499 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003500
3501 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003502 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003503 /* FIXME!!! here, we don't want to switch to SHUTW if the
3504 * client shuts read too early, because we may still have
3505 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01003506 * The side-effect is that if the client completely closes its
3507 * connection during SV_STHEADER, the connection to the server
3508 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01003509 */
willy tarreau036e1ce2005-12-17 13:46:33 +01003510 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003511 FD_CLR(t->srv_fd, StaticWriteEvent);
3512 tv_eternity(&t->swexpire);
3513 shutdown(t->srv_fd, SHUT_WR);
3514 t->srv_state = SV_STSHUTW;
3515 return 1;
3516 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003517 /* write timeout */
3518 /* FIXME!!! here, we don't want to switch to SHUTW if the
3519 * client shuts read too early, because we may still have
3520 * some work to do on the headers.
3521 */
3522 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3523 FD_CLR(t->srv_fd, StaticWriteEvent);
3524 tv_eternity(&t->swexpire);
3525 shutdown(t->srv_fd, SHUT_WR);
3526 t->srv_state = SV_STSHUTW;
3527 if (!(t->flags & SN_ERR_MASK))
3528 t->flags |= SN_ERR_SRVTO;
3529 if (!(t->flags & SN_FINST_MASK))
3530 t->flags |= SN_FINST_H;
3531 return 1;
3532 }
willy tarreau0f7af912005-12-17 12:21:26 +01003533
3534 if (req->l == 0) {
3535 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3536 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3537 tv_eternity(&t->swexpire);
3538 }
3539 }
3540 else { /* client buffer not empty */
3541 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3542 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003543 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003544 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003545 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3546 t->srexpire = t->swexpire;
3547 }
willy tarreau0f7af912005-12-17 12:21:26 +01003548 else
3549 tv_eternity(&t->swexpire);
3550 }
3551 }
3552
willy tarreau5cbea6f2005-12-17 12:48:26 +01003553 /* be nice with the client side which would like to send a complete header
3554 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3555 * would read all remaining data at once ! The client should not write past rep->lr
3556 * when the server is in header state.
3557 */
3558 //return header_processed;
3559 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003560 }
3561 else if (s == SV_STDATA) {
3562 /* read or write error */
3563 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003564 tv_eternity(&t->srexpire);
3565 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003566 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003567 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003568 if (!(t->flags & SN_ERR_MASK))
3569 t->flags |= SN_ERR_SRVCL;
3570 if (!(t->flags & SN_FINST_MASK))
3571 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003572 return 1;
3573 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003574 /* last read, or end of client write */
3575 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003576 FD_CLR(t->srv_fd, StaticReadEvent);
3577 tv_eternity(&t->srexpire);
3578 shutdown(t->srv_fd, SHUT_RD);
3579 t->srv_state = SV_STSHUTR;
3580 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01003581 }
3582 /* end of client read and no more data to send */
3583 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
3584 FD_CLR(t->srv_fd, StaticWriteEvent);
3585 tv_eternity(&t->swexpire);
3586 shutdown(t->srv_fd, SHUT_WR);
3587 t->srv_state = SV_STSHUTW;
3588 return 1;
3589 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003590 /* read timeout */
3591 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3592 FD_CLR(t->srv_fd, StaticReadEvent);
3593 tv_eternity(&t->srexpire);
3594 shutdown(t->srv_fd, SHUT_RD);
3595 t->srv_state = SV_STSHUTR;
3596 if (!(t->flags & SN_ERR_MASK))
3597 t->flags |= SN_ERR_SRVTO;
3598 if (!(t->flags & SN_FINST_MASK))
3599 t->flags |= SN_FINST_D;
3600 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003601 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003602 /* write timeout */
3603 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003604 FD_CLR(t->srv_fd, StaticWriteEvent);
3605 tv_eternity(&t->swexpire);
3606 shutdown(t->srv_fd, SHUT_WR);
3607 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01003608 if (!(t->flags & SN_ERR_MASK))
3609 t->flags |= SN_ERR_SRVTO;
3610 if (!(t->flags & SN_FINST_MASK))
3611 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003612 return 1;
3613 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003614
3615 /* recompute request time-outs */
3616 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003617 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3618 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3619 tv_eternity(&t->swexpire);
3620 }
3621 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01003622 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01003623 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3624 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003625 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003626 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003627 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3628 t->srexpire = t->swexpire;
3629 }
willy tarreau0f7af912005-12-17 12:21:26 +01003630 else
3631 tv_eternity(&t->swexpire);
3632 }
3633 }
3634
willy tarreaub1ff9db2005-12-17 13:51:03 +01003635 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01003636 if (rep->l == BUFSIZE) { /* no room to read more data */
3637 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3638 FD_CLR(t->srv_fd, StaticReadEvent);
3639 tv_eternity(&t->srexpire);
3640 }
3641 }
3642 else {
3643 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3644 FD_SET(t->srv_fd, StaticReadEvent);
3645 if (t->proxy->srvtimeout)
3646 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3647 else
3648 tv_eternity(&t->srexpire);
3649 }
3650 }
3651
3652 return 0; /* other cases change nothing */
3653 }
3654 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003655 if (t->res_sw == RES_ERROR) {
3656 //FD_CLR(t->srv_fd, StaticWriteEvent);
3657 tv_eternity(&t->swexpire);
3658 fd_delete(t->srv_fd);
3659 //close(t->srv_fd);
3660 t->srv_state = SV_STCLOSE;
3661 if (!(t->flags & SN_ERR_MASK))
3662 t->flags |= SN_ERR_SRVCL;
3663 if (!(t->flags & SN_FINST_MASK))
3664 t->flags |= SN_FINST_D;
3665 return 1;
3666 }
3667 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003668 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003669 tv_eternity(&t->swexpire);
3670 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003671 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003672 t->srv_state = SV_STCLOSE;
3673 return 1;
3674 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003675 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
3676 //FD_CLR(t->srv_fd, StaticWriteEvent);
3677 tv_eternity(&t->swexpire);
3678 fd_delete(t->srv_fd);
3679 //close(t->srv_fd);
3680 t->srv_state = SV_STCLOSE;
3681 if (!(t->flags & SN_ERR_MASK))
3682 t->flags |= SN_ERR_SRVTO;
3683 if (!(t->flags & SN_FINST_MASK))
3684 t->flags |= SN_FINST_D;
3685 return 1;
3686 }
willy tarreau0f7af912005-12-17 12:21:26 +01003687 else if (req->l == 0) {
3688 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3689 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3690 tv_eternity(&t->swexpire);
3691 }
3692 }
3693 else { /* buffer not empty */
3694 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3695 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003696 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003697 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003698 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3699 t->srexpire = t->swexpire;
3700 }
willy tarreau0f7af912005-12-17 12:21:26 +01003701 else
3702 tv_eternity(&t->swexpire);
3703 }
3704 }
3705 return 0;
3706 }
3707 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003708 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003709 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003710 tv_eternity(&t->srexpire);
3711 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003712 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003713 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003714 if (!(t->flags & SN_ERR_MASK))
3715 t->flags |= SN_ERR_SRVCL;
3716 if (!(t->flags & SN_FINST_MASK))
3717 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003718 return 1;
3719 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003720 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
3721 //FD_CLR(t->srv_fd, StaticReadEvent);
3722 tv_eternity(&t->srexpire);
3723 fd_delete(t->srv_fd);
3724 //close(t->srv_fd);
3725 t->srv_state = SV_STCLOSE;
3726 return 1;
3727 }
3728 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3729 //FD_CLR(t->srv_fd, StaticReadEvent);
3730 tv_eternity(&t->srexpire);
3731 fd_delete(t->srv_fd);
3732 //close(t->srv_fd);
3733 t->srv_state = SV_STCLOSE;
3734 if (!(t->flags & SN_ERR_MASK))
3735 t->flags |= SN_ERR_SRVTO;
3736 if (!(t->flags & SN_FINST_MASK))
3737 t->flags |= SN_FINST_D;
3738 return 1;
3739 }
willy tarreau0f7af912005-12-17 12:21:26 +01003740 else if (rep->l == BUFSIZE) { /* no room to read more data */
3741 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3742 FD_CLR(t->srv_fd, StaticReadEvent);
3743 tv_eternity(&t->srexpire);
3744 }
3745 }
3746 else {
3747 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3748 FD_SET(t->srv_fd, StaticReadEvent);
3749 if (t->proxy->srvtimeout)
3750 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3751 else
3752 tv_eternity(&t->srexpire);
3753 }
3754 }
3755 return 0;
3756 }
3757 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003758 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003759 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003760 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 +01003761 write(1, trash, len);
3762 }
3763 return 0;
3764 }
3765 return 0;
3766}
3767
3768
willy tarreau5cbea6f2005-12-17 12:48:26 +01003769/* Processes the client and server jobs of a session task, then
3770 * puts it back to the wait queue in a clean state, or
3771 * cleans up its resources if it must be deleted. Returns
3772 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003773 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003774int process_session(struct task *t) {
3775 struct session *s = t->context;
3776 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003777
willy tarreau5cbea6f2005-12-17 12:48:26 +01003778 do {
3779 fsm_resync = 0;
3780 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3781 fsm_resync |= process_cli(s);
3782 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3783 fsm_resync |= process_srv(s);
3784 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3785 } while (fsm_resync);
3786
3787 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003788 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003789 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003790
willy tarreau5cbea6f2005-12-17 12:48:26 +01003791 tv_min(&min1, &s->crexpire, &s->cwexpire);
3792 tv_min(&min2, &s->srexpire, &s->swexpire);
3793 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003794 tv_min(&t->expire, &min1, &min2);
3795
3796 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003797 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003798
willy tarreau5cbea6f2005-12-17 12:48:26 +01003799 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003800 }
3801
willy tarreau5cbea6f2005-12-17 12:48:26 +01003802 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003803 actconn--;
3804
willy tarreau9fe663a2005-12-17 13:02:59 +01003805 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003806 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003807 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 +01003808 write(1, trash, len);
3809 }
3810
willy tarreau750a4722005-12-17 13:21:24 +01003811 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003812 if (s->rep != NULL)
3813 s->logs.bytes = s->rep->total;
3814
willy tarreau9fe663a2005-12-17 13:02:59 +01003815 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003816 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003817 sess_log(s);
3818
willy tarreau0f7af912005-12-17 12:21:26 +01003819 /* the task MUST not be in the run queue anymore */
3820 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003821 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003822 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003823 return -1; /* rest in peace for eternity */
3824}
3825
3826
3827
3828/*
3829 * manages a server health-check. Returns
3830 * the time the task accepts to wait, or -1 for infinity.
3831 */
3832int process_chk(struct task *t) {
3833 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01003834 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003835 int fd = s->curfd;
3836 int one = 1;
3837
willy tarreauef900ab2005-12-17 12:52:52 +01003838 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003839
3840 if (fd < 0) { /* no check currently running */
3841 //fprintf(stderr, "process_chk: 2\n");
3842 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3843 task_queue(t); /* restore t to its place in the task list */
3844 return tv_remain(&now, &t->expire);
3845 }
3846
3847 /* we'll initiate a new check */
3848 s->result = 0; /* no result yet */
3849 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003850 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003851 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3852 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3853 //fprintf(stderr, "process_chk: 3\n");
3854
willy tarreaua41a8b42005-12-17 14:02:24 +01003855 /* we'll connect to the check port on the server */
3856 sa = s->addr;
3857 sa.sin_port = htons(s->check_port);
3858
willy tarreau036e1ce2005-12-17 13:46:33 +01003859 /* allow specific binding */
3860 if (s->proxy->options & PR_O_BIND_SRC &&
3861 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
3862 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
3863 close(fd);
3864 s->result = -1;
3865 }
willy tarreaua41a8b42005-12-17 14:02:24 +01003866 else if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003867 /* OK, connection in progress or established */
3868
3869 //fprintf(stderr, "process_chk: 4\n");
3870
3871 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3872 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003873 fdtab[fd].read = &event_srv_chk_r;
3874 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003875 fdtab[fd].state = FD_STCONN; /* connection in progress */
3876 FD_SET(fd, StaticWriteEvent); /* for connect status */
3877 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003878 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3879 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003880 task_queue(t); /* restore t to its place in the task list */
3881 return tv_remain(&now, &t->expire);
3882 }
3883 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3884 s->result = -1; /* a real error */
3885 }
3886 }
3887 //fprintf(stderr, "process_chk: 5\n");
3888 close(fd);
3889 }
3890
3891 if (!s->result) { /* nothing done */
3892 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003893 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003894 task_queue(t); /* restore t to its place in the task list */
3895 return tv_remain(&now, &t->expire);
3896 }
3897
3898 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003899 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003900 s->health--; /* still good */
3901 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003902 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003903 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003904 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003905
willy tarreau9fe663a2005-12-17 13:02:59 +01003906 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003907 }
willy tarreauef900ab2005-12-17 12:52:52 +01003908
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 s->health = 0; /* failure */
3910 s->state &= ~SRV_RUNNING;
3911 }
3912
3913 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003914 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3915 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003916 }
3917 else {
3918 //fprintf(stderr, "process_chk: 8\n");
3919 /* there was a test running */
3920 if (s->result > 0) { /* good server detected */
3921 //fprintf(stderr, "process_chk: 9\n");
3922 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003923 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003924 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003925 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003926 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003927 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003928 }
willy tarreauef900ab2005-12-17 12:52:52 +01003929
willy tarreaue47c8d72005-12-17 12:55:52 +01003930 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003931 s->state |= SRV_RUNNING;
3932 }
willy tarreauef900ab2005-12-17 12:52:52 +01003933 s->curfd = -1; /* no check running anymore */
3934 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003935 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003936 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003937 }
3938 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3939 //fprintf(stderr, "process_chk: 10\n");
3940 /* failure or timeout detected */
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 tarreau535ae7a2005-12-17 12:58:00 +01003944 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003945 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003946 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003947
3948 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003949 }
willy tarreauef900ab2005-12-17 12:52:52 +01003950
willy tarreau5cbea6f2005-12-17 12:48:26 +01003951 s->health = 0; /* failure */
3952 s->state &= ~SRV_RUNNING;
3953 }
3954 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003955 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003956 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003957 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003958 }
3959 /* if result is 0 and there's no timeout, we have to wait again */
3960 }
3961 //fprintf(stderr, "process_chk: 11\n");
3962 s->result = 0;
3963 task_queue(t); /* restore t to its place in the task list */
3964 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003965}
3966
3967
willy tarreau5cbea6f2005-12-17 12:48:26 +01003968
willy tarreau0f7af912005-12-17 12:21:26 +01003969#if STATTIME > 0
3970int stats(void);
3971#endif
3972
3973/*
3974 * Main select() loop.
3975 */
3976
3977void select_loop() {
3978 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003979 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003980 int status;
3981 int fd,i;
3982 struct timeval delta;
3983 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003984 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003985
willy tarreau5cbea6f2005-12-17 12:48:26 +01003986 tv_now(&now);
3987
3988 while (1) {
3989 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003990
willy tarreau5cbea6f2005-12-17 12:48:26 +01003991 /* look for expired tasks and add them to the run queue.
3992 */
3993 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3994 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3995 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003996 if (t->state & TASK_RUNNING)
3997 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003998
3999 /* wakeup expired entries. It doesn't matter if they are
4000 * already running because of a previous event
4001 */
4002 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01004003 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004004 task_wakeup(&rq, t);
4005 }
4006 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004007 /* first non-runnable task. Use its expiration date as an upper bound */
4008 int temp_time = tv_remain(&now, &t->expire);
4009 if (temp_time)
4010 next_time = temp_time;
4011 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004012 break;
4013 }
4014 }
4015
4016 /* process each task in the run queue now. Each task may be deleted
4017 * since we only use tnext.
4018 */
4019 tnext = rq;
4020 while ((t = tnext) != NULL) {
4021 int temp_time;
4022
4023 tnext = t->rqnext;
4024 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01004025 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004026 temp_time = t->process(t);
4027 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01004028 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004029 }
4030
willy tarreauef900ab2005-12-17 12:52:52 +01004031 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01004032
4033 /* maintain all proxies in a consistent state. This should quickly become a task */
4034 time2 = maintain_proxies();
4035 next_time = MINTIME(time2, next_time);
4036
4037 /* stop when there's no connection left and we don't allow them anymore */
4038 if (!actconn && listeners == 0)
4039 break;
4040
willy tarreau0f7af912005-12-17 12:21:26 +01004041
4042#if STATTIME > 0
4043 time2 = stats();
4044 // fprintf(stderr," stats = %d\n", time2);
4045 next_time = MINTIME(time2, next_time);
4046#endif
4047
willy tarreau5cbea6f2005-12-17 12:48:26 +01004048 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01004049 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004050 /* to avoid eventual select loops due to timer precision */
4051 next_time += SCHEDULER_RESOLUTION;
4052 delta.tv_sec = next_time / 1000;
4053 delta.tv_usec = (next_time % 1000) * 1000;
4054 }
4055 else if (next_time == 0) { /* allow select to return immediately when needed */
4056 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004057 }
4058
4059
4060 /* let's restore fdset state */
4061
4062 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004063 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004064 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
4065 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
4066 }
4067
4068// /* just a verification code, needs to be removed for performance */
4069// for (i=0; i<maxfd; i++) {
4070// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
4071// abort();
4072// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
4073// abort();
4074//
4075// }
4076
willy tarreau197e8ec2005-12-17 14:10:59 +01004077 status = select(maxfd,
4078 readnotnull ? ReadEvent : NULL,
4079 writenotnull ? WriteEvent : NULL,
4080 NULL,
4081 (next_time >= 0) ? &delta : NULL);
willy tarreau0f7af912005-12-17 12:21:26 +01004082
willy tarreau5cbea6f2005-12-17 12:48:26 +01004083 /* this is an experiment on the separation of the select work */
4084 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4085 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4086
willy tarreau0f7af912005-12-17 12:21:26 +01004087 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004088
willy tarreau0f7af912005-12-17 12:21:26 +01004089 if (status > 0) { /* must proceed with events */
4090
4091 int fds;
4092 char count;
4093
4094 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
4095 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
4096 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
4097
willy tarreau5cbea6f2005-12-17 12:48:26 +01004098 /* if we specify read first, the accepts and zero reads will be
4099 * seen first. Moreover, system buffers will be flushed faster.
4100 */
willy tarreau0f7af912005-12-17 12:21:26 +01004101 if (fdtab[fd].state == FD_STCLOSE)
4102 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01004103
4104 if (FD_ISSET(fd, ReadEvent))
4105 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004106
willy tarreau5cbea6f2005-12-17 12:48:26 +01004107 if (FD_ISSET(fd, WriteEvent))
4108 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004109 }
4110 }
4111 else {
4112 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
4113 }
willy tarreau0f7af912005-12-17 12:21:26 +01004114 }
4115}
4116
4117
4118#if STATTIME > 0
4119/*
4120 * Display proxy statistics regularly. It is designed to be called from the
4121 * select_loop().
4122 */
4123int stats(void) {
4124 static int lines;
4125 static struct timeval nextevt;
4126 static struct timeval lastevt;
4127 static struct timeval starttime = {0,0};
4128 unsigned long totaltime, deltatime;
4129 int ret;
4130
willy tarreau750a4722005-12-17 13:21:24 +01004131 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01004132 deltatime = (tv_diff(&lastevt, &now)?:1);
4133 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01004134
willy tarreau9fe663a2005-12-17 13:02:59 +01004135 if (global.mode & MODE_STATS) {
4136 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004137 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004138 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
4139 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004140 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004141 actconn, totalconn,
4142 stats_tsk_new, stats_tsk_good,
4143 stats_tsk_left, stats_tsk_right,
4144 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
4145 }
4146 }
4147
4148 tv_delayfrom(&nextevt, &now, STATTIME);
4149
4150 lastevt=now;
4151 }
4152 ret = tv_remain(&now, &nextevt);
4153 return ret;
4154}
4155#endif
4156
4157
4158/*
4159 * this function enables proxies when there are enough free sessions,
4160 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01004161 * select_loop(). It returns the time left before next expiration event
4162 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01004163 */
4164static int maintain_proxies(void) {
4165 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01004166 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004167 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01004168
4169 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004170 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01004171
4172 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01004173 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01004174 while (p) {
4175 if (p->nbconn < p->maxconn) {
4176 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004177 for (l = p->listen; l != NULL; l = l->next) {
4178 FD_SET(l->fd, StaticReadEvent);
4179 }
willy tarreau0f7af912005-12-17 12:21:26 +01004180 p->state = PR_STRUN;
4181 }
4182 }
4183 else {
4184 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004185 for (l = p->listen; l != NULL; l = l->next) {
4186 FD_CLR(l->fd, StaticReadEvent);
4187 }
willy tarreau0f7af912005-12-17 12:21:26 +01004188 p->state = PR_STIDLE;
4189 }
4190 }
4191 p = p->next;
4192 }
4193 }
4194 else { /* block all proxies */
4195 while (p) {
4196 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004197 for (l = p->listen; l != NULL; l = l->next) {
4198 FD_CLR(l->fd, StaticReadEvent);
4199 }
willy tarreau0f7af912005-12-17 12:21:26 +01004200 p->state = PR_STIDLE;
4201 }
4202 p = p->next;
4203 }
4204 }
4205
willy tarreau5cbea6f2005-12-17 12:48:26 +01004206 if (stopping) {
4207 p = proxy;
4208 while (p) {
4209 if (p->state != PR_STDISABLED) {
4210 int t;
4211 t = tv_remain(&now, &p->stop_time);
4212 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004213 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004214 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004215
willy tarreaua41a8b42005-12-17 14:02:24 +01004216 for (l = p->listen; l != NULL; l = l->next) {
4217 fd_delete(l->fd);
4218 listeners--;
4219 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004220 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004221 }
4222 else {
4223 tleft = MINTIME(t, tleft);
4224 }
4225 }
4226 p = p->next;
4227 }
4228 }
4229 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004230}
4231
4232/*
4233 * this function disables health-check servers so that the process will quickly be ignored
4234 * by load balancers.
4235 */
4236static void soft_stop(void) {
4237 struct proxy *p;
4238
4239 stopping = 1;
4240 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004241 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004242 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004243 if (p->state != PR_STDISABLED) {
4244 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004245 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004246 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004247 }
willy tarreau0f7af912005-12-17 12:21:26 +01004248 p = p->next;
4249 }
4250}
4251
4252/*
4253 * upon SIGUSR1, let's have a soft stop.
4254 */
4255void sig_soft_stop(int sig) {
4256 soft_stop();
4257 signal(sig, SIG_IGN);
4258}
4259
4260
willy tarreau8337c6b2005-12-17 13:41:01 +01004261/*
4262 * this function dumps every server's state when the process receives SIGHUP.
4263 */
4264void sig_dump_state(int sig) {
4265 struct proxy *p = proxy;
4266
4267 Warning("SIGHUP received, dumping servers states.\n");
4268 while (p) {
4269 struct server *s = p->srv;
4270
4271 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
4272 while (s) {
4273 if (s->state & SRV_RUNNING) {
4274 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
4275 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
4276 }
4277 else {
4278 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4279 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
4280 }
4281 s = s->next;
4282 }
4283 p = p->next;
4284 }
4285 signal(sig, sig_dump_state);
4286}
4287
willy tarreau0f7af912005-12-17 12:21:26 +01004288void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004289 struct task *t, *tnext;
4290 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01004291
willy tarreau5cbea6f2005-12-17 12:48:26 +01004292 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4293 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4294 tnext = t->next;
4295 s = t->context;
4296 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
4297 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
4298 "req=%d, rep=%d, clifd=%d\n",
4299 s, tv_remain(&now, &t->expire),
4300 s->cli_state,
4301 s->srv_state,
4302 FD_ISSET(s->cli_fd, StaticReadEvent),
4303 FD_ISSET(s->cli_fd, StaticWriteEvent),
4304 FD_ISSET(s->srv_fd, StaticReadEvent),
4305 FD_ISSET(s->srv_fd, StaticWriteEvent),
4306 s->req->l, s->rep?s->rep->l:0, s->cli_fd
4307 );
willy tarreau0f7af912005-12-17 12:21:26 +01004308 }
4309}
4310
willy tarreaue39cd132005-12-17 13:00:18 +01004311void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
4312 struct hdr_exp *exp;
4313
4314 while (*head != NULL)
4315 head = &(*head)->next;
4316
4317 exp = calloc(1, sizeof(struct hdr_exp));
4318
4319 exp->preg = preg;
4320 exp->replace = replace;
4321 exp->action = action;
4322 *head = exp;
4323}
4324
willy tarreau9fe663a2005-12-17 13:02:59 +01004325
willy tarreau0f7af912005-12-17 12:21:26 +01004326/*
willy tarreau9fe663a2005-12-17 13:02:59 +01004327 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01004328 */
willy tarreau9fe663a2005-12-17 13:02:59 +01004329int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01004330
willy tarreau9fe663a2005-12-17 13:02:59 +01004331 if (!strcmp(args[0], "global")) { /* new section */
4332 /* no option, nothing special to do */
4333 return 0;
4334 }
4335 else if (!strcmp(args[0], "daemon")) {
4336 global.mode |= MODE_DAEMON;
4337 }
4338 else if (!strcmp(args[0], "debug")) {
4339 global.mode |= MODE_DEBUG;
4340 }
4341 else if (!strcmp(args[0], "quiet")) {
4342 global.mode |= MODE_QUIET;
4343 }
4344 else if (!strcmp(args[0], "stats")) {
4345 global.mode |= MODE_STATS;
4346 }
4347 else if (!strcmp(args[0], "uid")) {
4348 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004349 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004350 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004351 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004352 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004353 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004354 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004356 global.uid = atol(args[1]);
4357 }
4358 else if (!strcmp(args[0], "gid")) {
4359 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004360 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004361 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004362 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004363 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004364 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004365 return -1;
4366 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004367 global.gid = atol(args[1]);
4368 }
4369 else if (!strcmp(args[0], "nbproc")) {
4370 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004371 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004372 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004373 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004374 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004375 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004376 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004377 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004378 global.nbproc = atol(args[1]);
4379 }
4380 else if (!strcmp(args[0], "maxconn")) {
4381 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004382 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004383 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004384 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004385 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004386 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004387 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004388 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004389 global.maxconn = atol(args[1]);
4390 }
4391 else if (!strcmp(args[0], "chroot")) {
4392 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004393 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004394 return 0;
4395 }
4396 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004397 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004398 return -1;
4399 }
4400 global.chroot = strdup(args[1]);
4401 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01004402 else if (!strcmp(args[0], "pidfile")) {
4403 if (global.pidfile != NULL) {
4404 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
4405 return 0;
4406 }
4407 if (*(args[1]) == 0) {
4408 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
4409 return -1;
4410 }
4411 global.pidfile = strdup(args[1]);
4412 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004413 else if (!strcmp(args[0], "log")) { /* syslog server address */
4414 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004415 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004416
4417 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004418 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004419 return -1;
4420 }
4421
4422 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4423 if (!strcmp(log_facilities[facility], args[2]))
4424 break;
4425
4426 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004427 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004428 exit(1);
4429 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004430
4431 level = 7; /* max syslog level = debug */
4432 if (*(args[3])) {
4433 while (level >= 0 && strcmp(log_levels[level], args[3]))
4434 level--;
4435 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004436 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004437 exit(1);
4438 }
4439 }
4440
willy tarreau9fe663a2005-12-17 13:02:59 +01004441 sa = str2sa(args[1]);
4442 if (!sa->sin_port)
4443 sa->sin_port = htons(SYSLOG_PORT);
4444
4445 if (global.logfac1 == -1) {
4446 global.logsrv1 = *sa;
4447 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004448 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004449 }
4450 else if (global.logfac2 == -1) {
4451 global.logsrv2 = *sa;
4452 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004453 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004454 }
4455 else {
4456 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4457 return -1;
4458 }
4459
4460 }
4461 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004462 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01004463 return -1;
4464 }
4465 return 0;
4466}
4467
4468
willy tarreaua41a8b42005-12-17 14:02:24 +01004469void init_default_instance() {
4470 memset(&defproxy, 0, sizeof(defproxy));
4471 defproxy.mode = PR_MODE_TCP;
4472 defproxy.state = PR_STNEW;
4473 defproxy.maxconn = cfg_maxpconn;
4474 defproxy.conn_retries = CONN_RETRIES;
4475 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
4476}
4477
willy tarreau9fe663a2005-12-17 13:02:59 +01004478/*
4479 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4480 */
4481int cfg_parse_listen(char *file, int linenum, char **args) {
4482 static struct proxy *curproxy = NULL;
4483 struct server *newsrv = NULL;
4484
4485 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01004486 if (!*args[1]) {
4487 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
4488 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004489 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004490 return -1;
4491 }
4492
4493 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004494 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004495 return -1;
4496 }
4497 curproxy->next = proxy;
4498 proxy = curproxy;
4499 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01004500 if (strchr(args[2], ':') != NULL)
4501 curproxy->listen = str2listener(args[2], curproxy->listen);
4502
willy tarreau9fe663a2005-12-17 13:02:59 +01004503 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01004504 curproxy->state = defproxy.state;
4505 curproxy->maxconn = defproxy.maxconn;
4506 curproxy->conn_retries = defproxy.conn_retries;
4507 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004508
4509 if (defproxy.check_req)
4510 curproxy->check_req = strdup(defproxy.check_req);
4511 curproxy->check_len = defproxy.check_len;
4512
4513 if (defproxy.cookie_name)
4514 curproxy->cookie_name = strdup(defproxy.cookie_name);
4515 curproxy->cookie_len = defproxy.cookie_len;
4516
4517 if (defproxy.capture_name)
4518 curproxy->capture_name = strdup(defproxy.capture_name);
4519 curproxy->capture_namelen = defproxy.capture_namelen;
4520 curproxy->capture_len = defproxy.capture_len;
4521
4522 if (defproxy.errmsg.msg400)
4523 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
4524 curproxy->errmsg.len400 = defproxy.errmsg.len400;
4525
4526 if (defproxy.errmsg.msg403)
4527 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
4528 curproxy->errmsg.len403 = defproxy.errmsg.len403;
4529
4530 if (defproxy.errmsg.msg408)
4531 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
4532 curproxy->errmsg.len408 = defproxy.errmsg.len408;
4533
4534 if (defproxy.errmsg.msg500)
4535 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
4536 curproxy->errmsg.len500 = defproxy.errmsg.len500;
4537
4538 if (defproxy.errmsg.msg502)
4539 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
4540 curproxy->errmsg.len502 = defproxy.errmsg.len502;
4541
4542 if (defproxy.errmsg.msg503)
4543 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
4544 curproxy->errmsg.len503 = defproxy.errmsg.len503;
4545
4546 if (defproxy.errmsg.msg504)
4547 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
4548 curproxy->errmsg.len504 = defproxy.errmsg.len504;
4549
willy tarreaua41a8b42005-12-17 14:02:24 +01004550 curproxy->clitimeout = defproxy.clitimeout;
4551 curproxy->contimeout = defproxy.contimeout;
4552 curproxy->srvtimeout = defproxy.srvtimeout;
4553 curproxy->mode = defproxy.mode;
4554 curproxy->logfac1 = defproxy.logfac1;
4555 curproxy->logsrv1 = defproxy.logsrv1;
4556 curproxy->loglev1 = defproxy.loglev1;
4557 curproxy->logfac2 = defproxy.logfac2;
4558 curproxy->logsrv2 = defproxy.logsrv2;
4559 curproxy->loglev2 = defproxy.loglev2;
4560 curproxy->to_log = defproxy.to_log;
4561 curproxy->grace = defproxy.grace;
4562 curproxy->source_addr = defproxy.source_addr;
4563 return 0;
4564 }
4565 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004566 /* some variables may have already been initialized earlier */
4567 if (defproxy.check_req) free(defproxy.check_req);
4568 if (defproxy.cookie_name) free(defproxy.cookie_name);
4569 if (defproxy.capture_name) free(defproxy.capture_name);
4570 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
4571 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
4572 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
4573 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
4574 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
4575 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
4576 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
4577
4578 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01004579 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01004580 return 0;
4581 }
4582 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004583 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004584 return -1;
4585 }
4586
willy tarreaua41a8b42005-12-17 14:02:24 +01004587 if (!strcmp(args[0], "bind")) { /* new listen addresses */
4588 if (curproxy == &defproxy) {
4589 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4590 return -1;
4591 }
4592
4593 if (strchr(args[1], ':') == NULL) {
4594 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
4595 file, linenum, args[0]);
4596 return -1;
4597 }
4598 curproxy->listen = str2listener(args[1], curproxy->listen);
4599 return 0;
4600 }
4601 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01004602 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
4603 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
4604 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
4605 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004606 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004607 return -1;
4608 }
4609 }
4610 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
4611 curproxy->state = PR_STDISABLED;
4612 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004613 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
4614 curproxy->state = PR_STNEW;
4615 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004616 else if (!strcmp(args[0], "cookie")) { /* cookie name */
4617 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004618// if (curproxy == &defproxy) {
4619// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4620// return -1;
4621// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004622
willy tarreau9fe663a2005-12-17 13:02:59 +01004623 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004624// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
4625// file, linenum);
4626// return 0;
4627 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004628 }
4629
4630 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004631 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
4632 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004633 return -1;
4634 }
4635 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004636 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004637
4638 cur_arg = 2;
4639 while (*(args[cur_arg])) {
4640 if (!strcmp(args[cur_arg], "rewrite")) {
4641 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01004642 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004643 else if (!strcmp(args[cur_arg], "indirect")) {
4644 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01004645 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004646 else if (!strcmp(args[cur_arg], "insert")) {
4647 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01004648 }
willy tarreau240afa62005-12-17 13:14:35 +01004649 else if (!strcmp(args[cur_arg], "nocache")) {
4650 curproxy->options |= PR_O_COOK_NOC;
4651 }
willy tarreaucd878942005-12-17 13:27:43 +01004652 else if (!strcmp(args[cur_arg], "postonly")) {
4653 curproxy->options |= PR_O_COOK_POST;
4654 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004655 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004656 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
4657 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004658 return -1;
4659 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004660 cur_arg++;
4661 }
4662 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 +01004663 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01004664 file, linenum);
4665 return -1;
4666 }
4667 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004668 else if (!strcmp(args[0], "capture")) { /* name of a cookie to capture */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004669// if (curproxy == &defproxy) {
4670// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4671// return -1;
4672// }
willy tarreaua41a8b42005-12-17 14:02:24 +01004673
willy tarreau8337c6b2005-12-17 13:41:01 +01004674 if (curproxy->capture_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01004675// Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4676// file, linenum, args[0]);
4677// return 0;
4678 free(curproxy->capture_name);
willy tarreau8337c6b2005-12-17 13:41:01 +01004679 }
4680
4681 if (*(args[4]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004682 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
4683 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004684 return -1;
4685 }
4686 curproxy->capture_name = strdup(args[2]);
4687 curproxy->capture_namelen = strlen(curproxy->capture_name);
4688 curproxy->capture_len = atol(args[4]);
4689 if (curproxy->capture_len >= CAPTURE_LEN) {
4690 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
4691 file, linenum, CAPTURE_LEN - 1);
4692 curproxy->capture_len = CAPTURE_LEN - 1;
4693 }
4694 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004695 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004696 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004697 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004698 return 0;
4699 }
4700 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004701 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4702 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004703 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004704 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004705 curproxy->contimeout = atol(args[1]);
4706 }
4707 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004708 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004709 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
4710 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004711 return 0;
4712 }
4713 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004714 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4715 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004716 return -1;
4717 }
4718 curproxy->clitimeout = atol(args[1]);
4719 }
4720 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01004721 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004722 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004723 return 0;
4724 }
4725 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004726 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
4727 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01004728 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004729 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004730 curproxy->srvtimeout = atol(args[1]);
4731 }
4732 else if (!strcmp(args[0], "retries")) { /* connection retries */
4733 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004734 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
4735 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004736 return -1;
4737 }
4738 curproxy->conn_retries = atol(args[1]);
4739 }
4740 else if (!strcmp(args[0], "option")) {
4741 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004742 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004743 return -1;
4744 }
4745 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004746 /* enable reconnections to dispatch */
4747 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004748#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004749 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004750 /* enable transparent proxy connections */
4751 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004752#endif
4753 else if (!strcmp(args[1], "keepalive"))
4754 /* enable keep-alive */
4755 curproxy->options |= PR_O_KEEPALIVE;
4756 else if (!strcmp(args[1], "forwardfor"))
4757 /* insert x-forwarded-for field */
4758 curproxy->options |= PR_O_FWDFOR;
willy tarreauc1cae632005-12-17 14:12:23 +01004759 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01004760 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01004761 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
willy tarreauc1cae632005-12-17 14:12:23 +01004762 else if (!strcmp(args[1], "tcplog"))
4763 /* generate a detailed TCP log */
4764 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID;
willy tarreaua1598082005-12-17 13:08:06 +01004765 else if (!strcmp(args[1], "dontlognull")) {
4766 /* don't log empty requests */
4767 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004768 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004769 else if (!strcmp(args[1], "httpchk")) {
4770 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004771 if (curproxy->check_req != NULL) {
4772 free(curproxy->check_req);
4773 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004774 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01004775 if (!*args[2]) { /* no argument */
4776 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
4777 curproxy->check_len = strlen(DEF_CHECK_REQ);
4778 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01004779 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
4780 curproxy->check_req = (char *)malloc(reqlen);
4781 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4782 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01004783 } else { /* more arguments : METHOD URI [HTTP_VER] */
4784 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
4785 if (*args[4])
4786 reqlen += strlen(args[4]);
4787 else
4788 reqlen += strlen("HTTP/1.0");
4789
4790 curproxy->check_req = (char *)malloc(reqlen);
4791 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
4792 "%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 +01004793 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004794 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004795 else if (!strcmp(args[1], "persist")) {
4796 /* persist on using the server specified by the cookie, even when it's down */
4797 curproxy->options |= PR_O_PERSIST;
4798 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004799 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004800 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004801 return -1;
4802 }
4803 return 0;
4804 }
4805 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4806 /* enable reconnections to dispatch */
4807 curproxy->options |= PR_O_REDISP;
4808 }
willy tarreaua1598082005-12-17 13:08:06 +01004809#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004810 else if (!strcmp(args[0], "transparent")) {
4811 /* enable transparent proxy connections */
4812 curproxy->options |= PR_O_TRANSP;
4813 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004814#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004815 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4816 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004817 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004818 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004819 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004820 curproxy->maxconn = atol(args[1]);
4821 }
4822 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4823 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004824 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004825 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004826 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004827 curproxy->grace = atol(args[1]);
4828 }
4829 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01004830 if (curproxy == &defproxy) {
4831 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4832 return -1;
4833 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004834 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004835 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004836 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004837 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004838 curproxy->dispatch_addr = *str2sa(args[1]);
4839 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004840 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01004841 if (*(args[1])) {
4842 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004843 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004844 }
4845 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01004846 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004847 return -1;
4848 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004849 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004850 else /* if no option is set, use round-robin by default */
4851 curproxy->options |= PR_O_BALANCE_RR;
4852 }
4853 else if (!strcmp(args[0], "server")) { /* server address */
4854 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01004855 char *rport;
4856 char *raddr;
4857 short realport;
4858 int do_check;
4859
4860 if (curproxy == &defproxy) {
4861 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
4862 return -1;
4863 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004864
willy tarreaua41a8b42005-12-17 14:02:24 +01004865 if (!*args[2]) {
4866 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01004867 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01004868 return -1;
4869 }
4870 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4871 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4872 return -1;
4873 }
4874 newsrv->next = curproxy->srv;
4875 curproxy->srv = newsrv;
4876 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01004877
4878 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004879 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01004880 newsrv->id = strdup(args[1]);
4881
4882 /* several ways to check the port component :
4883 * - IP => port=+0, relative
4884 * - IP: => port=+0, relative
4885 * - IP:N => port=N, absolute
4886 * - IP:+N => port=+N, relative
4887 * - IP:-N => port=-N, relative
4888 */
4889 raddr = strdup(args[2]);
4890 rport = strchr(raddr, ':');
4891 if (rport) {
4892 *rport++ = 0;
4893 realport = atol(rport);
4894 if (!isdigit((int)*rport))
4895 newsrv->state |= SRV_MAPPORTS;
4896 } else {
4897 realport = 0;
4898 newsrv->state |= SRV_MAPPORTS;
4899 }
4900
4901 newsrv->addr = *str2sa(raddr);
4902 newsrv->addr.sin_port = htons(realport);
4903 free(raddr);
4904
willy tarreau9fe663a2005-12-17 13:02:59 +01004905 newsrv->curfd = -1; /* no health-check in progress */
4906 newsrv->inter = DEF_CHKINTR;
4907 newsrv->rise = DEF_RISETIME;
4908 newsrv->fall = DEF_FALLTIME;
4909 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4910 cur_arg = 3;
4911 while (*args[cur_arg]) {
4912 if (!strcmp(args[cur_arg], "cookie")) {
4913 newsrv->cookie = strdup(args[cur_arg + 1]);
4914 newsrv->cklen = strlen(args[cur_arg + 1]);
4915 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004916 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004917 else if (!strcmp(args[cur_arg], "rise")) {
4918 newsrv->rise = atol(args[cur_arg + 1]);
4919 newsrv->health = newsrv->rise;
4920 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004921 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004922 else if (!strcmp(args[cur_arg], "fall")) {
4923 newsrv->fall = atol(args[cur_arg + 1]);
4924 cur_arg += 2;
4925 }
4926 else if (!strcmp(args[cur_arg], "inter")) {
4927 newsrv->inter = atol(args[cur_arg + 1]);
4928 cur_arg += 2;
4929 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004930 else if (!strcmp(args[cur_arg], "port")) {
4931 newsrv->check_port = atol(args[cur_arg + 1]);
4932 cur_arg += 2;
4933 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004934 else if (!strcmp(args[cur_arg], "backup")) {
4935 newsrv->state |= SRV_BACKUP;
4936 cur_arg ++;
4937 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004938 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004939 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004940 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004941 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004942 else {
willy tarreaua41a8b42005-12-17 14:02:24 +01004943 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
4944 file, linenum, newsrv->id);
4945 return -1;
4946 }
4947 }
4948
4949 if (do_check) {
4950 struct task *t;
4951
4952 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
4953 newsrv->check_port = realport; /* by default */
4954 if (!newsrv->check_port) {
4955 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 +01004956 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004957 return -1;
4958 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004959
4960 if ((t = pool_alloc(task)) == NULL) {
4961 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4962 return -1;
4963 }
4964
4965 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4966 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4967 t->state = TASK_IDLE;
4968 t->process = process_chk;
4969 t->context = newsrv;
4970
4971 if (curproxy->state != PR_STDISABLED) {
4972 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4973 task_queue(t);
4974 task_wakeup(&rq, t);
4975 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004976 }
willy tarreaua41a8b42005-12-17 14:02:24 +01004977
willy tarreau9fe663a2005-12-17 13:02:59 +01004978 curproxy->nbservers++;
4979 }
4980 else if (!strcmp(args[0], "log")) { /* syslog server address */
4981 struct sockaddr_in *sa;
4982 int facility;
4983
4984 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4985 curproxy->logfac1 = global.logfac1;
4986 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004987 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004988 curproxy->logfac2 = global.logfac2;
4989 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01004990 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01004991 }
4992 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01004993 int level;
4994
willy tarreau0f7af912005-12-17 12:21:26 +01004995 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4996 if (!strcmp(log_facilities[facility], args[2]))
4997 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004998
willy tarreau0f7af912005-12-17 12:21:26 +01004999 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005000 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01005001 exit(1);
5002 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005003
willy tarreau8337c6b2005-12-17 13:41:01 +01005004 level = 7; /* max syslog level = debug */
5005 if (*(args[3])) {
5006 while (level >= 0 && strcmp(log_levels[level], args[3]))
5007 level--;
5008 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005009 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005010 exit(1);
5011 }
5012 }
5013
willy tarreau0f7af912005-12-17 12:21:26 +01005014 sa = str2sa(args[1]);
5015 if (!sa->sin_port)
5016 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01005017
willy tarreau0f7af912005-12-17 12:21:26 +01005018 if (curproxy->logfac1 == -1) {
5019 curproxy->logsrv1 = *sa;
5020 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005021 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005022 }
5023 else if (curproxy->logfac2 == -1) {
5024 curproxy->logsrv2 = *sa;
5025 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005026 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005027 }
5028 else {
5029 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005030 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005031 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005032 }
5033 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005034 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005035 file, linenum);
5036 return -1;
5037 }
5038 }
willy tarreaua1598082005-12-17 13:08:06 +01005039 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01005040 if (!*args[1]) {
5041 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005042 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01005043 return -1;
5044 }
5045
5046 curproxy->source_addr = *str2sa(args[1]);
5047 curproxy->options |= PR_O_BIND_SRC;
5048 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005049 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
5050 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005051 if (curproxy == &defproxy) {
5052 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5053 return -1;
5054 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005055
5056 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005057 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5058 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005059 return -1;
5060 }
5061
5062 preg = calloc(1, sizeof(regex_t));
5063 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005064 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005065 return -1;
5066 }
5067
5068 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5069 }
5070 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
5071 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005072 if (curproxy == &defproxy) {
5073 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5074 return -1;
5075 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005076
5077 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005078 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005079 return -1;
5080 }
5081
5082 preg = calloc(1, sizeof(regex_t));
5083 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005084 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005085 return -1;
5086 }
5087
5088 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5089 }
5090 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
5091 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005092 if (curproxy == &defproxy) {
5093 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5094 return -1;
5095 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005096
5097 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005098 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005099 return -1;
5100 }
5101
5102 preg = calloc(1, sizeof(regex_t));
5103 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005104 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005105 return -1;
5106 }
5107
5108 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5109 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005110 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
5111 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005112 if (curproxy == &defproxy) {
5113 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5114 return -1;
5115 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005116
5117 if (*(args[1]) == 0) {
5118 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5119 return -1;
5120 }
5121
5122 preg = calloc(1, sizeof(regex_t));
5123 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
5124 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5125 return -1;
5126 }
5127
5128 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5129 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005130 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
5131 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005132 if (curproxy == &defproxy) {
5133 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5134 return -1;
5135 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005136
5137 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005138 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005139 return -1;
5140 }
5141
5142 preg = calloc(1, sizeof(regex_t));
5143 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005144 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005145 return -1;
5146 }
5147
5148 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5149 }
5150 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
5151 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005152 if (curproxy == &defproxy) {
5153 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5154 return -1;
5155 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005156
5157 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005158 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5159 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005160 return -1;
5161 }
5162
5163 preg = calloc(1, sizeof(regex_t));
5164 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005165 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005166 return -1;
5167 }
5168
5169 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5170 }
5171 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
5172 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005173 if (curproxy == &defproxy) {
5174 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5175 return -1;
5176 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005177
5178 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005179 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005180 return -1;
5181 }
5182
5183 preg = calloc(1, sizeof(regex_t));
5184 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005185 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005186 return -1;
5187 }
5188
5189 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5190 }
5191 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
5192 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005193 if (curproxy == &defproxy) {
5194 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5195 return -1;
5196 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005197
5198 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005199 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005200 return -1;
5201 }
5202
5203 preg = calloc(1, sizeof(regex_t));
5204 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005205 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005206 return -1;
5207 }
5208
5209 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
5210 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005211 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
5212 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005213 if (curproxy == &defproxy) {
5214 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5215 return -1;
5216 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005217
5218 if (*(args[1]) == 0) {
5219 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
5220 return -1;
5221 }
5222
5223 preg = calloc(1, sizeof(regex_t));
5224 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5225 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5226 return -1;
5227 }
5228
5229 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
5230 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005231 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
5232 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005233 if (curproxy == &defproxy) {
5234 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5235 return -1;
5236 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005237
5238 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005239 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005240 return -1;
5241 }
5242
5243 preg = calloc(1, sizeof(regex_t));
5244 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005245 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005246 return -1;
5247 }
5248
5249 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
5250 }
5251 else if (!strcmp(args[0], "reqadd")) { /* add request header */
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 }
5256
willy tarreau9fe663a2005-12-17 13:02:59 +01005257 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005258 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005259 return 0;
5260 }
5261
5262 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005263 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005264 return -1;
5265 }
5266
5267 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005268 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005269 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01005270 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01005271
5272 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005273 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5274 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005275 return -1;
5276 }
5277
5278 preg = calloc(1, sizeof(regex_t));
5279 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005280 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01005281 return -1;
5282 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005283
5284 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5285 }
5286 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
5287 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005288 if (curproxy == &defproxy) {
5289 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5290 return -1;
5291 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005292
5293 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005294 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005295 return -1;
5296 }
willy tarreaue39cd132005-12-17 13:00:18 +01005297
willy tarreau9fe663a2005-12-17 13:02:59 +01005298 preg = calloc(1, sizeof(regex_t));
5299 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005300 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005301 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005302 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005303
5304 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5305 }
5306 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01005307 regex_t *preg;
5308 if (curproxy == &defproxy) {
5309 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5310 return -1;
5311 }
willy tarreaue39cd132005-12-17 13:00:18 +01005312
willy tarreaua41a8b42005-12-17 14:02:24 +01005313 if (*(args[1]) == 0 || *(args[2]) == 0) {
5314 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5315 file, linenum, args[0]);
5316 return -1;
5317 }
willy tarreaue39cd132005-12-17 13:00:18 +01005318
willy tarreaua41a8b42005-12-17 14:02:24 +01005319 preg = calloc(1, sizeof(regex_t));
5320 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
5321 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
5322 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005323 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005324
5325 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
5326 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005327 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
5328 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005329 if (curproxy == &defproxy) {
5330 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5331 return -1;
5332 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005333
5334 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005335 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005336 return -1;
5337 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005338
willy tarreau9fe663a2005-12-17 13:02:59 +01005339 preg = calloc(1, sizeof(regex_t));
5340 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005341 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005342 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005343 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005344
5345 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
5346 }
5347 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01005348 if (curproxy == &defproxy) {
5349 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5350 return -1;
5351 }
5352
willy tarreau9fe663a2005-12-17 13:02:59 +01005353 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005354 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005355 return 0;
5356 }
5357
5358 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005359 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005360 return -1;
5361 }
5362
5363 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
5364 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005365 else if (!strcmp(args[0], "errorloc")) { /* error location */
5366 int errnum;
5367 char *err;
5368
willy tarreaueedaa9f2005-12-17 14:08:03 +01005369 // if (curproxy == &defproxy) {
5370 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5371 // return -1;
5372 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005373
willy tarreau8337c6b2005-12-17 13:41:01 +01005374 if (*(args[2]) == 0) {
5375 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
5376 return -1;
5377 }
5378
5379 errnum = atol(args[1]);
5380 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
5381 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
5382
5383 if (errnum == 400) {
5384 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005385 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005386 free(curproxy->errmsg.msg400);
5387 }
5388 curproxy->errmsg.msg400 = err;
5389 curproxy->errmsg.len400 = strlen(err);
5390 }
5391 else if (errnum == 403) {
5392 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005393 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005394 free(curproxy->errmsg.msg403);
5395 }
5396 curproxy->errmsg.msg403 = err;
5397 curproxy->errmsg.len403 = strlen(err);
5398 }
5399 else if (errnum == 408) {
5400 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005401 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005402 free(curproxy->errmsg.msg408);
5403 }
5404 curproxy->errmsg.msg408 = err;
5405 curproxy->errmsg.len408 = strlen(err);
5406 }
5407 else if (errnum == 500) {
5408 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005409 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005410 free(curproxy->errmsg.msg500);
5411 }
5412 curproxy->errmsg.msg500 = err;
5413 curproxy->errmsg.len500 = strlen(err);
5414 }
5415 else if (errnum == 502) {
5416 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005417 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005418 free(curproxy->errmsg.msg502);
5419 }
5420 curproxy->errmsg.msg502 = err;
5421 curproxy->errmsg.len502 = strlen(err);
5422 }
5423 else if (errnum == 503) {
5424 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005425 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005426 free(curproxy->errmsg.msg503);
5427 }
5428 curproxy->errmsg.msg503 = err;
5429 curproxy->errmsg.len503 = strlen(err);
5430 }
5431 else if (errnum == 504) {
5432 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005433 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01005434 free(curproxy->errmsg.msg504);
5435 }
5436 curproxy->errmsg.msg504 = err;
5437 curproxy->errmsg.len504 = strlen(err);
5438 }
5439 else {
5440 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
5441 free(err);
5442 }
5443 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005444 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005445 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01005446 return -1;
5447 }
5448 return 0;
5449}
willy tarreaue39cd132005-12-17 13:00:18 +01005450
willy tarreau5cbea6f2005-12-17 12:48:26 +01005451
willy tarreau9fe663a2005-12-17 13:02:59 +01005452/*
5453 * This function reads and parses the configuration file given in the argument.
5454 * returns 0 if OK, -1 if error.
5455 */
5456int readcfgfile(char *file) {
5457 char thisline[256];
5458 char *line;
5459 FILE *f;
5460 int linenum = 0;
5461 char *end;
5462 char *args[MAX_LINE_ARGS];
5463 int arg;
5464 int cfgerr = 0;
5465 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01005466
willy tarreau9fe663a2005-12-17 13:02:59 +01005467 struct proxy *curproxy = NULL;
5468 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005469
willy tarreau9fe663a2005-12-17 13:02:59 +01005470 if ((f=fopen(file,"r")) == NULL)
5471 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01005472
willy tarreaueedaa9f2005-12-17 14:08:03 +01005473 init_default_instance();
5474
willy tarreau9fe663a2005-12-17 13:02:59 +01005475 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
5476 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005477
willy tarreau9fe663a2005-12-17 13:02:59 +01005478 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005479
willy tarreau9fe663a2005-12-17 13:02:59 +01005480 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01005481 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01005482 line++;
5483
5484 arg = 0;
5485 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01005486
willy tarreau9fe663a2005-12-17 13:02:59 +01005487 while (*line && arg < MAX_LINE_ARGS) {
5488 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
5489 * C equivalent value. Other combinations left unchanged (eg: \1).
5490 */
5491 if (*line == '\\') {
5492 int skip = 0;
5493 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
5494 *line = line[1];
5495 skip = 1;
5496 }
5497 else if (line[1] == 'r') {
5498 *line = '\r';
5499 skip = 1;
5500 }
5501 else if (line[1] == 'n') {
5502 *line = '\n';
5503 skip = 1;
5504 }
5505 else if (line[1] == 't') {
5506 *line = '\t';
5507 skip = 1;
5508 }
5509 else if (line[1] == 'x' && (line + 3 < end )) {
5510 unsigned char hex1, hex2;
5511 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
5512 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
5513 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
5514 *line = (hex1<<4) + hex2;
5515 skip = 3;
5516 }
5517 if (skip) {
5518 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
5519 end -= skip;
5520 }
5521 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005522 }
willy tarreaua1598082005-12-17 13:08:06 +01005523 else if (*line == '#' || *line == '\n' || *line == '\r') {
5524 /* end of string, end of loop */
5525 *line = 0;
5526 break;
5527 }
willy tarreauc29948c2005-12-17 13:10:27 +01005528 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005529 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01005530 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01005531 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01005532 line++;
5533 args[++arg] = line;
5534 }
5535 else {
5536 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01005537 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005538 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005539
willy tarreau9fe663a2005-12-17 13:02:59 +01005540 /* empty line */
5541 if (!**args)
5542 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01005543
willy tarreau9fe663a2005-12-17 13:02:59 +01005544 /* zero out remaining args */
5545 while (++arg < MAX_LINE_ARGS) {
5546 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005547 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005548
willy tarreaua41a8b42005-12-17 14:02:24 +01005549 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01005550 confsect = CFG_LISTEN;
5551 else if (!strcmp(args[0], "global")) /* global config */
5552 confsect = CFG_GLOBAL;
5553 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005554
willy tarreau9fe663a2005-12-17 13:02:59 +01005555 switch (confsect) {
5556 case CFG_LISTEN:
5557 if (cfg_parse_listen(file, linenum, args) < 0)
5558 return -1;
5559 break;
5560 case CFG_GLOBAL:
5561 if (cfg_parse_global(file, linenum, args) < 0)
5562 return -1;
5563 break;
5564 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01005565 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005566 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005567 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005568
5569
willy tarreau0f7af912005-12-17 12:21:26 +01005570 }
5571 fclose(f);
5572
5573 /*
5574 * Now, check for the integrity of all that we have collected.
5575 */
5576
5577 if ((curproxy = proxy) == NULL) {
5578 Alert("parsing %s : no <listen> line. Nothing to do !\n",
5579 file);
5580 return -1;
5581 }
5582
5583 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01005584 if (curproxy->state == PR_STDISABLED) {
5585 curproxy = curproxy->next;
5586 continue;
5587 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005588 if ((curproxy->mode != PR_MODE_HEALTH) &&
5589 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01005590 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005591 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
5592 file, curproxy->id);
5593 cfgerr++;
5594 }
5595 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
5596 if (curproxy->options & PR_O_TRANSP) {
5597 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
5598 file, curproxy->id);
5599 cfgerr++;
5600 }
5601 else if (curproxy->srv == NULL) {
5602 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
5603 file, curproxy->id);
5604 cfgerr++;
5605 }
willy tarreaua1598082005-12-17 13:08:06 +01005606 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005607 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
5608 file, curproxy->id);
5609 }
5610 }
5611 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01005612 if (curproxy->cookie_name != NULL) {
5613 Warning("parsing %s : cookie will be ignored for listener %s.\n",
5614 file, curproxy->id);
5615 }
5616 if ((newsrv = curproxy->srv) != NULL) {
5617 Warning("parsing %s : servers will be ignored for listener %s.\n",
5618 file, curproxy->id);
5619 }
willy tarreaue39cd132005-12-17 13:00:18 +01005620 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005621 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
5622 file, curproxy->id);
5623 }
willy tarreaue39cd132005-12-17 13:00:18 +01005624 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01005625 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
5626 file, curproxy->id);
5627 }
5628 }
5629 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
5630 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
5631 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
5632 file, curproxy->id);
5633 cfgerr++;
5634 }
5635 else {
5636 while (newsrv != NULL) {
5637 /* nothing to check for now */
5638 newsrv = newsrv->next;
5639 }
5640 }
5641 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005642 if (curproxy->errmsg.msg400 == NULL) {
5643 curproxy->errmsg.msg400 = (char *)HTTP_400;
5644 curproxy->errmsg.len400 = strlen(HTTP_400);
5645 }
5646 if (curproxy->errmsg.msg403 == NULL) {
5647 curproxy->errmsg.msg403 = (char *)HTTP_403;
5648 curproxy->errmsg.len403 = strlen(HTTP_403);
5649 }
5650 if (curproxy->errmsg.msg408 == NULL) {
5651 curproxy->errmsg.msg408 = (char *)HTTP_408;
5652 curproxy->errmsg.len408 = strlen(HTTP_408);
5653 }
5654 if (curproxy->errmsg.msg500 == NULL) {
5655 curproxy->errmsg.msg500 = (char *)HTTP_500;
5656 curproxy->errmsg.len500 = strlen(HTTP_500);
5657 }
5658 if (curproxy->errmsg.msg502 == NULL) {
5659 curproxy->errmsg.msg502 = (char *)HTTP_502;
5660 curproxy->errmsg.len502 = strlen(HTTP_502);
5661 }
5662 if (curproxy->errmsg.msg503 == NULL) {
5663 curproxy->errmsg.msg503 = (char *)HTTP_503;
5664 curproxy->errmsg.len503 = strlen(HTTP_503);
5665 }
5666 if (curproxy->errmsg.msg504 == NULL) {
5667 curproxy->errmsg.msg504 = (char *)HTTP_504;
5668 curproxy->errmsg.len504 = strlen(HTTP_504);
5669 }
willy tarreau0f7af912005-12-17 12:21:26 +01005670 curproxy = curproxy->next;
5671 }
5672 if (cfgerr > 0) {
5673 Alert("Errors found in configuration file, aborting.\n");
5674 return -1;
5675 }
5676 else
5677 return 0;
5678}
5679
5680
5681/*
5682 * This function initializes all the necessary variables. It only returns
5683 * if everything is OK. If something fails, it exits.
5684 */
5685void init(int argc, char **argv) {
5686 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01005687 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01005688 char *old_argv = *argv;
5689 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01005690 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01005691 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01005692
5693 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005694 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005695 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
5696 sizeof(int)*8);
5697 exit(1);
5698 }
5699
5700 pid = getpid();
5701 progname = *argv;
5702 while ((tmp = strchr(progname, '/')) != NULL)
5703 progname = tmp + 1;
5704
5705 argc--; argv++;
5706 while (argc > 0) {
5707 char *flag;
5708
5709 if (**argv == '-') {
5710 flag = *argv+1;
5711
5712 /* 1 arg */
5713 if (*flag == 'v') {
5714 display_version();
5715 exit(0);
5716 }
5717 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01005718 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01005719 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01005720 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005721 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01005722 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01005723#if STATTIME > 0
5724 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01005725 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01005726 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01005727 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01005728#endif
5729 else { /* >=2 args */
5730 argv++; argc--;
5731 if (argc == 0)
5732 usage(old_argv);
5733
5734 switch (*flag) {
5735 case 'n' : cfg_maxconn = atol(*argv); break;
5736 case 'N' : cfg_maxpconn = atol(*argv); break;
5737 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01005738 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01005739 default: usage(old_argv);
5740 }
5741 }
5742 }
5743 else
5744 usage(old_argv);
5745 argv++; argc--;
5746 }
5747
willy tarreau0f7af912005-12-17 12:21:26 +01005748 if (!cfg_cfgfile)
5749 usage(old_argv);
5750
5751 gethostname(hostname, MAX_HOSTNAME_LEN);
5752
5753 if (readcfgfile(cfg_cfgfile) < 0) {
5754 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
5755 exit(1);
5756 }
5757
willy tarreau9fe663a2005-12-17 13:02:59 +01005758 if (cfg_maxconn > 0)
5759 global.maxconn = cfg_maxconn;
5760
willy tarreaufe2c5c12005-12-17 14:14:34 +01005761 if (cfg_pidfile) {
5762 if (global.pidfile)
5763 free(global.pidfile);
5764 global.pidfile = strdup(cfg_pidfile);
5765 }
5766
willy tarreau9fe663a2005-12-17 13:02:59 +01005767 if (global.maxconn == 0)
5768 global.maxconn = DEFAULT_MAXCONN;
5769
5770 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
5771
5772 if (arg_mode & MODE_DEBUG) {
5773 /* command line debug mode inhibits configuration mode */
5774 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5775 }
willy tarreau750a4722005-12-17 13:21:24 +01005776 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01005777
5778 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
5779 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
5780 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5781 }
5782
5783 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
5784 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
5785 global.nbproc = 1;
5786 }
5787
5788 if (global.nbproc < 1)
5789 global.nbproc = 1;
5790
willy tarreau0f7af912005-12-17 12:21:26 +01005791 ReadEvent = (fd_set *)calloc(1,
5792 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005793 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005794 WriteEvent = (fd_set *)calloc(1,
5795 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005796 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005797 StaticReadEvent = (fd_set *)calloc(1,
5798 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005799 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005800 StaticWriteEvent = (fd_set *)calloc(1,
5801 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005802 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005803
5804 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01005805 sizeof(struct fdtab) * (global.maxsock));
5806 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01005807 fdtab[i].state = FD_STCLOSE;
5808 }
5809}
5810
5811/*
5812 * this function starts all the proxies. It returns 0 if OK, -1 if not.
5813 */
5814int start_proxies() {
5815 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01005816 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01005817 int one = 1;
5818 int fd;
5819
5820 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01005821 if (curproxy->state == PR_STDISABLED)
5822 continue;
5823
willy tarreaua41a8b42005-12-17 14:02:24 +01005824 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
5825 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01005826 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005827 Alert("cannot create listening socket for proxy %s. Aborting.\n",
5828 curproxy->id);
5829 return -1;
5830 }
willy tarreau0f7af912005-12-17 12:21:26 +01005831
willy tarreaua41a8b42005-12-17 14:02:24 +01005832 if (fd >= global.maxsock) {
5833 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
5834 curproxy->id);
5835 close(fd);
5836 return -1;
5837 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005838
willy tarreaua41a8b42005-12-17 14:02:24 +01005839 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
5840 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
5841 (char *) &one, sizeof(one)) == -1)) {
5842 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
5843 curproxy->id);
5844 close(fd);
5845 return -1;
5846 }
willy tarreau0f7af912005-12-17 12:21:26 +01005847
willy tarreaua41a8b42005-12-17 14:02:24 +01005848 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
5849 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
5850 curproxy->id);
5851 }
willy tarreau0f7af912005-12-17 12:21:26 +01005852
willy tarreaua41a8b42005-12-17 14:02:24 +01005853 if (bind(fd,
5854 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01005855 listener->addr.ss_family == AF_INET6 ?
5856 sizeof(struct sockaddr_in6) :
5857 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005858 Alert("cannot bind socket for proxy %s. Aborting.\n",
5859 curproxy->id);
5860 close(fd);
5861 return -1;
5862 }
willy tarreau0f7af912005-12-17 12:21:26 +01005863
willy tarreaua41a8b42005-12-17 14:02:24 +01005864 if (listen(fd, curproxy->maxconn) == -1) {
5865 Alert("cannot listen to socket for proxy %s. Aborting.\n",
5866 curproxy->id);
5867 close(fd);
5868 return -1;
5869 }
willy tarreau0f7af912005-12-17 12:21:26 +01005870
willy tarreaua41a8b42005-12-17 14:02:24 +01005871 /* the function for the accept() event */
5872 fdtab[fd].read = &event_accept;
5873 fdtab[fd].write = NULL; /* never called */
5874 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
5875 curproxy->state = PR_STRUN;
5876 fdtab[fd].state = FD_STLISTEN;
5877 FD_SET(fd, StaticReadEvent);
5878 fd_insert(fd);
5879 listeners++;
5880 }
willy tarreaua1598082005-12-17 13:08:06 +01005881 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005882 }
5883 return 0;
5884}
5885
5886
5887int main(int argc, char **argv) {
willy tarreaufe2c5c12005-12-17 14:14:34 +01005888 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01005889 init(argc, argv);
5890
willy tarreau9fe663a2005-12-17 13:02:59 +01005891 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01005892 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005893 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01005894 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01005895 }
5896
5897 signal(SIGQUIT, dump);
5898 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01005899 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005900
5901 /* on very high loads, a sigpipe sometimes happen just between the
5902 * getsockopt() which tells "it's OK to write", and the following write :-(
5903 */
willy tarreau3242e862005-12-17 12:27:53 +01005904#ifndef MSG_NOSIGNAL
5905 signal(SIGPIPE, SIG_IGN);
5906#endif
willy tarreau0f7af912005-12-17 12:21:26 +01005907
5908 if (start_proxies() < 0)
5909 exit(1);
5910
willy tarreaufe2c5c12005-12-17 14:14:34 +01005911 /* open log & pid files before the chroot */
5912 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
5913 int pidfd;
5914 unlink(global.pidfile);
5915 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
5916 if (pidfd < 0) {
5917 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
5918 exit(1);
5919 }
5920 pidfile = fdopen(pidfd, "w");
5921 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005922
5923 /* chroot if needed */
5924 if (global.chroot != NULL) {
5925 if (chroot(global.chroot) == -1) {
5926 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
5927 exit(1);
5928 }
5929 chdir("/");
5930 }
5931
5932 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01005933 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005934 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
5935 exit(1);
5936 }
5937
willy tarreau036e1ce2005-12-17 13:46:33 +01005938 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005939 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
5940 exit(1);
5941 }
5942
5943 if (global.mode & MODE_DAEMON) {
5944 int ret = 0;
5945 int proc;
5946
5947 /* the father launches the required number of processes */
5948 for (proc = 0; proc < global.nbproc; proc++) {
5949 ret = fork();
5950 if (ret < 0) {
5951 Alert("[%s.main()] Cannot fork.\n", argv[0]);
5952 exit(1); /* there has been an error */
5953 }
5954 else if (ret == 0) /* child breaks here */
5955 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01005956 if (pidfile != NULL) {
5957 fprintf(pidfile, "%d\n", ret);
5958 fflush(pidfile);
5959 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005960 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005961 /* close the pidfile both in children and father */
5962 if (pidfile != NULL)
5963 fclose(pidfile);
5964 free(global.pidfile);
5965
willy tarreau9fe663a2005-12-17 13:02:59 +01005966 if (proc == global.nbproc)
5967 exit(0); /* parent must leave */
5968
willy tarreau750a4722005-12-17 13:21:24 +01005969 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
5970 * that we can detach from the TTY. We MUST NOT do it in other cases since
5971 * it would have already be done, and 0-2 would have been affected to listening
5972 * sockets
5973 */
5974 if (!(global.mode & MODE_QUIET)) {
5975 /* detach from the tty */
5976 fclose(stdin); fclose(stdout); fclose(stderr);
5977 close(0); close(1); close(2); /* close all fd's */
5978 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
5979 }
willy tarreaua1598082005-12-17 13:08:06 +01005980 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01005981 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01005982 }
5983
willy tarreau0f7af912005-12-17 12:21:26 +01005984 select_loop();
5985
5986 exit(0);
5987}