blob: e6721d7cc76660e26c23585774a81e878997df33 [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
3 * 2000-2002 - 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 tarreauef900ab2005-12-17 12:52:52 +010010 * Pending bugs :
willy tarreaua1598082005-12-17 13:08:06 +010011 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
12 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010013 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
14 * the snprintf() bug since requests we simple (GET / HTTP/1.0).
willy tarreauef900ab2005-12-17 12:52:52 +010015 * - cookie in insert+indirect mode sometimes segfaults !
16 * - a proxy with an invalid config will prevent the startup even if disabled.
17 *
willy tarreau0f7af912005-12-17 12:21:26 +010018 * ChangeLog :
19 *
willy tarreau240afa62005-12-17 13:14:35 +010020 * 2002/06/04 : 1.1.11
21 * - fixed multi-cookie handling in client request to allow clean deletion
22 * in insert+indirect mode. Now, only the server cookie is deleted and not
23 * all the header. Should now be compliant to RFC2109.
24 * - added a "nocache" option to "cookie" to specify that we explicitly want
25 * to add a "cache-control" header when we add a cookie.
26 * It is also possible to add an "Expires: <old-date>" to keep compatibility
27 * with old/broken caches.
willy tarreau96d40372005-12-17 13:11:56 +010028 * 2002/05/10 : 1.1.10
29 * - if a cookie is used in insert+indirect mode, it's desirable that the
30 * the servers don't see it. It was not possible to remove it correctly
31 * with regexps, so now it's removed automatically.
willy tarreauc29948c2005-12-17 13:10:27 +010032 * 2002/04/19 : 1.1.9
33 * - don't use snprintf()'s return value as an end of message since it may
34 * be larger. This caused bus errors and segfaults in internal libc's
35 * getenv() during localtime() in send_log().
36 * - removed dead insecure send_syslog() function and all references to it.
37 * - fixed warnings on Solaris due to buggy implementation of isXXXX().
willy tarreaua1598082005-12-17 13:08:06 +010038 * 2002/04/18 : 1.1.8
39 * - option "dontlognull"
40 * - fixed "double space" bug in config parser
41 * - fixed an uninitialized server field in case of dispatch
42 * with no existing server which could cause a segfault during
43 * logging.
44 * - the pid logged was always the father's, which was wrong for daemons.
45 * - fixed wrong level "LOG_INFO" for message "proxy started".
46 * 2002/04/13 :
47 * - http logging is now complete :
48 * - ip:port, date, proxy, server
49 * - req_time, conn_time, hdr_time, tot_time
50 * - status, size, request
51 * - source address
willy tarreau9fe663a2005-12-17 13:02:59 +010052 * 2002/04/12 : 1.1.7
53 * - added option forwardfor
54 * - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel
55 * - added "log global" in "listen" section.
56 * 2002/04/09 :
57 * - added a new "global" section :
58 * - logs
59 * - debug, quiet, daemon modes
60 * - uid, gid, chroot, nbproc, maxconn
willy tarreaue39cd132005-12-17 13:00:18 +010061 * 2002/04/08 : 1.1.6
62 * - regex are now chained and not limited anymore.
63 * - unavailable server now returns HTTP/502.
64 * - increased per-line args limit to 40
65 * - added reqallow/reqdeny to block some request on matches
66 * - added HTTP 400/403 responses
67 * 2002/04/03 : 1.1.5
willy tarreau535ae7a2005-12-17 12:58:00 +010068 * - connection logging displayed incorrect source address.
69 * - added proxy start/stop and server up/down log events.
70 * - replaced log message short buffers with larger trash.
71 * - enlarged buffer to 8 kB and replace buffer to 4 kB.
willy tarreaue39cd132005-12-17 13:00:18 +010072 * 2002/03/25 : 1.1.4
willy tarreaue47c8d72005-12-17 12:55:52 +010073 * - made rise/fall/interval time configurable
willy tarreaue39cd132005-12-17 13:00:18 +010074 * 2002/03/22 : 1.1.3
willy tarreaub719f002005-12-17 12:55:07 +010075 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
76 * which could lead to loops.
willy tarreaue39cd132005-12-17 13:00:18 +010077 * 2002/03/21 : 1.1.2
willy tarreauef900ab2005-12-17 12:52:52 +010078 * - fixed a bug in buffer management where we could have a loop
79 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
80 * => implemented an adjustable buffer limit.
81 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
82 * and running tasks are skipped.
83 * - added some debug lines for accept events.
84 * - send warnings for servers up/down.
willy tarreaue39cd132005-12-17 13:00:18 +010085 * 2002/03/12 : 1.1.1
willy tarreauefae1842005-12-17 12:51:03 +010086 * - fixed a bug in total failure handling
87 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreaue39cd132005-12-17 13:00:18 +010088 * 2002/03/10 : 1.1.0
willy tarreau5cbea6f2005-12-17 12:48:26 +010089 * - fixed a few timeout bugs
90 * - rearranged the task scheduler subsystem to improve performance,
91 * add new tasks, and make it easier to later port to librt ;
92 * - allow multiple accept() for one select() wake up ;
93 * - implemented internal load balancing with basic health-check ;
94 * - cookie insertion and header add/replace/delete, with better strings
95 * support.
96 * 2002/03/08
97 * - reworked buffer handling to fix a few rewrite bugs, and
98 * improve overall performance.
99 * - implement the "purge" option to delete server cookies in direct mode.
100 * 2002/03/07
101 * - fixed some error cases where the maxfd was not decreased.
102 * 2002/02/26
103 * - now supports transparent proxying, at least on linux 2.4.
104 * 2002/02/12
105 * - soft stop works again (fixed select timeout computation).
106 * - it seems that TCP proxies sometimes cannot timeout.
107 * - added a "quiet" mode.
108 * - enforce file descriptor limitation on socket() and accept().
109 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +0100110 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +0100111 * 2001/12/16 : release of version 1.0.0.
112 * 2001/12/16 : added syslog capability for each accepted connection.
113 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
114 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
115 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
116 * with or without cookies (use keyword http for this).
117 * 2001/09/01 : added client/server header replacing with regexps.
118 * eg:
119 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
120 * srvexp ^Server:\ .* Server:\ Apache
121 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
122 * 2000/11/28 : major rewrite
123 * 2000/11/26 : first write
124 *
willy tarreau5cbea6f2005-12-17 12:48:26 +0100125 * TODO:
126 * - handle properly intermediate incomplete server headers. Done ?
127 * - log proxies start/stop
128 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +0100129 *
130 */
131
132#include <stdio.h>
133#include <stdlib.h>
134#include <unistd.h>
135#include <string.h>
136#include <ctype.h>
137#include <sys/time.h>
138#include <sys/types.h>
139#include <sys/socket.h>
140#include <netinet/tcp.h>
141#include <netinet/in.h>
142#include <arpa/inet.h>
143#include <netdb.h>
144#include <fcntl.h>
145#include <errno.h>
146#include <signal.h>
147#include <stdarg.h>
148#include <sys/resource.h>
149#include <time.h>
150#include <regex.h>
151#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +0100152#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100153#include <linux/netfilter_ipv4.h>
154#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100155
willy tarreau240afa62005-12-17 13:14:35 +0100156#define HAPROXY_VERSION "1.1.11"
157#define HAPROXY_DATE "2002/06/04"
willy tarreau0f7af912005-12-17 12:21:26 +0100158
159/* this is for libc5 for example */
160#ifndef TCP_NODELAY
161#define TCP_NODELAY 1
162#endif
163
164#ifndef SHUT_RD
165#define SHUT_RD 0
166#endif
167
168#ifndef SHUT_WR
169#define SHUT_WR 1
170#endif
171
willy tarreau535ae7a2005-12-17 12:58:00 +0100172#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +0100173
174// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +0100175#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +0100176#define REQURI_LEN 1024
willy tarreau0f7af912005-12-17 12:21:26 +0100177
willy tarreau5cbea6f2005-12-17 12:48:26 +0100178// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100179#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100180
willy tarreaue39cd132005-12-17 13:00:18 +0100181// max # of added headers per request
182#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100183
184// max # of matches per regexp
185#define MAX_MATCH 10
186
willy tarreau5cbea6f2005-12-17 12:48:26 +0100187/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100188#define COOKIENAME_LEN 16
189#define SERVERID_LEN 16
190#define CONN_RETRIES 3
191
willy tarreau5cbea6f2005-12-17 12:48:26 +0100192#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100193#define DEF_CHKINTR 2000
194#define DEF_FALLTIME 3
195#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100196
willy tarreau9fe663a2005-12-17 13:02:59 +0100197/* default connections limit */
198#define DEFAULT_MAXCONN 2000
199
willy tarreau0f7af912005-12-17 12:21:26 +0100200/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
201#define INTBITS 5
202
203/* show stats this every millisecond, 0 to disable */
204#ifndef STATTIME
205#define STATTIME 2000
206#endif
207
willy tarreau5cbea6f2005-12-17 12:48:26 +0100208/* this reduces the number of calls to select() by choosing appropriate
209 * sheduler precision in milliseconds. It should be near the minimum
210 * time that is needed by select() to collect all events. All timeouts
211 * are rounded up by adding this value prior to pass it to select().
212 */
213#define SCHEDULER_RESOLUTION 9
214
willy tarreau0f7af912005-12-17 12:21:26 +0100215#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
216#define SETNOW(a) (*a=now)
217
willy tarreau9da061b2005-12-17 12:29:56 +0100218/****** string-specific macros and functions ******/
219/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
220#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
221
222/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
223#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
224
225
226#ifndef HAVE_STRLCPY
227/*
228 * copies at most <size-1> chars from <src> to <dst>. Last char is always
229 * set to 0, unless <size> is 0. The number of chars copied is returned
230 * (excluding the terminating zero).
231 * This code has been optimized for size and speed : on x86, it's 45 bytes
232 * long, uses only registers, and consumes only 4 cycles per char.
233 */
234int strlcpy(char *dst, const char *src, int size) {
235 char *orig = dst;
236 if (size) {
237 while (--size && (*dst = *src)) {
238 src++; dst++;
239 }
240 *dst = 0;
241 }
242 return dst - orig;
243}
244#endif
245
246
willy tarreau0f7af912005-12-17 12:21:26 +0100247#define MEM_OPTIM
248#ifdef MEM_OPTIM
249/*
250 * Returns a pointer to type <type> taken from the
251 * pool <pool_type> or dynamically allocated. In the
252 * first case, <pool_type> is updated to point to the
253 * next element in the list.
254 */
255#define pool_alloc(type) ({ \
256 void *p; \
257 if ((p = pool_##type) == NULL) \
258 p = malloc(sizeof_##type); \
259 else { \
260 pool_##type = *(void **)pool_##type; \
261 } \
262 p; \
263})
264
265/*
266 * Puts a memory area back to the corresponding pool.
267 * Items are chained directly through a pointer that
268 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100269 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100270 * that each memory area is at least as big as one
271 * pointer.
272 */
273#define pool_free(type, ptr) ({ \
274 *(void **)ptr = (void *)pool_##type; \
275 pool_##type = (void *)ptr; \
276})
277
278#else
279#define pool_alloc(type) (calloc(1,sizeof_##type));
280#define pool_free(type, ptr) (free(ptr));
281#endif /* MEM_OPTIM */
282
willy tarreau5cbea6f2005-12-17 12:48:26 +0100283#define sizeof_task sizeof(struct task)
284#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100285#define sizeof_buffer sizeof(struct buffer)
286#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100287#define sizeof_requri REQURI_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100288
willy tarreau5cbea6f2005-12-17 12:48:26 +0100289/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100290#define FD_STCLOSE 0
291#define FD_STLISTEN 1
292#define FD_STCONN 2
293#define FD_STREADY 3
294#define FD_STERROR 4
295
willy tarreau5cbea6f2005-12-17 12:48:26 +0100296/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100297#define TASK_IDLE 0
298#define TASK_RUNNING 1
299
willy tarreau5cbea6f2005-12-17 12:48:26 +0100300/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100301#define PR_STNEW 0
302#define PR_STIDLE 1
303#define PR_STRUN 2
304#define PR_STDISABLED 3
305
willy tarreau5cbea6f2005-12-17 12:48:26 +0100306/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100307#define PR_MODE_TCP 0
308#define PR_MODE_HTTP 1
309#define PR_MODE_HEALTH 2
310
willy tarreau5cbea6f2005-12-17 12:48:26 +0100311/* bits for proxy->options */
312#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
313#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
314#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
315#define PR_O_COOK_IND 8 /* keep only indirect cookies */
316#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
317#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
318#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
319#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100320#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
321#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100322#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
323#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100324#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreau9fe663a2005-12-17 13:02:59 +0100325
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326
willy tarreaue39cd132005-12-17 13:00:18 +0100327/* various session flags */
328#define SN_DIRECT 1 /* connection made on the server matching the client cookie */
329#define SN_CLDENY 2 /* a client header matches a deny regex */
330#define SN_CLALLOW 4 /* a client header matches an allow regex */
331#define SN_SVDENY 8 /* a server header matches a deny regex */
332#define SN_SVALLOW 16 /* a server header matches an allow regex */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100333
334/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100335#define CL_STHEADERS 0
336#define CL_STDATA 1
337#define CL_STSHUTR 2
338#define CL_STSHUTW 3
339#define CL_STCLOSE 4
340
willy tarreau5cbea6f2005-12-17 12:48:26 +0100341/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100342#define SV_STIDLE 0
343#define SV_STCONN 1
344#define SV_STHEADERS 2
345#define SV_STDATA 3
346#define SV_STSHUTR 4
347#define SV_STSHUTW 5
348#define SV_STCLOSE 6
349
350/* result of an I/O event */
351#define RES_SILENT 0 /* didn't happen */
352#define RES_DATA 1 /* data were sent or received */
353#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
354#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
355
willy tarreau9fe663a2005-12-17 13:02:59 +0100356/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100357#define MODE_DEBUG 1
358#define MODE_STATS 2
359#define MODE_LOG 4
360#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100361#define MODE_QUIET 16
362
363/* server flags */
364#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100365
willy tarreaue39cd132005-12-17 13:00:18 +0100366/* what to do when a header matches a regex */
367#define ACT_ALLOW 0 /* allow the request */
368#define ACT_REPLACE 1 /* replace the matching header */
369#define ACT_REMOVE 2 /* remove the matching header */
370#define ACT_DENY 3 /* deny the request */
371
willy tarreau9fe663a2005-12-17 13:02:59 +0100372/* configuration sections */
373#define CFG_NONE 0
374#define CFG_GLOBAL 1
375#define CFG_LISTEN 2
376
willy tarreaua1598082005-12-17 13:08:06 +0100377/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100378#define LW_DATE 1 /* date */
379#define LW_CLIP 2 /* CLient IP */
380#define LW_SVIP 4 /* SerVer IP */
381#define LW_SVID 8 /* server ID */
382#define LW_REQ 16 /* http REQuest */
383#define LW_RESP 32 /* http RESPonse */
384#define LW_PXIP 64 /* proxy IP */
385#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100386#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100387
willy tarreau0f7af912005-12-17 12:21:26 +0100388/*********************************************************************/
389
390#define LIST_HEAD(a) ((void *)(&(a)))
391
392/*********************************************************************/
393
394struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100395 struct hdr_exp *next;
396 regex_t *preg; /* expression to look for */
397 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
398 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100399};
400
401struct buffer {
402 unsigned int l; /* data length */
403 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100404 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100405 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100406 char data[BUFSIZE];
407};
408
409struct server {
410 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100411 int state; /* server state (SRV_*) */
412 int cklen; /* the len of the cookie, to speed up checks */
413 char *cookie; /* the id set in the cookie */
414 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100415 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100416 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100417 int rise, fall; /* time in iterations */
418 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100419 int result; /* 0 = connect OK, -1 = connect KO */
420 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100421 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100422};
423
willy tarreau5cbea6f2005-12-17 12:48:26 +0100424/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100425struct task {
426 struct task *next, *prev; /* chaining ... */
427 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100428 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100429 int state; /* task state : IDLE or RUNNING */
430 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100431 int (*process)(struct task *t); /* the function which processes the task */
432 void *context; /* the task's context */
433};
434
435/* WARNING: if new fields are added, they must be initialized in event_accept() */
436struct session {
437 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100438 /* application specific below */
439 struct timeval crexpire; /* expiration date for a client read */
440 struct timeval cwexpire; /* expiration date for a client write */
441 struct timeval srexpire; /* expiration date for a server read */
442 struct timeval swexpire; /* expiration date for a server write */
443 struct timeval cnexpire; /* expiration date for a connect */
444 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
445 struct proxy *proxy; /* the proxy this socket belongs to */
446 int cli_fd; /* the client side fd */
447 int srv_fd; /* the server side fd */
448 int cli_state; /* state of the client side */
449 int srv_state; /* state of the server side */
450 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100451 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100452 struct buffer *req; /* request buffer */
453 struct buffer *rep; /* response buffer */
454 struct sockaddr_in cli_addr; /* the client address */
455 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100456 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100457 struct {
458 int logwait; /* log fields waiting to be collected : LW_* */
459 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
460 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
461 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
462 long t_data; /* delay before the first data byte from the server ... */
463 unsigned long t_close; /* total session duration */
464 char *uri; /* first line if log needed, NULL otherwise */
465 int status; /* HTTP status from the server, negative if from proxy */
466 long long bytes; /* number of bytes transferred from the server */
467 } logs;
willy tarreau0f7af912005-12-17 12:21:26 +0100468};
469
470struct proxy {
471 int listen_fd; /* the listen socket */
472 int state; /* proxy state */
473 struct sockaddr_in listen_addr; /* the address we listen to */
474 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100475 struct server *srv, *cursrv; /* known servers, current server */
476 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100477 char *cookie_name; /* name of the cookie to look for */
478 int clitimeout; /* client I/O timeout (in milliseconds) */
479 int srvtimeout; /* server I/O timeout (in milliseconds) */
480 int contimeout; /* connect timeout (in milliseconds) */
481 char *id; /* proxy id */
482 int nbconn; /* # of active sessions */
483 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100484 int conn_retries; /* maximum number of connect retries */
485 int options; /* PR_O_REDISP, PR_O_TRANSP */
486 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100487 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100488 struct proxy *next;
489 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
490 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau9fe663a2005-12-17 13:02:59 +0100491 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100492 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100493 int nb_reqadd, nb_rspadd;
494 struct hdr_exp *req_exp; /* regular expressions for request headers */
495 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
496 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100497 int grace; /* grace time after stop request */
498};
499
500/* info about one given fd */
501struct fdtab {
502 int (*read)(int fd); /* read function */
503 int (*write)(int fd); /* write function */
504 struct task *owner; /* the session (or proxy) associated with this fd */
505 int state; /* the state of this fd */
506};
507
508/*********************************************************************/
509
willy tarreau0f7af912005-12-17 12:21:26 +0100510int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100511char *cfg_cfgfile = NULL; /* configuration file */
512char *progname = NULL; /* program name */
513int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100514
515/* global options */
516static struct {
517 int uid;
518 int gid;
519 int nbproc;
520 int maxconn;
521 int maxsock; /* max # of sockets */
522 int mode;
523 char *chroot;
524 int logfac1, logfac2;
525 struct sockaddr_in logsrv1, logsrv2;
526} global = {
527 logfac1 : -1,
528 logfac2 : -1,
529 /* others NULL OK */
530};
531
willy tarreau0f7af912005-12-17 12:21:26 +0100532/*********************************************************************/
533
534fd_set *ReadEvent,
535 *WriteEvent,
536 *StaticReadEvent,
537 *StaticWriteEvent;
538
539void **pool_session = NULL,
540 **pool_buffer = NULL,
541 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100542 **pool_requri = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100543 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100544
545struct proxy *proxy = NULL; /* list of all existing proxies */
546struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100547struct task *rq = NULL; /* global run queue */
548struct task wait_queue = { /* global wait queue */
549 prev:LIST_HEAD(wait_queue),
550 next:LIST_HEAD(wait_queue)
551};
willy tarreau0f7af912005-12-17 12:21:26 +0100552
willy tarreau0f7af912005-12-17 12:21:26 +0100553static int totalconn = 0; /* total # of terminated sessions */
554static int actconn = 0; /* # of active sessions */
555static int maxfd = 0; /* # of the highest fd + 1 */
556static int listeners = 0; /* # of listeners */
557static int stopping = 0; /* non zero means stopping in progress */
558static struct timeval now = {0,0}; /* the current date at any moment */
559
560static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
561static char trash[BUFSIZE];
562
563/*
564 * Syslog facilities and levels
565 */
566
567#define MAX_SYSLOG_LEN 1024
568#define NB_LOG_FACILITIES 24
569const char *log_facilities[NB_LOG_FACILITIES] = {
570 "kern", "user", "mail", "daemon",
571 "auth", "syslog", "lpr", "news",
572 "uucp", "cron", "auth2", "ftp",
573 "ntp", "audit", "alert", "cron2",
574 "local0", "local1", "local2", "local3",
575 "local4", "local5", "local6", "local7"
576};
577
578
579#define NB_LOG_LEVELS 8
580const char *log_levels[NB_LOG_LEVELS] = {
581 "emerg", "alert", "crit", "err",
582 "warning", "notice", "info", "debug"
583};
584
585#define SYSLOG_PORT 514
586
587const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
588 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
589#define MAX_HOSTNAME_LEN 32
590static char hostname[MAX_HOSTNAME_LEN] = "";
591
willy tarreaua1598082005-12-17 13:08:06 +0100592const char *HTTP_400 =
593 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100594 "Cache-Control: no-cache\r\n"
595 "Connection: close\r\n"
596 "\r\n"
willy tarreaua1598082005-12-17 13:08:06 +0100597 "400 Bad request : Your browser sent an invalid request.\r\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100598
willy tarreaua1598082005-12-17 13:08:06 +0100599const char *HTTP_403 =
600 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100601 "Cache-Control: no-cache\r\n"
602 "Connection: close\r\n"
603 "\r\n"
willy tarreaua1598082005-12-17 13:08:06 +0100604 "403 Forbidden : Request forbidden by administrative rules.\r\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100605
606const char *HTTP_502 =
607 "HTTP/1.0 502 Proxy Error\r\n"
608 "Cache-Control: no-cache\r\n"
609 "Connection: close\r\n"
610 "\r\n"
611 "502 Proxy Error : No server is available to handle this request.\r\n";
612
willy tarreau0f7af912005-12-17 12:21:26 +0100613/*********************************************************************/
614/* statistics ******************************************************/
615/*********************************************************************/
616
617static int stats_tsk_lsrch, stats_tsk_rsrch,
618 stats_tsk_good, stats_tsk_right, stats_tsk_left,
619 stats_tsk_new, stats_tsk_nsrch;
620
621
622/*********************************************************************/
623/* function prototypes *********************************************/
624/*********************************************************************/
625
626int event_accept(int fd);
627int event_cli_read(int fd);
628int event_cli_write(int fd);
629int event_srv_read(int fd);
630int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100631int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100632
633/*********************************************************************/
634/* general purpose functions ***************************************/
635/*********************************************************************/
636
637void display_version() {
638 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100639 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100640}
641
642/*
643 * This function prints the command line usage and exits
644 */
645void usage(char *name) {
646 display_version();
647 fprintf(stderr,
648 "Usage : %s -f <cfgfile> [ -vd"
649#if STATTIME > 0
650 "sl"
651#endif
652 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
653 " -v displays version\n"
654 " -d enters debug mode\n"
655#if STATTIME > 0
656 " -s enables statistics output\n"
657 " -l enables long statistics format\n"
658#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100659 " -D goes daemon ; implies -q\n"
660 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100661 " -n sets the maximum total # of connections (%d)\n"
662 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100663 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100664 exit(1);
665}
666
667
668/*
669 * Displays the message on stderr with the date and pid.
670 */
671void Alert(char *fmt, ...) {
672 va_list argp;
673 struct timeval tv;
674 struct tm *tm;
675
willy tarreau9fe663a2005-12-17 13:02:59 +0100676 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100677 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100678
willy tarreau5cbea6f2005-12-17 12:48:26 +0100679 gettimeofday(&tv, NULL);
680 tm=localtime(&tv.tv_sec);
681 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100682 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100683 vfprintf(stderr, fmt, argp);
684 fflush(stderr);
685 va_end(argp);
686 }
willy tarreau0f7af912005-12-17 12:21:26 +0100687}
688
689
690/*
691 * Displays the message on stderr with the date and pid.
692 */
693void Warning(char *fmt, ...) {
694 va_list argp;
695 struct timeval tv;
696 struct tm *tm;
697
willy tarreau9fe663a2005-12-17 13:02:59 +0100698 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100699 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100700
willy tarreau5cbea6f2005-12-17 12:48:26 +0100701 gettimeofday(&tv, NULL);
702 tm=localtime(&tv.tv_sec);
703 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100704 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100705 vfprintf(stderr, fmt, argp);
706 fflush(stderr);
707 va_end(argp);
708 }
709}
710
711/*
712 * Displays the message on <out> only if quiet mode is not set.
713 */
714void qfprintf(FILE *out, char *fmt, ...) {
715 va_list argp;
716
willy tarreau9fe663a2005-12-17 13:02:59 +0100717 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100718 va_start(argp, fmt);
719 vfprintf(out, fmt, argp);
720 fflush(out);
721 va_end(argp);
722 }
willy tarreau0f7af912005-12-17 12:21:26 +0100723}
724
725
726/*
727 * converts <str> to a struct sockaddr_in* which is locally allocated.
728 * The format is "addr:port", where "addr" can be empty or "*" to indicate
729 * INADDR_ANY.
730 */
731struct sockaddr_in *str2sa(char *str) {
732 static struct sockaddr_in sa;
733 char *c;
734 int port;
735
willy tarreaua1598082005-12-17 13:08:06 +0100736 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100737 str=strdup(str);
738
739 if ((c=strrchr(str,':')) != NULL) {
740 *c++=0;
741 port=atol(c);
742 }
743 else
744 port=0;
745
746 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
747 sa.sin_addr.s_addr = INADDR_ANY;
748 }
749 else if (
750#ifndef SOLARIS
751 !inet_aton(str, &sa.sin_addr)
752#else
753 !inet_pton(AF_INET, str, &sa.sin_addr)
754#endif
755 ) {
756 struct hostent *he;
757
758 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100759 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100760 }
761 else
762 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
763 }
764 sa.sin_port=htons(port);
765 sa.sin_family=AF_INET;
766
767 free(str);
768 return &sa;
769}
770
willy tarreau9fe663a2005-12-17 13:02:59 +0100771
772/*
773 * This function sends a syslog message to both log servers of a proxy,
774 * or to global log servers if the proxy is NULL.
775 * It also tries not to waste too much time computing the message header.
776 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100777 */
778void send_log(struct proxy *p, int level, char *message, ...) {
779 static int logfd = -1; /* syslog UDP socket */
780 static long tvsec = -1; /* to force the string to be initialized */
781 struct timeval tv;
782 va_list argp;
783 static char logmsg[MAX_SYSLOG_LEN];
784 static char *dataptr = NULL;
785 int fac_level;
786 int hdr_len, data_len;
787 struct sockaddr_in *sa[2];
788 int facilities[2];
789 int nbloggers = 0;
790 char *log_ptr;
791
792 if (logfd < 0) {
793 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
794 return;
795 }
796
797 if (level < 0 || progname == NULL || message == NULL)
798 return;
799
800 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100801 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100802 /* this string is rebuild only once a second */
803 struct tm *tm = localtime(&tv.tv_sec);
804 tvsec = tv.tv_sec;
805
willy tarreauc29948c2005-12-17 13:10:27 +0100806 hdr_len = snprintf(logmsg, sizeof(logmsg),
807 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
808 monthname[tm->tm_mon],
809 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
810 progname, pid);
811 /* WARNING: depending upon implementations, snprintf may return
812 * either -1 or the number of bytes that would be needed to store
813 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100814 */
willy tarreauc29948c2005-12-17 13:10:27 +0100815 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
816 hdr_len = sizeof(logmsg);
817
818 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100819 }
820
821 va_start(argp, message);
822 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100823 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
824 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100825 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100826 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100827
828 if (p == NULL) {
829 if (global.logfac1 >= 0) {
830 sa[nbloggers] = &global.logsrv1;
831 facilities[nbloggers] = global.logfac1;
832 nbloggers++;
833 }
834 if (global.logfac2 >= 0) {
835 sa[nbloggers] = &global.logsrv2;
836 facilities[nbloggers] = global.logfac2;
837 nbloggers++;
838 }
839 } else {
840 if (p->logfac1 >= 0) {
841 sa[nbloggers] = &p->logsrv1;
842 facilities[nbloggers] = p->logfac1;
843 nbloggers++;
844 }
845 if (p->logfac2 >= 0) {
846 sa[nbloggers] = &p->logsrv2;
847 facilities[nbloggers] = p->logfac2;
848 nbloggers++;
849 }
850 }
851
852 while (nbloggers-- > 0) {
willy tarreauc29948c2005-12-17 13:10:27 +0100853 /* For each target, we may have a different facility.
854 * We can also have a different log level for each message.
855 * This induces variations in the message header length.
856 * Since we don't want to recompute it each time, nor copy it every
857 * time, we only change the facility in the pre-computed header,
858 * and we change the pointer to the header accordingly.
859 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100860 fac_level = (facilities[nbloggers] << 3) + level;
861 log_ptr = logmsg + 3; /* last digit of the log level */
862 do {
863 *log_ptr = '0' + fac_level % 10;
864 fac_level /= 10;
865 log_ptr--;
866 } while (fac_level && log_ptr > logmsg);
867 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100868
willy tarreauc29948c2005-12-17 13:10:27 +0100869 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100870
871#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100872 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100873 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
874#else
willy tarreauc29948c2005-12-17 13:10:27 +0100875 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100876 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
877#endif
878 }
willy tarreau0f7af912005-12-17 12:21:26 +0100879}
880
881
882/* sets <tv> to the current time */
883static inline struct timeval *tv_now(struct timeval *tv) {
884 if (tv)
885 gettimeofday(tv, NULL);
886 return tv;
887}
888
889/*
890 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
891 */
892static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
893 if (!tv || !from)
894 return NULL;
895 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
896 tv->tv_sec = from->tv_sec + (ms/1000);
897 while (tv->tv_usec >= 1000000) {
898 tv->tv_usec -= 1000000;
899 tv->tv_sec++;
900 }
901 return tv;
902}
903
904/*
905 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
906 */
907static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
908 if (tv1->tv_sec > tv2->tv_sec)
909 return 1;
910 else if (tv1->tv_sec < tv2->tv_sec)
911 return -1;
912 else if (tv1->tv_usec > tv2->tv_usec)
913 return 1;
914 else if (tv1->tv_usec < tv2->tv_usec)
915 return -1;
916 else
917 return 0;
918}
919
920/*
921 * returns the absolute difference, in ms, between tv1 and tv2
922 */
923unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
924 int cmp;
925 unsigned long ret;
926
927
willy tarreauef900ab2005-12-17 12:52:52 +0100928 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100929 if (!cmp)
930 return 0; /* same dates, null diff */
931 else if (cmp<0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100932 struct timeval *tmp = tv1;
933 tv1 = tv2;
934 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100935 }
willy tarreauef900ab2005-12-17 12:52:52 +0100936 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100937 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100938 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100939 else
willy tarreauef900ab2005-12-17 12:52:52 +0100940 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100941 return (unsigned long) ret;
942}
943
944/*
945 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
946 */
947static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100948 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100949 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100950 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100951 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100952 return -1;
953 else
954 return 0;
955 }
956 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100957 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100958 return 1;
959 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100960 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100961 return -1;
962 else
963 return 0;
964}
965
966/*
967 * returns the remaining time between tv1=now and event=tv2
968 * if tv2 is passed, 0 is returned.
969 */
970static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
971 unsigned long ret;
972
willy tarreau0f7af912005-12-17 12:21:26 +0100973 if (tv_cmp_ms(tv1, tv2) >= 0)
974 return 0; /* event elapsed */
975
willy tarreauef900ab2005-12-17 12:52:52 +0100976 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100977 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100978 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100979 else
willy tarreauef900ab2005-12-17 12:52:52 +0100980 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100981 return (unsigned long) ret;
982}
983
984
985/*
986 * zeroes a struct timeval
987 */
988
989static inline struct timeval *tv_eternity(struct timeval *tv) {
990 tv->tv_sec = tv->tv_usec = 0;
991 return tv;
992}
993
994/*
995 * returns 1 if tv is null, else 0
996 */
997static inline int tv_iseternity(struct timeval *tv) {
998 if (tv->tv_sec == 0 && tv->tv_usec == 0)
999 return 1;
1000 else
1001 return 0;
1002}
1003
1004/*
1005 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1006 * considering that 0 is the eternity.
1007 */
1008static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1009 if (tv_iseternity(tv1))
1010 if (tv_iseternity(tv2))
1011 return 0; /* same */
1012 else
1013 return 1; /* tv1 later than tv2 */
1014 else if (tv_iseternity(tv2))
1015 return -1; /* tv2 later than tv1 */
1016
1017 if (tv1->tv_sec > tv2->tv_sec)
1018 return 1;
1019 else if (tv1->tv_sec < tv2->tv_sec)
1020 return -1;
1021 else if (tv1->tv_usec > tv2->tv_usec)
1022 return 1;
1023 else if (tv1->tv_usec < tv2->tv_usec)
1024 return -1;
1025 else
1026 return 0;
1027}
1028
1029/*
1030 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1031 * considering that 0 is the eternity.
1032 */
1033static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1034 if (tv_iseternity(tv1))
1035 if (tv_iseternity(tv2))
1036 return 0; /* same */
1037 else
1038 return 1; /* tv1 later than tv2 */
1039 else if (tv_iseternity(tv2))
1040 return -1; /* tv2 later than tv1 */
1041
willy tarreauefae1842005-12-17 12:51:03 +01001042 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001043 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001044 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001045 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001046 return -1;
1047 else
1048 return 0;
1049 }
1050 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001051 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001052 return 1;
1053 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001054 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001055 return -1;
1056 else
1057 return 0;
1058}
1059
1060/*
1061 * returns the first event between tv1 and tv2 into tvmin.
1062 * a zero tv is ignored. tvmin is returned.
1063 */
1064static inline struct timeval *tv_min(struct timeval *tvmin,
1065 struct timeval *tv1, struct timeval *tv2) {
1066
1067 if (tv_cmp2(tv1, tv2) <= 0)
1068 *tvmin = *tv1;
1069 else
1070 *tvmin = *tv2;
1071
1072 return tvmin;
1073}
1074
1075
1076
1077/***********************************************************/
1078/* fd management ***************************************/
1079/***********************************************************/
1080
1081
1082
willy tarreau5cbea6f2005-12-17 12:48:26 +01001083/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1084 * The file descriptor is also closed.
1085 */
willy tarreau0f7af912005-12-17 12:21:26 +01001086static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001087 FD_CLR(fd, StaticReadEvent);
1088 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001089 close(fd);
1090 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001091
1092 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1093 maxfd--;
1094}
1095
1096/* recomputes the maxfd limit from the fd */
1097static inline void fd_insert(int fd) {
1098 if (fd+1 > maxfd)
1099 maxfd = fd+1;
1100}
1101
1102/*************************************************************/
1103/* task management ***************************************/
1104/*************************************************************/
1105
willy tarreau5cbea6f2005-12-17 12:48:26 +01001106/* puts the task <t> in run queue <q>, and returns <t> */
1107static inline struct task *task_wakeup(struct task **q, struct task *t) {
1108 if (t->state == TASK_RUNNING)
1109 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001110 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001111 t->rqnext = *q;
1112 t->state = TASK_RUNNING;
1113 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001114 }
1115}
1116
willy tarreau5cbea6f2005-12-17 12:48:26 +01001117/* removes the task <t> from the queue <q>
1118 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001119 * set the run queue to point to the next one, and return it
1120 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001121static inline struct task *task_sleep(struct task **q, struct task *t) {
1122 if (t->state == TASK_RUNNING) {
1123 *q = t->rqnext;
1124 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001125 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001126 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001127}
1128
1129/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001130 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001131 * from the run queue. A pointer to the task itself is returned.
1132 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001133static inline struct task *task_delete(struct task *t) {
1134 t->prev->next = t->next;
1135 t->next->prev = t->prev;
1136 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001137}
1138
1139/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001140 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001141 */
1142static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001143 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001144}
1145
willy tarreau5cbea6f2005-12-17 12:48:26 +01001146/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001147 * may be only moved or left where it was, depending on its timing requirements.
1148 * <task> is returned.
1149 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001150struct task *task_queue(struct task *task) {
1151 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001152 struct task *start_from;
1153
1154 /* first, test if the task was already in a list */
1155 if (task->prev == NULL) {
1156 // start_from = list;
1157 start_from = list->prev;
1158 stats_tsk_new++;
1159
1160 /* insert the unlinked <task> into the list, searching back from the last entry */
1161 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1162 start_from = start_from->prev;
1163 stats_tsk_nsrch++;
1164 }
1165
1166 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1167 // start_from = start_from->next;
1168 // stats_tsk_nsrch++;
1169 // }
1170 }
1171 else if (task->prev == list ||
1172 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1173 start_from = task->next;
1174 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
1175 stats_tsk_good++;
1176 return task; /* it's already in the right place */
1177 }
1178
1179 stats_tsk_right++;
1180 /* insert the unlinked <task> into the list, searching after position <start_from> */
1181 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1182 start_from = start_from->next;
1183 stats_tsk_rsrch++;
1184 }
1185 /* we need to unlink it now */
1186 task_delete(task);
1187 }
1188 else { /* walk left. */
1189 stats_tsk_left++;
1190#ifdef LEFT_TO_TOP /* not very good */
1191 start_from = list;
1192 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1193 start_from = start_from->next;
1194 stats_tsk_lsrch++;
1195 }
1196#else
1197 start_from = task->prev->prev; /* valid because of the previous test above */
1198 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1199 start_from = start_from->prev;
1200 stats_tsk_lsrch++;
1201 }
1202#endif
1203 /* we need to unlink it now */
1204 task_delete(task);
1205 }
1206 task->prev = start_from;
1207 task->next = start_from->next;
1208 task->next->prev = task;
1209 start_from->next = task;
1210 return task;
1211}
1212
1213
1214/*********************************************************************/
1215/* more specific functions ***************************************/
1216/*********************************************************************/
1217
1218/* some prototypes */
1219static int maintain_proxies(void);
1220
willy tarreau5cbea6f2005-12-17 12:48:26 +01001221/* this either returns the sockname or the original destination address. Code
1222 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1223 */
1224static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001225#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001226 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1227#else
willy tarreaua1598082005-12-17 13:08:06 +01001228#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001229 return getsockname(fd, (struct sockaddr *)sa, salen);
1230#else
1231 return -1;
1232#endif
1233#endif
1234}
1235
1236/*
1237 * frees the context associated to a session. It must have been removed first.
1238 */
1239static inline void session_free(struct session *s) {
1240 if (s->req)
1241 pool_free(buffer, s->req);
1242 if (s->rep)
1243 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001244 if (s->logs.uri)
1245 pool_free(requri, s->logs.uri);
willy tarreau9fe663a2005-12-17 13:02:59 +01001246
willy tarreau5cbea6f2005-12-17 12:48:26 +01001247 pool_free(session, s);
1248}
1249
willy tarreau0f7af912005-12-17 12:21:26 +01001250
1251/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001252 * This function initiates a connection to the current server (s->srv) if (s->direct)
1253 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001254 * it's OK, -1 if it's impossible.
1255 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001256int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001257 int one = 1;
1258 int fd;
1259
1260 // fprintf(stderr,"connect_server : s=%p\n",s);
1261
willy tarreaue39cd132005-12-17 13:00:18 +01001262 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001263 s->srv_addr = s->srv->addr;
1264 }
1265 else if (s->proxy->options & PR_O_BALANCE) {
1266 if (s->proxy->options & PR_O_BALANCE_RR) {
1267 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001268 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001269 if (s->proxy->cursrv == NULL)
1270 s->proxy->cursrv = s->proxy->srv;
1271 if (s->proxy->cursrv->state & SRV_RUNNING)
1272 break;
1273 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001274 retry--;
1275 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001276
1277 if (retry == 0) /* no server left */
1278 return -1;
1279
1280 s->srv = s->proxy->cursrv;
1281 s->srv_addr = s->srv->addr;
1282 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001283 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001284 else /* unknown balancing algorithm */
1285 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001286 }
willy tarreaua1598082005-12-17 13:08:06 +01001287 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001288 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001289 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001290 }
1291 else if (s->proxy->options & PR_O_TRANSP) {
1292 /* in transparent mode, use the original dest addr if no dispatch specified */
1293 int salen = sizeof(struct sockaddr_in);
1294 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1295 qfprintf(stderr, "Cannot get original server address.\n");
1296 return -1;
1297 }
1298 }
willy tarreau0f7af912005-12-17 12:21:26 +01001299
1300 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001301 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001302 return -1;
1303 }
1304
willy tarreau9fe663a2005-12-17 13:02:59 +01001305 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001306 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1307 close(fd);
1308 return -1;
1309 }
1310
willy tarreau0f7af912005-12-17 12:21:26 +01001311 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1312 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001313 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001314 close(fd);
1315 return -1;
1316 }
1317
willy tarreaua1598082005-12-17 13:08:06 +01001318 /* allow specific binding */
1319 if (s->proxy->options & PR_O_BIND_SRC &&
1320 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1321 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1322 close(fd);
1323 return -1;
1324 }
1325
willy tarreau0f7af912005-12-17 12:21:26 +01001326 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1327 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001328 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001329 close(fd);
1330 return -1;
1331 }
1332 else if (errno != EALREADY && errno != EISCONN) {
1333 close(fd);
1334 return -1;
1335 }
1336 }
1337
willy tarreau5cbea6f2005-12-17 12:48:26 +01001338 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001339 fdtab[fd].read = &event_srv_read;
1340 fdtab[fd].write = &event_srv_write;
1341 fdtab[fd].state = FD_STCONN; /* connection in progress */
1342
1343 FD_SET(fd, StaticWriteEvent); /* for connect status */
1344
1345 fd_insert(fd);
1346
1347 if (s->proxy->contimeout)
1348 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1349 else
1350 tv_eternity(&s->cnexpire);
1351 return 0;
1352}
1353
1354/*
1355 * this function is called on a read event from a client socket.
1356 * It returns 0.
1357 */
1358int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001359 struct task *t = fdtab[fd].owner;
1360 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001361 struct buffer *b = s->req;
1362 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001363
1364 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1365
willy tarreau0f7af912005-12-17 12:21:26 +01001366 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001367 while (1) {
1368 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1369 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001370 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001371 }
1372 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001373 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001374 }
1375 else {
1376 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001377 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1378 * since it means that the rewrite protection has been removed. This
1379 * implies that the if statement can be removed.
1380 */
1381 if (max > b->rlim - b->data)
1382 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001383 }
1384
1385 if (max == 0) { /* not anymore room to store data */
1386 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001387 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001388 }
1389
willy tarreau3242e862005-12-17 12:27:53 +01001390#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001391 {
1392 int skerr, lskerr;
1393
1394 lskerr = sizeof(skerr);
1395 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1396 if (skerr)
1397 ret = -1;
1398 else
1399 ret = recv(fd, b->r, max, 0);
1400 }
willy tarreau3242e862005-12-17 12:27:53 +01001401#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001402 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001403#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001404 if (ret > 0) {
1405 b->r += ret;
1406 b->l += ret;
1407 s->res_cr = RES_DATA;
1408
1409 if (b->r == b->data + BUFSIZE) {
1410 b->r = b->data; /* wrap around the buffer */
1411 }
willy tarreaua1598082005-12-17 13:08:06 +01001412
1413 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001414 /* we hope to read more data or to get a close on next round */
1415 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001416 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001417 else if (ret == 0) {
1418 s->res_cr = RES_NULL;
1419 break;
1420 }
1421 else if (errno == EAGAIN) {/* ignore EAGAIN */
1422 break;
1423 }
1424 else {
1425 s->res_cr = RES_ERROR;
1426 fdtab[fd].state = FD_STERROR;
1427 break;
1428 }
1429 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001430 }
1431 else {
1432 s->res_cr = RES_ERROR;
1433 fdtab[fd].state = FD_STERROR;
1434 }
1435
willy tarreau5cbea6f2005-12-17 12:48:26 +01001436 if (s->res_cr != RES_SILENT) {
1437 if (s->proxy->clitimeout)
1438 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1439 else
1440 tv_eternity(&s->crexpire);
1441
1442 task_wakeup(&rq, t);
1443 }
willy tarreau0f7af912005-12-17 12:21:26 +01001444
willy tarreau0f7af912005-12-17 12:21:26 +01001445 return 0;
1446}
1447
1448
1449/*
1450 * this function is called on a read event from a server socket.
1451 * It returns 0.
1452 */
1453int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001454 struct task *t = fdtab[fd].owner;
1455 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001456 struct buffer *b = s->rep;
1457 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001458
1459 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1460
willy tarreau0f7af912005-12-17 12:21:26 +01001461 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001462 while (1) {
1463 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1464 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001465 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001466 }
1467 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001468 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001469 }
1470 else {
1471 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001472 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1473 * since it means that the rewrite protection has been removed. This
1474 * implies that the if statement can be removed.
1475 */
1476 if (max > b->rlim - b->data)
1477 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001478 }
1479
1480 if (max == 0) { /* not anymore room to store data */
1481 FD_CLR(fd, StaticReadEvent);
1482 break;
1483 }
1484
willy tarreau3242e862005-12-17 12:27:53 +01001485#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001486 {
1487 int skerr, lskerr;
1488
1489 lskerr = sizeof(skerr);
1490 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1491 if (skerr)
1492 ret = -1;
1493 else
1494 ret = recv(fd, b->r, max, 0);
1495 }
willy tarreau3242e862005-12-17 12:27:53 +01001496#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001497 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001498#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001499 if (ret > 0) {
1500 b->r += ret;
1501 b->l += ret;
1502 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001503
willy tarreau5cbea6f2005-12-17 12:48:26 +01001504 if (b->r == b->data + BUFSIZE) {
1505 b->r = b->data; /* wrap around the buffer */
1506 }
willy tarreaua1598082005-12-17 13:08:06 +01001507
1508 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001509 /* we hope to read more data or to get a close on next round */
1510 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001511 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001512 else if (ret == 0) {
1513 s->res_sr = RES_NULL;
1514 break;
1515 }
1516 else if (errno == EAGAIN) {/* ignore EAGAIN */
1517 break;
1518 }
1519 else {
1520 s->res_sr = RES_ERROR;
1521 fdtab[fd].state = FD_STERROR;
1522 break;
1523 }
1524 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001525 }
1526 else {
1527 s->res_sr = RES_ERROR;
1528 fdtab[fd].state = FD_STERROR;
1529 }
1530
willy tarreau5cbea6f2005-12-17 12:48:26 +01001531 if (s->res_sr != RES_SILENT) {
1532 if (s->proxy->srvtimeout)
1533 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1534 else
1535 tv_eternity(&s->srexpire);
1536
1537 task_wakeup(&rq, t);
1538 }
willy tarreau0f7af912005-12-17 12:21:26 +01001539
willy tarreau0f7af912005-12-17 12:21:26 +01001540 return 0;
1541}
1542
1543/*
1544 * this function is called on a write event from a client socket.
1545 * It returns 0.
1546 */
1547int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001548 struct task *t = fdtab[fd].owner;
1549 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001550 struct buffer *b = s->rep;
1551 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001552
1553 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1554
1555 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001556 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001557 // max = BUFSIZE; BUG !!!!
1558 max = 0;
1559 }
1560 else if (b->r > b->w) {
1561 max = b->r - b->w;
1562 }
1563 else
1564 max = b->data + BUFSIZE - b->w;
1565
willy tarreau0f7af912005-12-17 12:21:26 +01001566 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001567#ifndef MSG_NOSIGNAL
1568 int skerr, lskerr;
1569#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001570
1571 if (max == 0) {
1572 s->res_cw = RES_NULL;
1573 task_wakeup(&rq, t);
1574 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001575 }
1576
willy tarreau3242e862005-12-17 12:27:53 +01001577#ifndef MSG_NOSIGNAL
1578 lskerr=sizeof(skerr);
1579 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1580 if (skerr)
1581 ret = -1;
1582 else
1583 ret = send(fd, b->w, max, MSG_DONTWAIT);
1584#else
willy tarreau0f7af912005-12-17 12:21:26 +01001585 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001586#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001587
1588 if (ret > 0) {
1589 b->l -= ret;
1590 b->w += ret;
1591
1592 s->res_cw = RES_DATA;
1593
1594 if (b->w == b->data + BUFSIZE) {
1595 b->w = b->data; /* wrap around the buffer */
1596 }
1597 }
1598 else if (ret == 0) {
1599 /* nothing written, just make as if we were never called */
1600// s->res_cw = RES_NULL;
1601 return 0;
1602 }
1603 else if (errno == EAGAIN) /* ignore EAGAIN */
1604 return 0;
1605 else {
1606 s->res_cw = RES_ERROR;
1607 fdtab[fd].state = FD_STERROR;
1608 }
1609 }
1610 else {
1611 s->res_cw = RES_ERROR;
1612 fdtab[fd].state = FD_STERROR;
1613 }
1614
1615 if (s->proxy->clitimeout)
1616 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1617 else
1618 tv_eternity(&s->cwexpire);
1619
willy tarreau5cbea6f2005-12-17 12:48:26 +01001620 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001621 return 0;
1622}
1623
1624
1625/*
1626 * this function is called on a write event from a server socket.
1627 * It returns 0.
1628 */
1629int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001630 struct task *t = fdtab[fd].owner;
1631 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001632 struct buffer *b = s->req;
1633 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001634
1635 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1636
1637 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001638 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001639 // max = BUFSIZE; BUG !!!!
1640 max = 0;
1641 }
1642 else if (b->r > b->w) {
1643 max = b->r - b->w;
1644 }
1645 else
1646 max = b->data + BUFSIZE - b->w;
1647
willy tarreau0f7af912005-12-17 12:21:26 +01001648 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001649#ifndef MSG_NOSIGNAL
1650 int skerr, lskerr;
1651#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001652 if (max == 0) {
1653 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001654 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001655 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001656 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001657 return 0;
1658 }
1659
willy tarreauef900ab2005-12-17 12:52:52 +01001660
willy tarreau3242e862005-12-17 12:27:53 +01001661#ifndef MSG_NOSIGNAL
1662 lskerr=sizeof(skerr);
1663 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1664 if (skerr)
1665 ret = -1;
1666 else
1667 ret = send(fd, b->w, max, MSG_DONTWAIT);
1668#else
willy tarreau0f7af912005-12-17 12:21:26 +01001669 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001670#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001671 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001672 if (ret > 0) {
1673 b->l -= ret;
1674 b->w += ret;
1675
1676 s->res_sw = RES_DATA;
1677
1678 if (b->w == b->data + BUFSIZE) {
1679 b->w = b->data; /* wrap around the buffer */
1680 }
1681 }
1682 else if (ret == 0) {
1683 /* nothing written, just make as if we were never called */
1684 // s->res_sw = RES_NULL;
1685 return 0;
1686 }
1687 else if (errno == EAGAIN) /* ignore EAGAIN */
1688 return 0;
1689 else {
1690 s->res_sw = RES_ERROR;
1691 fdtab[fd].state = FD_STERROR;
1692 }
1693 }
1694 else {
1695 s->res_sw = RES_ERROR;
1696 fdtab[fd].state = FD_STERROR;
1697 }
1698
1699 if (s->proxy->srvtimeout)
1700 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1701 else
1702 tv_eternity(&s->swexpire);
1703
willy tarreau5cbea6f2005-12-17 12:48:26 +01001704 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001705 return 0;
1706}
1707
1708
1709/*
willy tarreaue39cd132005-12-17 13:00:18 +01001710 * returns a message to the client ; the connection is shut down for read,
1711 * and the request is cleared so that no server connection can be initiated.
1712 * The client must be in a valid state for this (HEADER, DATA ...).
1713 * Nothing is performed on the server side.
1714 * The reply buffer must be empty before this.
1715 */
1716void client_retnclose(struct session *s, int len, const char *msg) {
1717 FD_CLR(s->cli_fd, StaticReadEvent);
1718 FD_SET(s->cli_fd, StaticWriteEvent);
1719 tv_eternity(&s->crexpire);
1720 shutdown(s->cli_fd, SHUT_RD);
1721 s->cli_state = CL_STSHUTR;
1722 strcpy(s->rep->data, msg);
1723 s->rep->l = len;
1724 s->rep->r += len;
1725 s->req->l = 0;
1726}
1727
1728
1729/*
1730 * returns a message into the rep buffer, and flushes the req buffer.
1731 * The reply buffer must be empty before this.
1732 */
1733void client_return(struct session *s, int len, const char *msg) {
1734 strcpy(s->rep->data, msg);
1735 s->rep->l = len;
1736 s->rep->r += len;
1737 s->req->l = 0;
1738}
1739
willy tarreau9fe663a2005-12-17 13:02:59 +01001740/*
1741 * send a log for the session when we have enough info about it
1742 */
1743void sess_log(struct session *s) {
1744 unsigned char *pn;
1745 struct proxy *p = s->proxy;
1746 int log;
1747 char *uri;
1748 char *pxid;
1749 char *srv;
1750
1751 /* This is a first attempt at a better logging system.
1752 * For now, we rely on send_log() to provide the date, although it obviously
1753 * is the date of the log and not of the request, and most fields are not
1754 * computed.
1755 */
1756
willy tarreaua1598082005-12-17 13:08:06 +01001757 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001758
1759 pn = (log & LW_CLIP) ?
1760 (unsigned char *)&s->cli_addr.sin_addr :
1761 (unsigned char *)"\0\0\0\0";
1762
willy tarreaua1598082005-12-17 13:08:06 +01001763 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001764 pxid = p->id;
1765 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001766 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1767
1768 if (p->to_log & LW_DATE) {
1769 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1770
1771 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld \"%s\"\n",
1772 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1773 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1774 tm->tm_hour, tm->tm_min, tm->tm_sec,
1775 pxid, srv,
1776 s->logs.t_request,
1777 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1778 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1779 s->logs.t_close,
1780 s->logs.status, s->logs.bytes,
1781 uri);
1782 }
1783 else {
1784 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld \"%s\"\n",
1785 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1786 pxid, srv,
1787 s->logs.t_request,
1788 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1789 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1790 s->logs.t_close,
1791 s->logs.status, s->logs.bytes,
1792 uri);
1793 }
1794
1795 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001796}
1797
willy tarreaue39cd132005-12-17 13:00:18 +01001798
1799/*
willy tarreau0f7af912005-12-17 12:21:26 +01001800 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001801 * to an accept. It tries to accept as many connections as possible.
1802 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001803 */
1804int event_accept(int fd) {
1805 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001806 struct session *s;
1807 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001808 int cfd;
1809 int one = 1;
1810
willy tarreau5cbea6f2005-12-17 12:48:26 +01001811 while (p->nbconn < p->maxconn) {
1812 struct sockaddr_in addr;
1813 int laddr = sizeof(addr);
1814 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1815 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001816
willy tarreau5cbea6f2005-12-17 12:48:26 +01001817 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1818 Alert("out of memory in event_accept().\n");
1819 FD_CLR(fd, StaticReadEvent);
1820 p->state = PR_STIDLE;
1821 close(cfd);
1822 return 0;
1823 }
willy tarreau0f7af912005-12-17 12:21:26 +01001824
willy tarreau5cbea6f2005-12-17 12:48:26 +01001825 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1826 Alert("out of memory in event_accept().\n");
1827 FD_CLR(fd, StaticReadEvent);
1828 p->state = PR_STIDLE;
1829 close(cfd);
1830 pool_free(session, s);
1831 return 0;
1832 }
willy tarreau0f7af912005-12-17 12:21:26 +01001833
willy tarreau5cbea6f2005-12-17 12:48:26 +01001834 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001835 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001836 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1837 close(cfd);
1838 pool_free(task, t);
1839 pool_free(session, s);
1840 return 0;
1841 }
willy tarreau0f7af912005-12-17 12:21:26 +01001842
willy tarreau5cbea6f2005-12-17 12:48:26 +01001843 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1844 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1845 (char *) &one, sizeof(one)) == -1)) {
1846 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1847 close(cfd);
1848 pool_free(task, t);
1849 pool_free(session, s);
1850 return 0;
1851 }
willy tarreau0f7af912005-12-17 12:21:26 +01001852
willy tarreau9fe663a2005-12-17 13:02:59 +01001853 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1854 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1855 t->state = TASK_IDLE;
1856 t->process = process_session;
1857 t->context = s;
1858
1859 s->task = t;
1860 s->proxy = p;
1861 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1862 s->srv_state = SV_STIDLE;
1863 s->req = s->rep = NULL; /* will be allocated later */
1864 s->flags = 0;
1865 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1866 s->cli_fd = cfd;
1867 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01001868 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01001869 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01001870
1871 s->logs.logwait = p->to_log;
1872 s->logs.tv_accept = now;
1873 s->logs.t_request = -1;
1874 s->logs.t_connect = -1;
1875 s->logs.t_data = -1;
1876 s->logs.t_close = 0;
1877 s->logs.uri = NULL;
1878 s->logs.status = -1;
1879 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001880
willy tarreau5cbea6f2005-12-17 12:48:26 +01001881 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1882 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01001883 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001884 unsigned char *pn, *sn;
1885 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01001886
willy tarreau5cbea6f2005-12-17 12:48:26 +01001887 namelen = sizeof(sockname);
1888 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1889 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1890 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01001891 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001892
willy tarreau9fe663a2005-12-17 13:02:59 +01001893 if (p->to_log) {
1894 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01001895 if (s->logs.logwait & LW_CLIP)
1896 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01001897 sess_log(s);
1898 }
1899 else
1900 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1901 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1902 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1903 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01001904 }
willy tarreau0f7af912005-12-17 12:21:26 +01001905
willy tarreau9fe663a2005-12-17 13:02:59 +01001906 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreauef900ab2005-12-17 12:52:52 +01001907 int len;
1908 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1909 write(1, trash, len);
1910 }
willy tarreau0f7af912005-12-17 12:21:26 +01001911
willy tarreau5cbea6f2005-12-17 12:48:26 +01001912 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1913 close(cfd); /* nothing can be done for this fd without memory */
1914 pool_free(task, t);
1915 pool_free(session, s);
1916 return 0;
1917 }
1918 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01001919 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001920 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1921 s->req->rlim = s->req->data + BUFSIZE;
1922 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
1923 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01001924
willy tarreau5cbea6f2005-12-17 12:48:26 +01001925 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1926 pool_free(buffer, s->req);
1927 close(cfd); /* nothing can be done for this fd without memory */
1928 pool_free(task, t);
1929 pool_free(session, s);
1930 return 0;
1931 }
1932 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01001933 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001934 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 +01001935
willy tarreau5cbea6f2005-12-17 12:48:26 +01001936 fdtab[cfd].read = &event_cli_read;
1937 fdtab[cfd].write = &event_cli_write;
1938 fdtab[cfd].owner = t;
1939 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001940
willy tarreau5cbea6f2005-12-17 12:48:26 +01001941 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01001942 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001943 }
1944 else {
1945 FD_SET(cfd, StaticReadEvent);
1946 }
1947
1948 fd_insert(cfd);
1949
1950 tv_eternity(&s->cnexpire);
1951 tv_eternity(&s->srexpire);
1952 tv_eternity(&s->swexpire);
1953 tv_eternity(&s->cwexpire);
1954
1955 if (s->proxy->clitimeout)
1956 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1957 else
1958 tv_eternity(&s->crexpire);
1959
1960 t->expire = s->crexpire;
1961
1962 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01001963
1964 if (p->mode != PR_MODE_HEALTH)
1965 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001966
1967 p->nbconn++;
1968 actconn++;
1969 totalconn++;
1970
1971 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1972 } /* end of while (p->nbconn < p->maxconn) */
1973 return 0;
1974}
willy tarreau0f7af912005-12-17 12:21:26 +01001975
willy tarreau0f7af912005-12-17 12:21:26 +01001976
willy tarreau5cbea6f2005-12-17 12:48:26 +01001977/*
1978 * This function is used only for server health-checks. It handles
1979 * the connection acknowledgement and returns 1 if the socket is OK,
1980 * or -1 if an error occured.
1981 */
1982int event_srv_hck(int fd) {
1983 struct task *t = fdtab[fd].owner;
1984 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001985
willy tarreau5cbea6f2005-12-17 12:48:26 +01001986 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01001987 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001988 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1989 if (skerr)
1990 s->result = -1;
1991 else
1992 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001993
willy tarreau5cbea6f2005-12-17 12:48:26 +01001994 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001995 return 0;
1996}
1997
1998
1999/*
2000 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2001 * and moves <end> just after the end of <str>.
2002 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2003 * the shift value (positive or negative) is returned.
2004 * If there's no space left, the move is not done.
2005 *
2006 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002008 int delta;
2009 int len;
2010
2011 len = strlen(str);
2012 delta = len - (end - pos);
2013
2014 if (delta + b->r >= b->data + BUFSIZE)
2015 return 0; /* no space left */
2016
2017 /* first, protect the end of the buffer */
2018 memmove(end + delta, end, b->data + b->l - end);
2019
2020 /* now, copy str over pos */
2021 memcpy(pos, str,len);
2022
willy tarreau5cbea6f2005-12-17 12:48:26 +01002023 /* we only move data after the displaced zone */
2024 if (b->r > pos) b->r += delta;
2025 if (b->w > pos) b->w += delta;
2026 if (b->h > pos) b->h += delta;
2027 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002028 b->l += delta;
2029
2030 return delta;
2031}
2032
willy tarreau240afa62005-12-17 13:14:35 +01002033/* same except that the string len is given, which allows str to be NULL if
2034 * len is 0.
2035 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002036int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002037 int delta;
2038
2039 delta = len - (end - pos);
2040
2041 if (delta + b->r >= b->data + BUFSIZE)
2042 return 0; /* no space left */
2043
2044 /* first, protect the end of the buffer */
2045 memmove(end + delta, end, b->data + b->l - end);
2046
2047 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002048 if (len)
2049 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002050
willy tarreau5cbea6f2005-12-17 12:48:26 +01002051 /* we only move data after the displaced zone */
2052 if (b->r > pos) b->r += delta;
2053 if (b->w > pos) b->w += delta;
2054 if (b->h > pos) b->h += delta;
2055 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002056 b->l += delta;
2057
2058 return delta;
2059}
2060
2061
2062int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2063 char *old_dst = dst;
2064
2065 while (*str) {
2066 if (*str == '\\') {
2067 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002068 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002069 int len, num;
2070
2071 num = *str - '0';
2072 str++;
2073
2074 if (matches[num].rm_so > -1) {
2075 len = matches[num].rm_eo - matches[num].rm_so;
2076 memcpy(dst, src + matches[num].rm_so, len);
2077 dst += len;
2078 }
2079
2080 }
2081 else if (*str == 'x') {
2082 unsigned char hex1, hex2;
2083 str++;
2084
2085 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2086
2087 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2088 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2089 *dst++ = (hex1<<4) + hex2;
2090 }
2091 else
2092 *dst++ = *str++;
2093 }
2094 else
2095 *dst++ = *str++;
2096 }
2097 *dst = 0;
2098 return dst - old_dst;
2099}
2100
willy tarreau9fe663a2005-12-17 13:02:59 +01002101
willy tarreau0f7af912005-12-17 12:21:26 +01002102/*
2103 * manages the client FSM and its socket. BTW, it also tries to handle the
2104 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2105 * 0 else.
2106 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002107int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002108 int s = t->srv_state;
2109 int c = t->cli_state;
2110 struct buffer *req = t->req;
2111 struct buffer *rep = t->rep;
2112
2113 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2114 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2115 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2116 //);
2117 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002118 /* now parse the partial (or complete) headers */
2119 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2120 char *ptr;
2121 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002122
willy tarreau5cbea6f2005-12-17 12:48:26 +01002123 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002124
willy tarreau0f7af912005-12-17 12:21:26 +01002125 /* look for the end of the current header */
2126 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2127 ptr++;
2128
willy tarreau5cbea6f2005-12-17 12:48:26 +01002129 if (ptr == req->h) { /* empty line, end of headers */
2130 char newhdr[MAXREWRITE + 1];
2131 int line, len;
2132 /* we can only get here after an end of headers */
2133 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002134
willy tarreaue39cd132005-12-17 13:00:18 +01002135 if (t->flags & SN_CLDENY) {
2136 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002137 t->logs.status = 403;
willy tarreaue39cd132005-12-17 13:00:18 +01002138 client_retnclose(t, strlen(HTTP_403), HTTP_403);
2139 return 1;
2140 }
2141
willy tarreau5cbea6f2005-12-17 12:48:26 +01002142 for (line = 0; line < t->proxy->nb_reqadd; line++) {
2143 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
2144 buffer_replace2(req, req->h, req->h, newhdr, len);
2145 }
willy tarreau0f7af912005-12-17 12:21:26 +01002146
willy tarreau9fe663a2005-12-17 13:02:59 +01002147 if (t->proxy->options & PR_O_FWDFOR) {
2148 /* insert an X-Forwarded-For header */
2149 unsigned char *pn;
2150 pn = (unsigned char *)&t->cli_addr.sin_addr;
2151 len = sprintf(newhdr, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2152 pn[0], pn[1], pn[2], pn[3]);
2153 buffer_replace2(req, req->h, req->h, newhdr, len);
2154 }
2155
willy tarreau5cbea6f2005-12-17 12:48:26 +01002156 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002157 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002158
willy tarreaua1598082005-12-17 13:08:06 +01002159 t->logs.t_request = tv_delta(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002160 /* FIXME: we'll set the client in a wait state while we try to
2161 * connect to the server. Is this really needed ? wouldn't it be
2162 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002163 //FD_CLR(t->cli_fd, StaticReadEvent);
2164 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002165 break;
2166 }
willy tarreau0f7af912005-12-17 12:21:26 +01002167
willy tarreau5cbea6f2005-12-17 12:48:26 +01002168 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2169 if (ptr > req->r - 2) {
2170 /* this is a partial header, let's wait for more to come */
2171 req->lr = ptr;
2172 break;
2173 }
willy tarreau0f7af912005-12-17 12:21:26 +01002174
willy tarreau5cbea6f2005-12-17 12:48:26 +01002175 /* now we know that *ptr is either \r or \n,
2176 * and that there are at least 1 char after it.
2177 */
2178 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2179 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2180 else
2181 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002182
willy tarreau5cbea6f2005-12-17 12:48:26 +01002183 /*
2184 * now we know that we have a full header ; we can do whatever
2185 * we want with these pointers :
2186 * req->h = beginning of header
2187 * ptr = end of header (first \r or \n)
2188 * req->lr = beginning of next line (next rep->h)
2189 * req->r = end of data (not used at this stage)
2190 */
willy tarreau0f7af912005-12-17 12:21:26 +01002191
willy tarreaua1598082005-12-17 13:08:06 +01002192 if (t->logs.logwait & LW_REQ &&
2193 t->proxy->mode & PR_MODE_HTTP) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002194 /* we have a complete HTTP request that we must log */
2195 int urilen;
2196
willy tarreaua1598082005-12-17 13:08:06 +01002197 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002198 Alert("HTTP logging : out of memory.\n");
willy tarreaua1598082005-12-17 13:08:06 +01002199 t->logs.status = 502;
2200 client_retnclose(t, strlen(HTTP_502), HTTP_502);
willy tarreau9fe663a2005-12-17 13:02:59 +01002201 return 1;
2202 }
2203
2204 urilen = ptr - req->h;
2205 if (urilen >= REQURI_LEN)
2206 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002207 memcpy(t->logs.uri, req->h, urilen);
2208 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002209
willy tarreaua1598082005-12-17 13:08:06 +01002210 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002211 sess_log(t);
2212 }
2213
willy tarreau5cbea6f2005-12-17 12:48:26 +01002214 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002215
willy tarreau9fe663a2005-12-17 13:02:59 +01002216 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002217 int len, max;
2218 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2219 max = ptr - req->h;
2220 UBOUND(max, sizeof(trash) - len - 1);
2221 len += strlcpy(trash + len, req->h, max + 1);
2222 trash[len++] = '\n';
2223 write(1, trash, len);
2224 }
willy tarreau0f7af912005-12-17 12:21:26 +01002225
willy tarreau5cbea6f2005-12-17 12:48:26 +01002226 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002227 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2228 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002229 char term;
2230
2231 term = *ptr;
2232 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002233 exp = t->proxy->req_exp;
2234 do {
2235 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2236 switch (exp->action) {
2237 case ACT_ALLOW:
2238 if (!(t->flags & SN_CLDENY))
2239 t->flags |= SN_CLALLOW;
2240 break;
2241 case ACT_REPLACE:
2242 if (!(t->flags & SN_CLDENY)) {
2243 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2244 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2245 }
2246 break;
2247 case ACT_REMOVE:
2248 if (!(t->flags & SN_CLDENY))
2249 delete_header = 1;
2250 break;
2251 case ACT_DENY:
2252 if (!(t->flags & SN_CLALLOW))
2253 t->flags |= SN_CLDENY;
2254 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002255 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002256 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002257 }
willy tarreaue39cd132005-12-17 13:00:18 +01002258 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002259 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002260 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002261
willy tarreau240afa62005-12-17 13:14:35 +01002262 /* Now look for cookies. Conforming to RFC2109, we have to support
2263 * attributes whose name begin with a '$', and associate them with
2264 * the right cookie, if we want to delete this cookie.
2265 * So there are 3 cases for each cookie read :
2266 * 1) it's a special attribute, beginning with a '$' : ignore it.
2267 * 2) it's a server id cookie that we *MAY* want to delete : save
2268 * some pointers on it (last semi-colon, beginning of cookie...)
2269 * 3) it's an application cookie : we *MAY* have to delete a previous
2270 * "special" cookie.
2271 * At the end of loop, if a "special" cookie remains, we may have to
2272 * remove it. If no application cookie persists in the header, we
2273 * *MUST* delete it
2274 */
2275 if (!delete_header && (t->proxy->cookie_name != NULL)
2276 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002277 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
2278 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002279 char *del_colon, *del_cookie, *colon;
2280 int app_cookies;
2281
willy tarreau5cbea6f2005-12-17 12:48:26 +01002282 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002283 colon = p1;
2284 /* del_cookie == NULL => nothing to be deleted */
2285 del_colon = del_cookie = NULL;
2286 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002287
2288 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002289 /* skip spaces and colons, but keep an eye on these ones */
2290 while (p1 < ptr) {
2291 if (*p1 == ';' || *p1 == ',')
2292 colon = p1;
2293 else if (!isspace((int)*p1))
2294 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002295 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002296 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002297
2298 if (p1 == ptr)
2299 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002300
2301 /* p1 is at the beginning of the cookie name */
2302 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002303 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002304 p2++;
2305
2306 if (p2 == ptr)
2307 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002308
2309 p3 = p2 + 1; /* skips the '=' sign */
2310 if (p3 == ptr)
2311 break;
2312
willy tarreau240afa62005-12-17 13:14:35 +01002313 p4 = p3;
2314 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002315 p4++;
2316
2317 /* here, we have the cookie name between p1 and p2,
2318 * and its value between p3 and p4.
2319 * we can process it.
2320 */
2321
willy tarreau240afa62005-12-17 13:14:35 +01002322 if (*p1 == '$') {
2323 /* skip this one */
2324 }
2325 else if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2326 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002327 /* Cool... it's the right one */
2328 struct server *srv = t->proxy->srv;
2329
2330 while (srv &&
2331 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2332 srv = srv->next;
2333 }
2334
2335 if (srv) { /* we found the server */
willy tarreaue39cd132005-12-17 13:00:18 +01002336 t->flags |= SN_DIRECT;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002337 t->srv = srv;
2338 }
willy tarreau240afa62005-12-17 13:14:35 +01002339 /* if this cookie was set in insert+indirect mode, then it's better that the
2340 * server never sees it.
2341 */
2342 if (del_cookie == NULL &&
2343 (t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
2344 del_cookie = p1;
2345 del_colon = colon;
2346 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002347 }
2348 else {
willy tarreau240afa62005-12-17 13:14:35 +01002349 /* now we know that we must keep this cookie since it's
2350 * not ours. But if we wanted to delete our cookie
2351 * earlier, we cannot remove the complete header, but we
2352 * can remove the previous block itself.
2353 */
2354 app_cookies++;
2355
2356 if (del_cookie != NULL) {
2357 buffer_replace2(req, del_cookie, p1, NULL, 0);
2358 p4 -= (p1 - del_cookie);
2359 ptr -= (p1 - del_cookie);
2360 del_cookie = del_colon = NULL;
2361 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002362 }
willy tarreau240afa62005-12-17 13:14:35 +01002363
willy tarreau5cbea6f2005-12-17 12:48:26 +01002364 /* we'll have to look for another cookie ... */
2365 p1 = p4;
2366 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002367
2368 /* There's no more cookie on this line.
2369 * We may have marked the last one(s) for deletion.
2370 * We must do this now in two ways :
2371 * - if there is no app cookie, we simply delete the header ;
2372 * - if there are app cookies, we must delete the end of the
2373 * string properly, including the colon/semi-colon before
2374 * the cookie name.
2375 */
2376 if (del_cookie != NULL) {
2377 if (app_cookies) {
2378 buffer_replace2(req, del_colon, ptr, NULL, 0);
2379 /* WARNING! <ptr> becomes invalid for now. If some code
2380 * below needs to rely on it before the end of the global
2381 * header loop, we need to correct it with this code :
2382 * ptr = del_colon;
2383 */
2384 }
2385 else
2386 delete_header = 1;
2387 }
2388 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002389
2390 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002391 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002392 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002393 }
willy tarreau240afa62005-12-17 13:14:35 +01002394 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2395
willy tarreau5cbea6f2005-12-17 12:48:26 +01002396 req->h = req->lr;
2397 } /* while (req->lr < req->r) */
2398
2399 /* end of header processing (even if incomplete) */
2400
willy tarreauef900ab2005-12-17 12:52:52 +01002401 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2402 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2403 * full. We cannot loop here since event_cli_read will disable it only if
2404 * req->l == rlim-data
2405 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002406 FD_SET(t->cli_fd, StaticReadEvent);
2407 if (t->proxy->clitimeout)
2408 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2409 else
2410 tv_eternity(&t->crexpire);
2411 }
2412
willy tarreaue39cd132005-12-17 13:00:18 +01002413 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002414 * won't be able to free more later, so the session will never terminate.
2415 */
willy tarreaue39cd132005-12-17 13:00:18 +01002416 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002417 t->logs.status = 400;
willy tarreaue39cd132005-12-17 13:00:18 +01002418 client_retnclose(t, strlen(HTTP_400), HTTP_400);
2419 return 1;
2420 }
2421 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2422 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2423
2424 /* read timeout, read error, or last read : give up.
2425 * since we are in header mode, if there's no space left for headers, we
2426 * won't be able to free more later, so the session will never terminate.
2427 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002428 tv_eternity(&t->crexpire);
2429 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002430 t->cli_state = CL_STCLOSE;
2431 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002432 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002433
2434 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002435 }
2436 else if (c == CL_STDATA) {
2437 /* read or write error */
2438 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002439 tv_eternity(&t->crexpire);
2440 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002441 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002442 t->cli_state = CL_STCLOSE;
2443 return 1;
2444 }
2445 /* read timeout, last read, or end of server write */
2446 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2447 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002448 FD_CLR(t->cli_fd, StaticReadEvent);
2449 // if (req->l == 0) /* nothing to write on the server side */
2450 // FD_CLR(t->srv_fd, StaticWriteEvent);
2451 tv_eternity(&t->crexpire);
2452 shutdown(t->cli_fd, SHUT_RD);
2453 t->cli_state = CL_STSHUTR;
2454 return 1;
2455 }
2456 /* write timeout, or last server read and buffer empty */
2457 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2458 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002459 FD_CLR(t->cli_fd, StaticWriteEvent);
2460 tv_eternity(&t->cwexpire);
2461 shutdown(t->cli_fd, SHUT_WR);
2462 t->cli_state = CL_STSHUTW;
2463 return 1;
2464 }
2465
willy tarreauef900ab2005-12-17 12:52:52 +01002466 if (req->l >= req->rlim - req->data) {
2467 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002468 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002469 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002470 FD_CLR(t->cli_fd, StaticReadEvent);
2471 tv_eternity(&t->crexpire);
2472 }
2473 }
2474 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002475 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002476 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2477 FD_SET(t->cli_fd, StaticReadEvent);
2478 if (t->proxy->clitimeout)
2479 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2480 else
2481 tv_eternity(&t->crexpire);
2482 }
2483 }
2484
2485 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002486 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002487 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2488 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2489 tv_eternity(&t->cwexpire);
2490 }
2491 }
2492 else { /* buffer not empty */
2493 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2494 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2495 if (t->proxy->clitimeout)
2496 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2497 else
2498 tv_eternity(&t->cwexpire);
2499 }
2500 }
2501 return 0; /* other cases change nothing */
2502 }
2503 else if (c == CL_STSHUTR) {
2504 if ((t->res_cw == RES_ERROR) ||
2505 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002506 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002507 tv_eternity(&t->cwexpire);
2508 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002509 t->cli_state = CL_STCLOSE;
2510 return 1;
2511 }
2512 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002513 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002514 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2515 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2516 tv_eternity(&t->cwexpire);
2517 }
2518 }
2519 else { /* buffer not empty */
2520 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2521 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2522 if (t->proxy->clitimeout)
2523 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2524 else
2525 tv_eternity(&t->cwexpire);
2526 }
2527 }
2528 return 0;
2529 }
2530 else if (c == CL_STSHUTW) {
2531 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002532 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002533 tv_eternity(&t->crexpire);
2534 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002535 t->cli_state = CL_STCLOSE;
2536 return 1;
2537 }
willy tarreauef900ab2005-12-17 12:52:52 +01002538 else if (req->l >= req->rlim - req->data) {
2539 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002540 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002541 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002542 FD_CLR(t->cli_fd, StaticReadEvent);
2543 tv_eternity(&t->crexpire);
2544 }
2545 }
2546 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002547 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002548 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2549 FD_SET(t->cli_fd, StaticReadEvent);
2550 if (t->proxy->clitimeout)
2551 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2552 else
2553 tv_eternity(&t->crexpire);
2554 }
2555 }
2556 return 0;
2557 }
2558 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002559 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002560 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002561 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002562 write(1, trash, len);
2563 }
2564 return 0;
2565 }
2566 return 0;
2567}
2568
2569
2570/*
2571 * manages the server FSM and its socket. It returns 1 if a state has changed
2572 * (and a resync may be needed), 0 else.
2573 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002574int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002575 int s = t->srv_state;
2576 int c = t->cli_state;
2577 struct buffer *req = t->req;
2578 struct buffer *rep = t->rep;
2579
willy tarreau5cbea6f2005-12-17 12:48:26 +01002580 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2581 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2582 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2583 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2584 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002585 if (s == SV_STIDLE) {
2586 if (c == CL_STHEADERS)
2587 return 0; /* stay in idle, waiting for data to reach the client side */
2588 else if (c == CL_STCLOSE ||
2589 c == CL_STSHUTW ||
2590 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2591 tv_eternity(&t->cnexpire);
2592 t->srv_state = SV_STCLOSE;
2593 return 1;
2594 }
2595 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002596 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002597 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2598 t->srv_state = SV_STCONN;
2599 }
2600 else { /* try again */
2601 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002602 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002603 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002604 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2605 }
2606
2607 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002608 t->srv_state = SV_STCONN;
2609 break;
2610 }
2611 }
2612 if (t->conn_retries < 0) {
2613 /* if conn_retries < 0 or other error, let's abort */
2614 tv_eternity(&t->cnexpire);
2615 t->srv_state = SV_STCLOSE;
willy tarreaua1598082005-12-17 13:08:06 +01002616 t->logs.status = 502;
willy tarreaue39cd132005-12-17 13:00:18 +01002617 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002618 }
2619 }
2620 return 1;
2621 }
2622 }
2623 else if (s == SV_STCONN) { /* connection in progress */
2624 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2625 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2626 return 0; /* nothing changed */
2627 }
2628 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2629 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2630 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002632 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002633 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002634 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002635 if (t->conn_retries >= 0) {
2636 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002637 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002638 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2639 }
2640 if (connect_server(t) == 0)
2641 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002642 }
2643 /* if conn_retries < 0 or other error, let's abort */
2644 tv_eternity(&t->cnexpire);
2645 t->srv_state = SV_STCLOSE;
2646 return 1;
2647 }
2648 else { /* no error or write 0 */
willy tarreaua1598082005-12-17 13:08:06 +01002649 t->logs.t_connect = tv_delta(&t->logs.tv_accept, &now);
2650
willy tarreau0f7af912005-12-17 12:21:26 +01002651 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2652 if (req->l == 0) /* nothing to write */
2653 FD_CLR(t->srv_fd, StaticWriteEvent);
2654 else /* need the right to write */
2655 FD_SET(t->srv_fd, StaticWriteEvent);
2656
2657 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2658 FD_SET(t->srv_fd, StaticReadEvent);
2659 if (t->proxy->srvtimeout)
2660 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2661 else
2662 tv_eternity(&t->srexpire);
2663
2664 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002665 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002666 }
willy tarreauef900ab2005-12-17 12:52:52 +01002667 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002668 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002669 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2670 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002671 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002672 return 1;
2673 }
2674 }
2675 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002676
2677 /* now parse the partial (or complete) headers */
2678 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2679 char *ptr;
2680 int delete_header;
2681
2682 ptr = rep->lr;
2683
2684 /* look for the end of the current header */
2685 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2686 ptr++;
2687
2688 if (ptr == rep->h) {
2689 char newhdr[MAXREWRITE + 1];
2690 int line, len;
2691
2692 /* we can only get here after an end of headers */
2693 /* we'll have something else to do here : add new headers ... */
2694
willy tarreaue39cd132005-12-17 13:00:18 +01002695 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002696 /* the server is known, it's not the one the client requested, we have to
2697 * insert a set-cookie here.
2698 */
2699 len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
2700 t->proxy->cookie_name, t->srv->cookie);
willy tarreau240afa62005-12-17 13:14:35 +01002701 if (t->proxy->options & PR_O_COOK_NOC)
2702 len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
2703
willy tarreau5cbea6f2005-12-17 12:48:26 +01002704 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2705 }
2706
2707 /* headers to be added */
2708 for (line = 0; line < t->proxy->nb_rspadd; line++) {
2709 len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
2710 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2711 }
2712
2713 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002714 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreaua1598082005-12-17 13:08:06 +01002715 t->logs.t_data = tv_delta(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002716 break;
2717 }
2718
2719 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2720 if (ptr > rep->r - 2) {
2721 /* this is a partial header, let's wait for more to come */
2722 rep->lr = ptr;
2723 break;
2724 }
2725
2726 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2727 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2728
2729 /* now we know that *ptr is either \r or \n,
2730 * and that there are at least 1 char after it.
2731 */
2732 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2733 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2734 else
2735 rep->lr = ptr + 2; /* \r\n or \n\r */
2736
2737 /*
2738 * now we know that we have a full header ; we can do whatever
2739 * we want with these pointers :
2740 * rep->h = beginning of header
2741 * ptr = end of header (first \r or \n)
2742 * rep->lr = beginning of next line (next rep->h)
2743 * rep->r = end of data (not used at this stage)
2744 */
2745
willy tarreaua1598082005-12-17 13:08:06 +01002746
2747 if (t->logs.logwait & LW_RESP) {
2748 t->logs.logwait &= ~LW_RESP;
2749 t->logs.status = atoi(rep->h + 9);
2750 }
2751
willy tarreau5cbea6f2005-12-17 12:48:26 +01002752 delete_header = 0;
2753
willy tarreau9fe663a2005-12-17 13:02:59 +01002754 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002755 int len, max;
2756 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2757 max = ptr - rep->h;
2758 UBOUND(max, sizeof(trash) - len - 1);
2759 len += strlcpy(trash + len, rep->h, max + 1);
2760 trash[len++] = '\n';
2761 write(1, trash, len);
2762 }
2763
2764 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002765 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
2766 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002767 char term;
2768
2769 term = *ptr;
2770 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002771 exp = t->proxy->rsp_exp;
2772 do {
2773 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2774 switch (exp->action) {
2775 case ACT_ALLOW:
2776 if (!(t->flags & SN_SVDENY))
2777 t->flags |= SN_SVALLOW;
2778 break;
2779 case ACT_REPLACE:
2780 if (!(t->flags & SN_SVDENY)) {
2781 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2782 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2783 }
2784 break;
2785 case ACT_REMOVE:
2786 if (!(t->flags & SN_SVDENY))
2787 delete_header = 1;
2788 break;
2789 case ACT_DENY:
2790 if (!(t->flags & SN_SVALLOW))
2791 t->flags |= SN_SVDENY;
2792 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002793 }
2794 break;
2795 }
willy tarreaue39cd132005-12-17 13:00:18 +01002796 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002797 *ptr = term; /* restore the string terminator */
2798 }
2799
2800 /* check for server cookies */
willy tarreau240afa62005-12-17 13:14:35 +01002801 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY)
2802 && (t->proxy->cookie_name != NULL) && (ptr >= rep->h + 12)
2803 && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002804 char *p1, *p2, *p3, *p4;
2805
2806 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2807
2808 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01002809 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002810 p1++;
2811
2812 if (p1 == ptr || *p1 == ';') /* end of cookie */
2813 break;
2814
2815 /* p1 is at the beginning of the cookie name */
2816 p2 = p1;
2817
2818 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2819 p2++;
2820
2821 if (p2 == ptr || *p2 == ';') /* next cookie */
2822 break;
2823
2824 p3 = p2 + 1; /* skips the '=' sign */
2825 if (p3 == ptr)
2826 break;
2827
2828 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01002829 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002830 p4++;
2831
2832 /* here, we have the cookie name between p1 and p2,
2833 * and its value between p3 and p4.
2834 * we can process it.
2835 */
2836
2837 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2838 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2839 /* Cool... it's the right one */
2840
2841 /* If the cookie is in insert mode on a known server, we'll delete
2842 * this occurrence because we'll insert another one later.
2843 * We'll delete it too if the "indirect" option is set and we're in
2844 * a direct access. */
2845 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01002846 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002847 /* this header must be deleted */
2848 delete_header = 1;
2849 }
2850 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2851 /* replace bytes p3->p4 with the cookie name associated
2852 * with this server since we know it.
2853 */
2854 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2855 }
2856 break;
2857 }
2858 else {
2859 // fprintf(stderr,"Ignoring unknown cookie : ");
2860 // write(2, p1, p2-p1);
2861 // fprintf(stderr," = ");
2862 // write(2, p3, p4-p3);
2863 // fprintf(stderr,"\n");
2864 }
2865 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2866 } /* we're now at the end of the cookie value */
2867 } /* end of cookie processing */
2868
2869 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002870 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002871 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01002872
willy tarreau5cbea6f2005-12-17 12:48:26 +01002873 rep->h = rep->lr;
2874 } /* while (rep->lr < rep->r) */
2875
2876 /* end of header processing (even if incomplete) */
2877
willy tarreauef900ab2005-12-17 12:52:52 +01002878 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2879 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2880 * full. We cannot loop here since event_srv_read will disable it only if
2881 * rep->l == rlim-data
2882 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002883 FD_SET(t->srv_fd, StaticReadEvent);
2884 if (t->proxy->srvtimeout)
2885 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2886 else
2887 tv_eternity(&t->srexpire);
2888 }
willy tarreau0f7af912005-12-17 12:21:26 +01002889
2890 /* read or write error */
2891 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002892 tv_eternity(&t->srexpire);
2893 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002894 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002895 t->srv_state = SV_STCLOSE;
2896 return 1;
2897 }
willy tarreauef900ab2005-12-17 12:52:52 +01002898 /* read timeout, last read, or end of client write
2899 * since we are in header mode, if there's no space left for headers, we
2900 * won't be able to free more later, so the session will never terminate.
2901 */
2902 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2903 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002904 FD_CLR(t->srv_fd, StaticReadEvent);
2905 tv_eternity(&t->srexpire);
2906 shutdown(t->srv_fd, SHUT_RD);
2907 t->srv_state = SV_STSHUTR;
2908 return 1;
2909
2910 }
2911 /* write timeout, or last client read and buffer empty */
2912 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2913 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2914 FD_CLR(t->srv_fd, StaticWriteEvent);
2915 tv_eternity(&t->swexpire);
2916 shutdown(t->srv_fd, SHUT_WR);
2917 t->srv_state = SV_STSHUTW;
2918 return 1;
2919 }
2920
2921 if (req->l == 0) {
2922 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2923 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2924 tv_eternity(&t->swexpire);
2925 }
2926 }
2927 else { /* client buffer not empty */
2928 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2929 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2930 if (t->proxy->srvtimeout)
2931 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2932 else
2933 tv_eternity(&t->swexpire);
2934 }
2935 }
2936
willy tarreau5cbea6f2005-12-17 12:48:26 +01002937 /* be nice with the client side which would like to send a complete header
2938 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2939 * would read all remaining data at once ! The client should not write past rep->lr
2940 * when the server is in header state.
2941 */
2942 //return header_processed;
2943 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002944 }
2945 else if (s == SV_STDATA) {
2946 /* read or write error */
2947 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002948 tv_eternity(&t->srexpire);
2949 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002950 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002951 t->srv_state = SV_STCLOSE;
2952 return 1;
2953 }
2954 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01002955 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2956 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002957 FD_CLR(t->srv_fd, StaticReadEvent);
2958 tv_eternity(&t->srexpire);
2959 shutdown(t->srv_fd, SHUT_RD);
2960 t->srv_state = SV_STSHUTR;
2961 return 1;
2962
2963 }
2964 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01002965 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
2966 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002967 FD_CLR(t->srv_fd, StaticWriteEvent);
2968 tv_eternity(&t->swexpire);
2969 shutdown(t->srv_fd, SHUT_WR);
2970 t->srv_state = SV_STSHUTW;
2971 return 1;
2972 }
2973 else if (req->l == 0) {
2974 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2975 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2976 tv_eternity(&t->swexpire);
2977 }
2978 }
2979 else { /* buffer not empty */
2980 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2981 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2982 if (t->proxy->srvtimeout)
2983 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2984 else
2985 tv_eternity(&t->swexpire);
2986 }
2987 }
2988
2989 if (rep->l == BUFSIZE) { /* no room to read more data */
2990 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2991 FD_CLR(t->srv_fd, StaticReadEvent);
2992 tv_eternity(&t->srexpire);
2993 }
2994 }
2995 else {
2996 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2997 FD_SET(t->srv_fd, StaticReadEvent);
2998 if (t->proxy->srvtimeout)
2999 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3000 else
3001 tv_eternity(&t->srexpire);
3002 }
3003 }
3004
3005 return 0; /* other cases change nothing */
3006 }
3007 else if (s == SV_STSHUTR) {
3008 if ((t->res_sw == RES_ERROR) ||
3009 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
3010 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003011 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003012 tv_eternity(&t->swexpire);
3013 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003014 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003015 t->srv_state = SV_STCLOSE;
3016 return 1;
3017 }
3018 else if (req->l == 0) {
3019 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3020 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3021 tv_eternity(&t->swexpire);
3022 }
3023 }
3024 else { /* buffer not empty */
3025 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3026 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3027 if (t->proxy->srvtimeout)
3028 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3029 else
3030 tv_eternity(&t->swexpire);
3031 }
3032 }
3033 return 0;
3034 }
3035 else if (s == SV_STSHUTW) {
3036 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
3037 c == CL_STSHUTW || c == CL_STCLOSE ||
3038 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003039 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003040 tv_eternity(&t->srexpire);
3041 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003042 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003043 t->srv_state = SV_STCLOSE;
3044 return 1;
3045 }
3046 else if (rep->l == BUFSIZE) { /* no room to read more data */
3047 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3048 FD_CLR(t->srv_fd, StaticReadEvent);
3049 tv_eternity(&t->srexpire);
3050 }
3051 }
3052 else {
3053 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3054 FD_SET(t->srv_fd, StaticReadEvent);
3055 if (t->proxy->srvtimeout)
3056 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3057 else
3058 tv_eternity(&t->srexpire);
3059 }
3060 }
3061 return 0;
3062 }
3063 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003064 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003065 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003066 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003067 write(1, trash, len);
3068 }
3069 return 0;
3070 }
3071 return 0;
3072}
3073
3074
willy tarreau5cbea6f2005-12-17 12:48:26 +01003075/* Processes the client and server jobs of a session task, then
3076 * puts it back to the wait queue in a clean state, or
3077 * cleans up its resources if it must be deleted. Returns
3078 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003079 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003080int process_session(struct task *t) {
3081 struct session *s = t->context;
3082 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003083
willy tarreau5cbea6f2005-12-17 12:48:26 +01003084 do {
3085 fsm_resync = 0;
3086 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3087 fsm_resync |= process_cli(s);
3088 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3089 fsm_resync |= process_srv(s);
3090 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3091 } while (fsm_resync);
3092
3093 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003094 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003095 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003096
willy tarreau5cbea6f2005-12-17 12:48:26 +01003097 tv_min(&min1, &s->crexpire, &s->cwexpire);
3098 tv_min(&min2, &s->srexpire, &s->swexpire);
3099 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003100 tv_min(&t->expire, &min1, &min2);
3101
3102 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003104
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003106 }
3107
willy tarreau5cbea6f2005-12-17 12:48:26 +01003108 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003109 actconn--;
3110
willy tarreau9fe663a2005-12-17 13:02:59 +01003111 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003112 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003113 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003114 write(1, trash, len);
3115 }
3116
willy tarreaua1598082005-12-17 13:08:06 +01003117 s->logs.t_close = tv_delta(&s->logs.tv_accept, &now);
3118 if (s->rep != NULL)
3119 s->logs.bytes = s->rep->total;
3120
willy tarreau9fe663a2005-12-17 13:02:59 +01003121 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003122 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003123 sess_log(s);
3124
willy tarreau0f7af912005-12-17 12:21:26 +01003125 /* the task MUST not be in the run queue anymore */
3126 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003128 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003129 return -1; /* rest in peace for eternity */
3130}
3131
3132
3133
3134/*
3135 * manages a server health-check. Returns
3136 * the time the task accepts to wait, or -1 for infinity.
3137 */
3138int process_chk(struct task *t) {
3139 struct server *s = t->context;
3140 int fd = s->curfd;
3141 int one = 1;
3142
willy tarreauef900ab2005-12-17 12:52:52 +01003143 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003144
3145 if (fd < 0) { /* no check currently running */
3146 //fprintf(stderr, "process_chk: 2\n");
3147 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3148 task_queue(t); /* restore t to its place in the task list */
3149 return tv_remain(&now, &t->expire);
3150 }
3151
3152 /* we'll initiate a new check */
3153 s->result = 0; /* no result yet */
3154 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003155 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003156 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3157 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3158 //fprintf(stderr, "process_chk: 3\n");
3159
3160 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
3161 /* OK, connection in progress or established */
3162
3163 //fprintf(stderr, "process_chk: 4\n");
3164
3165 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3166 fdtab[fd].owner = t;
3167 fdtab[fd].read = NULL;
3168 fdtab[fd].write = &event_srv_hck;
3169 fdtab[fd].state = FD_STCONN; /* connection in progress */
3170 FD_SET(fd, StaticWriteEvent); /* for connect status */
3171 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003172 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3173 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003174 task_queue(t); /* restore t to its place in the task list */
3175 return tv_remain(&now, &t->expire);
3176 }
3177 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3178 s->result = -1; /* a real error */
3179 }
3180 }
3181 //fprintf(stderr, "process_chk: 5\n");
3182 close(fd);
3183 }
3184
3185 if (!s->result) { /* nothing done */
3186 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003187 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003188 task_queue(t); /* restore t to its place in the task list */
3189 return tv_remain(&now, &t->expire);
3190 }
3191
3192 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003193 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003194 s->health--; /* still good */
3195 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003196 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003197 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003198 Warning("server %s DOWN.\n", s->id);
3199
willy tarreau9fe663a2005-12-17 13:02:59 +01003200 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003201 }
willy tarreauef900ab2005-12-17 12:52:52 +01003202
willy tarreau5cbea6f2005-12-17 12:48:26 +01003203 s->health = 0; /* failure */
3204 s->state &= ~SRV_RUNNING;
3205 }
3206
3207 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003208 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3209 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003210 }
3211 else {
3212 //fprintf(stderr, "process_chk: 8\n");
3213 /* there was a test running */
3214 if (s->result > 0) { /* good server detected */
3215 //fprintf(stderr, "process_chk: 9\n");
3216 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003217 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003218 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003219 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003220 Warning("server %s UP.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003221 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003222 }
willy tarreauef900ab2005-12-17 12:52:52 +01003223
willy tarreaue47c8d72005-12-17 12:55:52 +01003224 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003225 s->state |= SRV_RUNNING;
3226 }
willy tarreauef900ab2005-12-17 12:52:52 +01003227 s->curfd = -1; /* no check running anymore */
3228 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003229 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003230 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003231 }
3232 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3233 //fprintf(stderr, "process_chk: 10\n");
3234 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003235 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003236 s->health--; /* still good */
3237 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003238 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003239 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003240 Warning("server %s DOWN.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003241
3242 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003243 }
willy tarreauef900ab2005-12-17 12:52:52 +01003244
willy tarreau5cbea6f2005-12-17 12:48:26 +01003245 s->health = 0; /* failure */
3246 s->state &= ~SRV_RUNNING;
3247 }
3248 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003249 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003250 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003251 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003252 }
3253 /* if result is 0 and there's no timeout, we have to wait again */
3254 }
3255 //fprintf(stderr, "process_chk: 11\n");
3256 s->result = 0;
3257 task_queue(t); /* restore t to its place in the task list */
3258 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003259}
3260
3261
willy tarreau5cbea6f2005-12-17 12:48:26 +01003262
willy tarreau0f7af912005-12-17 12:21:26 +01003263#if STATTIME > 0
3264int stats(void);
3265#endif
3266
3267/*
3268 * Main select() loop.
3269 */
3270
3271void select_loop() {
3272 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003273 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003274 int status;
3275 int fd,i;
3276 struct timeval delta;
3277 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003278 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003279
willy tarreau5cbea6f2005-12-17 12:48:26 +01003280 tv_now(&now);
3281
3282 while (1) {
3283 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003284
willy tarreau5cbea6f2005-12-17 12:48:26 +01003285 /* look for expired tasks and add them to the run queue.
3286 */
3287 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3288 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3289 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003290 if (t->state & TASK_RUNNING)
3291 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003292
3293 /* wakeup expired entries. It doesn't matter if they are
3294 * already running because of a previous event
3295 */
3296 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003297 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003298 task_wakeup(&rq, t);
3299 }
3300 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003301 /* first non-runnable task. Use its expiration date as an upper bound */
3302 int temp_time = tv_remain(&now, &t->expire);
3303 if (temp_time)
3304 next_time = temp_time;
3305 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003306 break;
3307 }
3308 }
3309
3310 /* process each task in the run queue now. Each task may be deleted
3311 * since we only use tnext.
3312 */
3313 tnext = rq;
3314 while ((t = tnext) != NULL) {
3315 int temp_time;
3316
3317 tnext = t->rqnext;
3318 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003319 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003320 temp_time = t->process(t);
3321 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003322 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003323 }
3324
willy tarreauef900ab2005-12-17 12:52:52 +01003325 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003326
3327 /* maintain all proxies in a consistent state. This should quickly become a task */
3328 time2 = maintain_proxies();
3329 next_time = MINTIME(time2, next_time);
3330
3331 /* stop when there's no connection left and we don't allow them anymore */
3332 if (!actconn && listeners == 0)
3333 break;
3334
willy tarreau0f7af912005-12-17 12:21:26 +01003335
3336#if STATTIME > 0
3337 time2 = stats();
3338 // fprintf(stderr," stats = %d\n", time2);
3339 next_time = MINTIME(time2, next_time);
3340#endif
3341
willy tarreau5cbea6f2005-12-17 12:48:26 +01003342 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003343 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344 /* to avoid eventual select loops due to timer precision */
3345 next_time += SCHEDULER_RESOLUTION;
3346 delta.tv_sec = next_time / 1000;
3347 delta.tv_usec = (next_time % 1000) * 1000;
3348 }
3349 else if (next_time == 0) { /* allow select to return immediately when needed */
3350 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003351 }
3352
3353
3354 /* let's restore fdset state */
3355
3356 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003357 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003358 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3359 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3360 }
3361
3362// /* just a verification code, needs to be removed for performance */
3363// for (i=0; i<maxfd; i++) {
3364// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3365// abort();
3366// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3367// abort();
3368//
3369// }
3370
3371 status=select(maxfd,
3372 readnotnull ? ReadEvent : NULL,
3373 writenotnull ? WriteEvent : NULL,
3374 NULL,
3375 (next_time >= 0) ? &delta : NULL);
3376
willy tarreau5cbea6f2005-12-17 12:48:26 +01003377 /* this is an experiment on the separation of the select work */
3378 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3379 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3380
willy tarreau0f7af912005-12-17 12:21:26 +01003381 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003382
willy tarreau0f7af912005-12-17 12:21:26 +01003383 if (status > 0) { /* must proceed with events */
3384
3385 int fds;
3386 char count;
3387
3388 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3389 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3390 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3391
willy tarreau5cbea6f2005-12-17 12:48:26 +01003392 /* if we specify read first, the accepts and zero reads will be
3393 * seen first. Moreover, system buffers will be flushed faster.
3394 */
willy tarreau0f7af912005-12-17 12:21:26 +01003395 if (fdtab[fd].state == FD_STCLOSE)
3396 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003397
3398 if (FD_ISSET(fd, ReadEvent))
3399 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003400
willy tarreau5cbea6f2005-12-17 12:48:26 +01003401 if (FD_ISSET(fd, WriteEvent))
3402 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003403 }
3404 }
3405 else {
3406 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3407 }
willy tarreau0f7af912005-12-17 12:21:26 +01003408 }
3409}
3410
3411
3412#if STATTIME > 0
3413/*
3414 * Display proxy statistics regularly. It is designed to be called from the
3415 * select_loop().
3416 */
3417int stats(void) {
3418 static int lines;
3419 static struct timeval nextevt;
3420 static struct timeval lastevt;
3421 static struct timeval starttime = {0,0};
3422 unsigned long totaltime, deltatime;
3423 int ret;
3424
3425 if (tv_remain(&now, &nextevt) == 0) {
3426 deltatime = (tv_delta(&now, &lastevt)?:1);
3427 totaltime = (tv_delta(&now, &starttime)?:1);
3428
willy tarreau9fe663a2005-12-17 13:02:59 +01003429 if (global.mode & MODE_STATS) {
3430 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003431 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003432 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3433 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003434 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003435 actconn, totalconn,
3436 stats_tsk_new, stats_tsk_good,
3437 stats_tsk_left, stats_tsk_right,
3438 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3439 }
3440 }
3441
3442 tv_delayfrom(&nextevt, &now, STATTIME);
3443
3444 lastevt=now;
3445 }
3446 ret = tv_remain(&now, &nextevt);
3447 return ret;
3448}
3449#endif
3450
3451
3452/*
3453 * this function enables proxies when there are enough free sessions,
3454 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003455 * select_loop(). It returns the time left before next expiration event
3456 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003457 */
3458static int maintain_proxies(void) {
3459 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003460 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003461
3462 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003463 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003464
3465 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003466 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003467 while (p) {
3468 if (p->nbconn < p->maxconn) {
3469 if (p->state == PR_STIDLE) {
3470 FD_SET(p->listen_fd, StaticReadEvent);
3471 p->state = PR_STRUN;
3472 }
3473 }
3474 else {
3475 if (p->state == PR_STRUN) {
3476 FD_CLR(p->listen_fd, StaticReadEvent);
3477 p->state = PR_STIDLE;
3478 }
3479 }
3480 p = p->next;
3481 }
3482 }
3483 else { /* block all proxies */
3484 while (p) {
3485 if (p->state == PR_STRUN) {
3486 FD_CLR(p->listen_fd, StaticReadEvent);
3487 p->state = PR_STIDLE;
3488 }
3489 p = p->next;
3490 }
3491 }
3492
willy tarreau5cbea6f2005-12-17 12:48:26 +01003493 if (stopping) {
3494 p = proxy;
3495 while (p) {
3496 if (p->state != PR_STDISABLED) {
3497 int t;
3498 t = tv_remain(&now, &p->stop_time);
3499 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003500 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003501 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003502
willy tarreau5cbea6f2005-12-17 12:48:26 +01003503 fd_delete(p->listen_fd);
3504 p->state = PR_STDISABLED;
3505 listeners--;
3506 }
3507 else {
3508 tleft = MINTIME(t, tleft);
3509 }
3510 }
3511 p = p->next;
3512 }
3513 }
3514 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003515}
3516
3517/*
3518 * this function disables health-check servers so that the process will quickly be ignored
3519 * by load balancers.
3520 */
3521static void soft_stop(void) {
3522 struct proxy *p;
3523
3524 stopping = 1;
3525 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003526 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003527 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003528 if (p->state != PR_STDISABLED) {
3529 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01003530 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01003531 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01003532 }
willy tarreau0f7af912005-12-17 12:21:26 +01003533 p = p->next;
3534 }
3535}
3536
3537/*
3538 * upon SIGUSR1, let's have a soft stop.
3539 */
3540void sig_soft_stop(int sig) {
3541 soft_stop();
3542 signal(sig, SIG_IGN);
3543}
3544
3545
3546void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003547 struct task *t, *tnext;
3548 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003549
willy tarreau5cbea6f2005-12-17 12:48:26 +01003550 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3551 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3552 tnext = t->next;
3553 s = t->context;
3554 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3555 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3556 "req=%d, rep=%d, clifd=%d\n",
3557 s, tv_remain(&now, &t->expire),
3558 s->cli_state,
3559 s->srv_state,
3560 FD_ISSET(s->cli_fd, StaticReadEvent),
3561 FD_ISSET(s->cli_fd, StaticWriteEvent),
3562 FD_ISSET(s->srv_fd, StaticReadEvent),
3563 FD_ISSET(s->srv_fd, StaticWriteEvent),
3564 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3565 );
willy tarreau0f7af912005-12-17 12:21:26 +01003566 }
3567}
3568
willy tarreaue39cd132005-12-17 13:00:18 +01003569void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
3570 struct hdr_exp *exp;
3571
3572 while (*head != NULL)
3573 head = &(*head)->next;
3574
3575 exp = calloc(1, sizeof(struct hdr_exp));
3576
3577 exp->preg = preg;
3578 exp->replace = replace;
3579 exp->action = action;
3580 *head = exp;
3581}
3582
willy tarreau9fe663a2005-12-17 13:02:59 +01003583
willy tarreau0f7af912005-12-17 12:21:26 +01003584/*
willy tarreau9fe663a2005-12-17 13:02:59 +01003585 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01003586 */
willy tarreau9fe663a2005-12-17 13:02:59 +01003587int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01003588
willy tarreau9fe663a2005-12-17 13:02:59 +01003589 if (!strcmp(args[0], "global")) { /* new section */
3590 /* no option, nothing special to do */
3591 return 0;
3592 }
3593 else if (!strcmp(args[0], "daemon")) {
3594 global.mode |= MODE_DAEMON;
3595 }
3596 else if (!strcmp(args[0], "debug")) {
3597 global.mode |= MODE_DEBUG;
3598 }
3599 else if (!strcmp(args[0], "quiet")) {
3600 global.mode |= MODE_QUIET;
3601 }
3602 else if (!strcmp(args[0], "stats")) {
3603 global.mode |= MODE_STATS;
3604 }
3605 else if (!strcmp(args[0], "uid")) {
3606 if (global.uid != 0) {
3607 Alert("parsing [%s:%d] : <uid> already specified. Continuing.\n", file, linenum);
3608 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003609 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003610 if (*(args[1]) == 0) {
3611 Alert("parsing [%s:%d] : <uid> expects an integer argument.\n", file, linenum);
3612 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003613 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003614 global.uid = atol(args[1]);
3615 }
3616 else if (!strcmp(args[0], "gid")) {
3617 if (global.gid != 0) {
3618 Alert("parsing [%s:%d] : <gid> already specified. Continuing.\n", file, linenum);
3619 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003620 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003621 if (*(args[1]) == 0) {
3622 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003623 return -1;
3624 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003625 global.gid = atol(args[1]);
3626 }
3627 else if (!strcmp(args[0], "nbproc")) {
3628 if (global.nbproc != 0) {
3629 Alert("parsing [%s:%d] : <nbproc> already specified. Continuing.\n", file, linenum);
3630 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003631 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003632 if (*(args[1]) == 0) {
3633 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
3634 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003635 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003636 global.nbproc = atol(args[1]);
3637 }
3638 else if (!strcmp(args[0], "maxconn")) {
3639 if (global.maxconn != 0) {
3640 Alert("parsing [%s:%d] : <maxconn> already specified. Continuing.\n", file, linenum);
3641 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003642 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003643 if (*(args[1]) == 0) {
3644 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3645 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003646 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003647 global.maxconn = atol(args[1]);
3648 }
3649 else if (!strcmp(args[0], "chroot")) {
3650 if (global.chroot != NULL) {
3651 Alert("parsing [%s:%d] : <chroot> already specified. Continuing.\n", file, linenum);
3652 return 0;
3653 }
3654 if (*(args[1]) == 0) {
3655 Alert("parsing [%s:%d] : <chroot> expects a directory as an argument.\n", file, linenum);
3656 return -1;
3657 }
3658 global.chroot = strdup(args[1]);
3659 }
3660 else if (!strcmp(args[0], "log")) { /* syslog server address */
3661 struct sockaddr_in *sa;
3662 int facility;
3663
3664 if (*(args[1]) == 0 || *(args[2]) == 0) {
3665 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n", file, linenum);
3666 return -1;
3667 }
3668
3669 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3670 if (!strcmp(log_facilities[facility], args[2]))
3671 break;
3672
3673 if (facility >= NB_LOG_FACILITIES) {
3674 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3675 exit(1);
3676 }
3677
3678 sa = str2sa(args[1]);
3679 if (!sa->sin_port)
3680 sa->sin_port = htons(SYSLOG_PORT);
3681
3682 if (global.logfac1 == -1) {
3683 global.logsrv1 = *sa;
3684 global.logfac1 = facility;
3685 }
3686 else if (global.logfac2 == -1) {
3687 global.logsrv2 = *sa;
3688 global.logfac2 = facility;
3689 }
3690 else {
3691 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3692 return -1;
3693 }
3694
3695 }
3696 else {
3697 Alert("parsing [%s:%d] : unknown keyword <%s> in <global> section\n", file, linenum, args[0]);
3698 return -1;
3699 }
3700 return 0;
3701}
3702
3703
3704/*
3705 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
3706 */
3707int cfg_parse_listen(char *file, int linenum, char **args) {
3708 static struct proxy *curproxy = NULL;
3709 struct server *newsrv = NULL;
3710
3711 if (!strcmp(args[0], "listen")) { /* new proxy */
3712 if (strchr(args[2], ':') == NULL) {
3713 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3714 file, linenum);
3715 return -1;
3716 }
3717
3718 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
3719 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3720 return -1;
3721 }
3722 curproxy->next = proxy;
3723 proxy = curproxy;
3724 curproxy->id = strdup(args[1]);
3725 curproxy->listen_addr = *str2sa(args[2]);
3726 curproxy->state = PR_STNEW;
3727 /* set default values */
3728 curproxy->maxconn = cfg_maxpconn;
3729 curproxy->conn_retries = CONN_RETRIES;
3730 curproxy->options = 0;
3731 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3732 curproxy->mode = PR_MODE_TCP;
3733 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3734 curproxy->to_log = 0;
3735 return 0;
3736 }
3737 else if (curproxy == NULL) {
3738 Alert("parsing [%s:%d] : <listen> expected.\n", file, linenum);
3739 return -1;
3740 }
3741
3742 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3743 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3744 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3745 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3746 else {
3747 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3748 return -1;
3749 }
3750 }
3751 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3752 curproxy->state = PR_STDISABLED;
3753 }
3754 else if (!strcmp(args[0], "cookie")) { /* cookie name */
3755 int cur_arg;
3756 if (curproxy->cookie_name != NULL) {
3757 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3758 file, linenum);
3759 return 0;
3760 }
3761
3762 if (*(args[1]) == 0) {
3763 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3764 file, linenum);
3765 return -1;
3766 }
3767 curproxy->cookie_name = strdup(args[1]);
3768
3769 cur_arg = 2;
3770 while (*(args[cur_arg])) {
3771 if (!strcmp(args[cur_arg], "rewrite")) {
3772 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01003773 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003774 else if (!strcmp(args[cur_arg], "indirect")) {
3775 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01003776 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003777 else if (!strcmp(args[cur_arg], "insert")) {
3778 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01003779 }
willy tarreau240afa62005-12-17 13:14:35 +01003780 else if (!strcmp(args[cur_arg], "nocache")) {
3781 curproxy->options |= PR_O_COOK_NOC;
3782 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003783 else {
3784 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003785 file, linenum);
3786 return -1;
3787 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003788 cur_arg++;
3789 }
3790 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3791 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3792 file, linenum);
3793 return -1;
3794 }
3795 }
3796 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3797 if (curproxy->contimeout != 0) {
3798 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n", file, linenum);
3799 return 0;
3800 }
3801 if (*(args[1]) == 0) {
3802 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3803 file, linenum);
3804 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003805 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003806 curproxy->contimeout = atol(args[1]);
3807 }
3808 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3809 if (curproxy->clitimeout != 0) {
3810 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3811 file, linenum);
3812 return 0;
3813 }
3814 if (*(args[1]) == 0) {
3815 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3816 file, linenum);
3817 return -1;
3818 }
3819 curproxy->clitimeout = atol(args[1]);
3820 }
3821 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3822 if (curproxy->srvtimeout != 0) {
3823 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n", file, linenum);
3824 return 0;
3825 }
3826 if (*(args[1]) == 0) {
3827 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003828 file, linenum);
3829 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003830 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003831 curproxy->srvtimeout = atol(args[1]);
3832 }
3833 else if (!strcmp(args[0], "retries")) { /* connection retries */
3834 if (*(args[1]) == 0) {
3835 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3836 file, linenum);
3837 return -1;
3838 }
3839 curproxy->conn_retries = atol(args[1]);
3840 }
3841 else if (!strcmp(args[0], "option")) {
3842 if (*(args[1]) == 0) {
3843 Alert("parsing [%s:%d] : <option> expects an option name.\n", file, linenum);
3844 return -1;
3845 }
3846 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003847 /* enable reconnections to dispatch */
3848 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01003849#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003850 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003851 /* enable transparent proxy connections */
3852 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01003853#endif
3854 else if (!strcmp(args[1], "keepalive"))
3855 /* enable keep-alive */
3856 curproxy->options |= PR_O_KEEPALIVE;
3857 else if (!strcmp(args[1], "forwardfor"))
3858 /* insert x-forwarded-for field */
3859 curproxy->options |= PR_O_FWDFOR;
3860 else if (!strcmp(args[1], "httplog")) {
3861 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01003862 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
3863 }
3864 else if (!strcmp(args[1], "dontlognull")) {
3865 /* don't log empty requests */
3866 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003867 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003868 else {
3869 Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
3870 return -1;
3871 }
3872 return 0;
3873 }
3874 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3875 /* enable reconnections to dispatch */
3876 curproxy->options |= PR_O_REDISP;
3877 }
willy tarreaua1598082005-12-17 13:08:06 +01003878#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003879 else if (!strcmp(args[0], "transparent")) {
3880 /* enable transparent proxy connections */
3881 curproxy->options |= PR_O_TRANSP;
3882 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003883#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01003884 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3885 if (*(args[1]) == 0) {
3886 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3887 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003888 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003889 curproxy->maxconn = atol(args[1]);
3890 }
3891 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3892 if (*(args[1]) == 0) {
3893 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n", file, linenum);
3894 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003895 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003896 curproxy->grace = atol(args[1]);
3897 }
3898 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3899 if (strchr(args[1], ':') == NULL) {
3900 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n", file, linenum);
3901 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003902 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003903 curproxy->dispatch_addr = *str2sa(args[1]);
3904 }
3905 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
3906 if (*(args[1])) {
3907 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003908 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01003909 }
3910 else {
3911 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n", file, linenum);
3912 return -1;
3913 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003914 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003915 else /* if no option is set, use round-robin by default */
3916 curproxy->options |= PR_O_BALANCE_RR;
3917 }
3918 else if (!strcmp(args[0], "server")) { /* server address */
3919 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003920
willy tarreau9fe663a2005-12-17 13:02:59 +01003921 if (strchr(args[2], ':') == NULL) {
3922 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
3923 file, linenum);
3924 return -1;
3925 }
3926 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
3927 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3928 return -1;
3929 }
3930 newsrv->next = curproxy->srv;
3931 curproxy->srv = newsrv;
3932 newsrv->proxy = curproxy;
3933 newsrv->id = strdup(args[1]);
3934 newsrv->addr = *str2sa(args[2]);
3935 newsrv->state = SRV_RUNNING; /* early server setup */
3936 newsrv->curfd = -1; /* no health-check in progress */
3937 newsrv->inter = DEF_CHKINTR;
3938 newsrv->rise = DEF_RISETIME;
3939 newsrv->fall = DEF_FALLTIME;
3940 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
3941 cur_arg = 3;
3942 while (*args[cur_arg]) {
3943 if (!strcmp(args[cur_arg], "cookie")) {
3944 newsrv->cookie = strdup(args[cur_arg + 1]);
3945 newsrv->cklen = strlen(args[cur_arg + 1]);
3946 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01003947 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003948 else if (!strcmp(args[cur_arg], "rise")) {
3949 newsrv->rise = atol(args[cur_arg + 1]);
3950 newsrv->health = newsrv->rise;
3951 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01003952 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003953 else if (!strcmp(args[cur_arg], "fall")) {
3954 newsrv->fall = atol(args[cur_arg + 1]);
3955 cur_arg += 2;
3956 }
3957 else if (!strcmp(args[cur_arg], "inter")) {
3958 newsrv->inter = atol(args[cur_arg + 1]);
3959 cur_arg += 2;
3960 }
3961 else if (!strcmp(args[cur_arg], "check")) {
3962 struct task *t;
3963
3964 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3965 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003966 return -1;
3967 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003968
3969 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
3970 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
3971 t->state = TASK_IDLE;
3972 t->process = process_chk;
3973 t->context = newsrv;
3974
3975 if (curproxy->state != PR_STDISABLED) {
3976 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
3977 task_queue(t);
3978 task_wakeup(&rq, t);
3979 }
3980
3981 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003982 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003983 else {
3984 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
3985 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01003986 return -1;
3987 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003988 }
3989 curproxy->nbservers++;
3990 }
3991 else if (!strcmp(args[0], "log")) { /* syslog server address */
3992 struct sockaddr_in *sa;
3993 int facility;
3994
3995 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
3996 curproxy->logfac1 = global.logfac1;
3997 curproxy->logsrv1 = global.logsrv1;
3998 curproxy->logfac2 = global.logfac2;
3999 curproxy->logsrv2 = global.logsrv2;
4000 }
4001 else if (*(args[1]) && *(args[2])) {
willy tarreau0f7af912005-12-17 12:21:26 +01004002 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4003 if (!strcmp(log_facilities[facility], args[2]))
4004 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004005
willy tarreau0f7af912005-12-17 12:21:26 +01004006 if (facility >= NB_LOG_FACILITIES) {
4007 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
4008 exit(1);
4009 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004010
willy tarreau0f7af912005-12-17 12:21:26 +01004011 sa = str2sa(args[1]);
4012 if (!sa->sin_port)
4013 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004014
willy tarreau0f7af912005-12-17 12:21:26 +01004015 if (curproxy->logfac1 == -1) {
4016 curproxy->logsrv1 = *sa;
4017 curproxy->logfac1 = facility;
4018 }
4019 else if (curproxy->logfac2 == -1) {
4020 curproxy->logsrv2 = *sa;
4021 curproxy->logfac2 = facility;
4022 }
4023 else {
4024 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004025 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004026 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004027 }
4028 else {
4029 Alert("parsing [%s:%d] : <log> expects either <address[:port]> and <facility> or 'global' as arguments.\n",
4030 file, linenum);
4031 return -1;
4032 }
4033 }
willy tarreaua1598082005-12-17 13:08:06 +01004034 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
4035 if (strchr(args[1], ':') == NULL) {
4036 Alert("parsing [%s:%d] : <source> expects <addr:port> as argument.\n",
4037 file, linenum);
4038 return -1;
4039 }
4040
4041 curproxy->source_addr = *str2sa(args[1]);
4042 curproxy->options |= PR_O_BIND_SRC;
4043 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004044 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4045 regex_t *preg;
4046
4047 if (*(args[1]) == 0 || *(args[2]) == 0) {
4048 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
4049 file, linenum);
4050 return -1;
4051 }
4052
4053 preg = calloc(1, sizeof(regex_t));
4054 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4055 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4056 return -1;
4057 }
4058
4059 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4060 }
4061 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4062 regex_t *preg;
4063
4064 if (*(args[1]) == 0) {
4065 Alert("parsing [%s:%d] : <reqdel> expects <regex> as an argument.\n", file, linenum);
4066 return -1;
4067 }
4068
4069 preg = calloc(1, sizeof(regex_t));
4070 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4071 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4072 return -1;
4073 }
4074
4075 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4076 }
4077 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
4078 regex_t *preg;
4079
4080 if (*(args[1]) == 0) {
4081 Alert("parsing [%s:%d] : <reqdeny> expects <regex> as an argument.\n", file, linenum);
4082 return -1;
4083 }
4084
4085 preg = calloc(1, sizeof(regex_t));
4086 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4087 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4088 return -1;
4089 }
4090
4091 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4092 }
4093 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4094 regex_t *preg;
4095
4096 if (*(args[1]) == 0) {
4097 Alert("parsing [%s:%d] : <reqallow> expects <regex> as an argument.\n", file, linenum);
4098 return -1;
4099 }
4100
4101 preg = calloc(1, sizeof(regex_t));
4102 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4103 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4104 return -1;
4105 }
4106
4107 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4108 }
4109 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4110 regex_t *preg;
4111
4112 if (*(args[1]) == 0 || *(args[2]) == 0) {
4113 Alert("parsing [%s:%d] : <reqirep> expects <search> and <replace> as arguments.\n",
4114 file, linenum);
4115 return -1;
4116 }
4117
4118 preg = calloc(1, sizeof(regex_t));
4119 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4120 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4121 return -1;
4122 }
4123
4124 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4125 }
4126 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4127 regex_t *preg;
4128
4129 if (*(args[1]) == 0) {
4130 Alert("parsing [%s:%d] : <reqidel> expects <regex> as an argument.\n", file, linenum);
4131 return -1;
4132 }
4133
4134 preg = calloc(1, sizeof(regex_t));
4135 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4136 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4137 return -1;
4138 }
4139
4140 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4141 }
4142 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4143 regex_t *preg;
4144
4145 if (*(args[1]) == 0) {
4146 Alert("parsing [%s:%d] : <reqideny> expects <regex> as an argument.\n", file, linenum);
4147 return -1;
4148 }
4149
4150 preg = calloc(1, sizeof(regex_t));
4151 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4152 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4153 return -1;
4154 }
4155
4156 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4157 }
4158 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4159 regex_t *preg;
4160
4161 if (*(args[1]) == 0) {
4162 Alert("parsing [%s:%d] : <reqiallow> expects <regex> as an argument.\n", file, linenum);
4163 return -1;
4164 }
4165
4166 preg = calloc(1, sizeof(regex_t));
4167 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4168 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4169 return -1;
4170 }
4171
4172 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4173 }
4174 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4175 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
4176 Alert("parsing [%s:%d] : too many `reqadd'. Continuing.\n", file, linenum);
4177 return 0;
4178 }
4179
4180 if (*(args[1]) == 0) {
4181 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n", file, linenum);
4182 return -1;
4183 }
4184
4185 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004186 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004187 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004188 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004189
4190 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004191 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004192 file, linenum);
4193 return -1;
4194 }
4195
4196 preg = calloc(1, sizeof(regex_t));
4197 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4198 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4199 return -1;
4200 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004201
4202 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4203 }
4204 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4205 regex_t *preg;
4206
4207 if (*(args[1]) == 0) {
4208 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n", file, linenum);
4209 return -1;
4210 }
willy tarreaue39cd132005-12-17 13:00:18 +01004211
willy tarreau9fe663a2005-12-17 13:02:59 +01004212 preg = calloc(1, sizeof(regex_t));
4213 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4214 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4215 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004216 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004217
4218 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4219 }
4220 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004221 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004222
willy tarreau9fe663a2005-12-17 13:02:59 +01004223 if (*(args[1]) == 0 || *(args[2]) == 0) {
4224 Alert("parsing [%s:%d] : <rspirep> expects <search> and <replace> as arguments.\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01004225 file, linenum);
willy tarreaue39cd132005-12-17 13:00:18 +01004226 return -1;
4227 }
4228
4229 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004230 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreaue39cd132005-12-17 13:00:18 +01004231 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4232 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004233 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004234
4235 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4236 }
4237 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4238 regex_t *preg;
4239
4240 if (*(args[1]) == 0) {
4241 Alert("parsing [%s:%d] : <rspidel> expects <search> as an argument.\n", file, linenum);
4242 return -1;
4243 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004244
willy tarreau9fe663a2005-12-17 13:02:59 +01004245 preg = calloc(1, sizeof(regex_t));
4246 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4247 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4248 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004249 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004250
4251 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4252 }
4253 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4254 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
4255 Alert("parsing [%s:%d] : too many `rspadd'. Continuing.\n", file, linenum);
4256 return 0;
4257 }
4258
4259 if (*(args[1]) == 0) {
4260 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n", file, linenum);
4261 return -1;
4262 }
4263
4264 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4265 }
4266 else {
4267 Alert("parsing [%s:%d] : unknown keyword <%s> in <listen> section\n", file, linenum, args[0]);
4268 return -1;
4269 }
4270 return 0;
4271}
willy tarreaue39cd132005-12-17 13:00:18 +01004272
willy tarreau5cbea6f2005-12-17 12:48:26 +01004273
willy tarreau9fe663a2005-12-17 13:02:59 +01004274/*
4275 * This function reads and parses the configuration file given in the argument.
4276 * returns 0 if OK, -1 if error.
4277 */
4278int readcfgfile(char *file) {
4279 char thisline[256];
4280 char *line;
4281 FILE *f;
4282 int linenum = 0;
4283 char *end;
4284 char *args[MAX_LINE_ARGS];
4285 int arg;
4286 int cfgerr = 0;
4287 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01004288
willy tarreau9fe663a2005-12-17 13:02:59 +01004289 struct proxy *curproxy = NULL;
4290 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01004291
willy tarreau9fe663a2005-12-17 13:02:59 +01004292 if ((f=fopen(file,"r")) == NULL)
4293 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004294
willy tarreau9fe663a2005-12-17 13:02:59 +01004295 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
4296 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004297
willy tarreau9fe663a2005-12-17 13:02:59 +01004298 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004299
willy tarreau9fe663a2005-12-17 13:02:59 +01004300 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01004301 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01004302 line++;
4303
4304 arg = 0;
4305 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01004306
willy tarreau9fe663a2005-12-17 13:02:59 +01004307 while (*line && arg < MAX_LINE_ARGS) {
4308 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
4309 * C equivalent value. Other combinations left unchanged (eg: \1).
4310 */
4311 if (*line == '\\') {
4312 int skip = 0;
4313 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
4314 *line = line[1];
4315 skip = 1;
4316 }
4317 else if (line[1] == 'r') {
4318 *line = '\r';
4319 skip = 1;
4320 }
4321 else if (line[1] == 'n') {
4322 *line = '\n';
4323 skip = 1;
4324 }
4325 else if (line[1] == 't') {
4326 *line = '\t';
4327 skip = 1;
4328 }
4329 else if (line[1] == 'x' && (line + 3 < end )) {
4330 unsigned char hex1, hex2;
4331 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
4332 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4333 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4334 *line = (hex1<<4) + hex2;
4335 skip = 3;
4336 }
4337 if (skip) {
4338 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
4339 end -= skip;
4340 }
4341 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004342 }
willy tarreaua1598082005-12-17 13:08:06 +01004343 else if (*line == '#' || *line == '\n' || *line == '\r') {
4344 /* end of string, end of loop */
4345 *line = 0;
4346 break;
4347 }
willy tarreauc29948c2005-12-17 13:10:27 +01004348 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004349 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01004350 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01004351 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01004352 line++;
4353 args[++arg] = line;
4354 }
4355 else {
4356 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004357 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004358 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004359
willy tarreau9fe663a2005-12-17 13:02:59 +01004360 /* empty line */
4361 if (!**args)
4362 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01004363
willy tarreau9fe663a2005-12-17 13:02:59 +01004364 /* zero out remaining args */
4365 while (++arg < MAX_LINE_ARGS) {
4366 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004367 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004368
willy tarreau9fe663a2005-12-17 13:02:59 +01004369 if (!strcmp(args[0], "listen")) /* new proxy */
4370 confsect = CFG_LISTEN;
4371 else if (!strcmp(args[0], "global")) /* global config */
4372 confsect = CFG_GLOBAL;
4373 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004374
willy tarreau9fe663a2005-12-17 13:02:59 +01004375 switch (confsect) {
4376 case CFG_LISTEN:
4377 if (cfg_parse_listen(file, linenum, args) < 0)
4378 return -1;
4379 break;
4380 case CFG_GLOBAL:
4381 if (cfg_parse_global(file, linenum, args) < 0)
4382 return -1;
4383 break;
4384 default:
4385 Alert("parsing [%s:%d] : unknown keyword <%s> out of section.\n", file, linenum, args[0]);
4386 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004387 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004388
4389
willy tarreau0f7af912005-12-17 12:21:26 +01004390 }
4391 fclose(f);
4392
4393 /*
4394 * Now, check for the integrity of all that we have collected.
4395 */
4396
4397 if ((curproxy = proxy) == NULL) {
4398 Alert("parsing %s : no <listen> line. Nothing to do !\n",
4399 file);
4400 return -1;
4401 }
4402
4403 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01004404 if (curproxy->state == PR_STDISABLED) {
4405 curproxy = curproxy->next;
4406 continue;
4407 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004408 if ((curproxy->mode != PR_MODE_HEALTH) &&
4409 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01004410 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004411 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
4412 file, curproxy->id);
4413 cfgerr++;
4414 }
4415 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
4416 if (curproxy->options & PR_O_TRANSP) {
4417 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
4418 file, curproxy->id);
4419 cfgerr++;
4420 }
4421 else if (curproxy->srv == NULL) {
4422 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
4423 file, curproxy->id);
4424 cfgerr++;
4425 }
willy tarreaua1598082005-12-17 13:08:06 +01004426 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004427 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
4428 file, curproxy->id);
4429 }
4430 }
4431 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01004432 if (curproxy->cookie_name != NULL) {
4433 Warning("parsing %s : cookie will be ignored for listener %s.\n",
4434 file, curproxy->id);
4435 }
4436 if ((newsrv = curproxy->srv) != NULL) {
4437 Warning("parsing %s : servers will be ignored for listener %s.\n",
4438 file, curproxy->id);
4439 }
willy tarreaue39cd132005-12-17 13:00:18 +01004440 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004441 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
4442 file, curproxy->id);
4443 }
willy tarreaue39cd132005-12-17 13:00:18 +01004444 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004445 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
4446 file, curproxy->id);
4447 }
4448 }
4449 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
4450 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
4451 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
4452 file, curproxy->id);
4453 cfgerr++;
4454 }
4455 else {
4456 while (newsrv != NULL) {
4457 /* nothing to check for now */
4458 newsrv = newsrv->next;
4459 }
4460 }
4461 }
4462 curproxy = curproxy->next;
4463 }
4464 if (cfgerr > 0) {
4465 Alert("Errors found in configuration file, aborting.\n");
4466 return -1;
4467 }
4468 else
4469 return 0;
4470}
4471
4472
4473/*
4474 * This function initializes all the necessary variables. It only returns
4475 * if everything is OK. If something fails, it exits.
4476 */
4477void init(int argc, char **argv) {
4478 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01004479 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004480 char *old_argv = *argv;
4481 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01004482 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01004483
4484 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004485 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004486 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
4487 sizeof(int)*8);
4488 exit(1);
4489 }
4490
4491 pid = getpid();
4492 progname = *argv;
4493 while ((tmp = strchr(progname, '/')) != NULL)
4494 progname = tmp + 1;
4495
4496 argc--; argv++;
4497 while (argc > 0) {
4498 char *flag;
4499
4500 if (**argv == '-') {
4501 flag = *argv+1;
4502
4503 /* 1 arg */
4504 if (*flag == 'v') {
4505 display_version();
4506 exit(0);
4507 }
4508 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01004509 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01004510 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01004511 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004512 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01004513 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01004514#if STATTIME > 0
4515 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01004516 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01004517 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01004518 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01004519#endif
4520 else { /* >=2 args */
4521 argv++; argc--;
4522 if (argc == 0)
4523 usage(old_argv);
4524
4525 switch (*flag) {
4526 case 'n' : cfg_maxconn = atol(*argv); break;
4527 case 'N' : cfg_maxpconn = atol(*argv); break;
4528 case 'f' : cfg_cfgfile = *argv; break;
4529 default: usage(old_argv);
4530 }
4531 }
4532 }
4533 else
4534 usage(old_argv);
4535 argv++; argc--;
4536 }
4537
willy tarreau0f7af912005-12-17 12:21:26 +01004538 if (!cfg_cfgfile)
4539 usage(old_argv);
4540
4541 gethostname(hostname, MAX_HOSTNAME_LEN);
4542
4543 if (readcfgfile(cfg_cfgfile) < 0) {
4544 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
4545 exit(1);
4546 }
4547
willy tarreau9fe663a2005-12-17 13:02:59 +01004548 if (cfg_maxconn > 0)
4549 global.maxconn = cfg_maxconn;
4550
4551 if (global.maxconn == 0)
4552 global.maxconn = DEFAULT_MAXCONN;
4553
4554 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
4555
4556 if (arg_mode & MODE_DEBUG) {
4557 /* command line debug mode inhibits configuration mode */
4558 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4559 }
4560 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG));
4561
4562 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
4563 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
4564 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4565 }
4566
4567 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
4568 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
4569 global.nbproc = 1;
4570 }
4571
4572 if (global.nbproc < 1)
4573 global.nbproc = 1;
4574
willy tarreau0f7af912005-12-17 12:21:26 +01004575 ReadEvent = (fd_set *)calloc(1,
4576 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004577 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004578 WriteEvent = (fd_set *)calloc(1,
4579 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004580 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004581 StaticReadEvent = (fd_set *)calloc(1,
4582 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004583 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004584 StaticWriteEvent = (fd_set *)calloc(1,
4585 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004586 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004587
4588 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01004589 sizeof(struct fdtab) * (global.maxsock));
4590 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004591 fdtab[i].state = FD_STCLOSE;
4592 }
4593}
4594
4595/*
4596 * this function starts all the proxies. It returns 0 if OK, -1 if not.
4597 */
4598int start_proxies() {
4599 struct proxy *curproxy;
4600 int one = 1;
4601 int fd;
4602
4603 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
4604
4605 if (curproxy->state == PR_STDISABLED)
4606 continue;
4607
4608 if ((fd = curproxy->listen_fd =
4609 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
4610 Alert("cannot create listening socket for proxy %s. Aborting.\n",
4611 curproxy->id);
4612 return -1;
4613 }
4614
willy tarreau9fe663a2005-12-17 13:02:59 +01004615 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004616 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
4617 curproxy->id);
4618 close(fd);
4619 return -1;
4620 }
4621
willy tarreau0f7af912005-12-17 12:21:26 +01004622 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
4623 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
4624 (char *) &one, sizeof(one)) == -1)) {
4625 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
4626 curproxy->id);
4627 close(fd);
4628 return -1;
4629 }
4630
4631 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
4632 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
4633 curproxy->id);
4634 }
4635
4636 if (bind(fd,
4637 (struct sockaddr *)&curproxy->listen_addr,
4638 sizeof(curproxy->listen_addr)) == -1) {
4639 Alert("cannot bind socket for proxy %s. Aborting.\n",
4640 curproxy->id);
4641 close(fd);
4642 return -1;
4643 }
4644
4645 if (listen(fd, curproxy->maxconn) == -1) {
4646 Alert("cannot listen to socket for proxy %s. Aborting.\n",
4647 curproxy->id);
4648 close(fd);
4649 return -1;
4650 }
4651
4652 /* the function for the accept() event */
4653 fdtab[fd].read = &event_accept;
4654 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004655 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01004656 curproxy->state = PR_STRUN;
4657 fdtab[fd].state = FD_STLISTEN;
4658 FD_SET(fd, StaticReadEvent);
4659 fd_insert(fd);
4660 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01004661
willy tarreaua1598082005-12-17 13:08:06 +01004662 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004663
willy tarreau0f7af912005-12-17 12:21:26 +01004664 }
4665 return 0;
4666}
4667
4668
4669int main(int argc, char **argv) {
4670 init(argc, argv);
4671
willy tarreau9fe663a2005-12-17 13:02:59 +01004672 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01004673 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004674 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01004675 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01004676 }
4677
4678 signal(SIGQUIT, dump);
4679 signal(SIGUSR1, sig_soft_stop);
4680
4681 /* on very high loads, a sigpipe sometimes happen just between the
4682 * getsockopt() which tells "it's OK to write", and the following write :-(
4683 */
willy tarreau3242e862005-12-17 12:27:53 +01004684#ifndef MSG_NOSIGNAL
4685 signal(SIGPIPE, SIG_IGN);
4686#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004687
4688 if (start_proxies() < 0)
4689 exit(1);
4690
willy tarreau9fe663a2005-12-17 13:02:59 +01004691 /* open log files */
4692
4693 /* chroot if needed */
4694 if (global.chroot != NULL) {
4695 if (chroot(global.chroot) == -1) {
4696 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
4697 exit(1);
4698 }
4699 chdir("/");
4700 }
4701
4702 /* setgid / setuid */
4703 if (global.gid && setregid(global.gid, global.gid) == -1) {
4704 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
4705 exit(1);
4706 }
4707
4708 if (global.uid && setreuid(global.uid, global.uid) == -1) {
4709 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
4710 exit(1);
4711 }
4712
4713 if (global.mode & MODE_DAEMON) {
4714 int ret = 0;
4715 int proc;
4716
4717 /* the father launches the required number of processes */
4718 for (proc = 0; proc < global.nbproc; proc++) {
4719 ret = fork();
4720 if (ret < 0) {
4721 Alert("[%s.main()] Cannot fork.\n", argv[0]);
4722 exit(1); /* there has been an error */
4723 }
4724 else if (ret == 0) /* child breaks here */
4725 break;
4726 }
4727 if (proc == global.nbproc)
4728 exit(0); /* parent must leave */
4729
willy tarreaua1598082005-12-17 13:08:06 +01004730 pid = getpid(); /* update child's pid */
willy tarreau9fe663a2005-12-17 13:02:59 +01004731 setpgid(1, 0);
4732 }
4733
willy tarreau0f7af912005-12-17 12:21:26 +01004734 select_loop();
4735
4736 exit(0);
4737}
willy tarreaua1598082005-12-17 13:08:06 +01004738