blob: 67df4b1b8c063d5d79a19bab066f2cb5fc916bbb [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 tarreauc29948c2005-12-17 13:10:27 +010020 * 2002/04/19 : 1.1.9
21 * - don't use snprintf()'s return value as an end of message since it may
22 * be larger. This caused bus errors and segfaults in internal libc's
23 * getenv() during localtime() in send_log().
24 * - removed dead insecure send_syslog() function and all references to it.
25 * - fixed warnings on Solaris due to buggy implementation of isXXXX().
willy tarreaua1598082005-12-17 13:08:06 +010026 * 2002/04/18 : 1.1.8
27 * - option "dontlognull"
28 * - fixed "double space" bug in config parser
29 * - fixed an uninitialized server field in case of dispatch
30 * with no existing server which could cause a segfault during
31 * logging.
32 * - the pid logged was always the father's, which was wrong for daemons.
33 * - fixed wrong level "LOG_INFO" for message "proxy started".
34 * 2002/04/13 :
35 * - http logging is now complete :
36 * - ip:port, date, proxy, server
37 * - req_time, conn_time, hdr_time, tot_time
38 * - status, size, request
39 * - source address
willy tarreau9fe663a2005-12-17 13:02:59 +010040 * 2002/04/12 : 1.1.7
41 * - added option forwardfor
42 * - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel
43 * - added "log global" in "listen" section.
44 * 2002/04/09 :
45 * - added a new "global" section :
46 * - logs
47 * - debug, quiet, daemon modes
48 * - uid, gid, chroot, nbproc, maxconn
willy tarreaue39cd132005-12-17 13:00:18 +010049 * 2002/04/08 : 1.1.6
50 * - regex are now chained and not limited anymore.
51 * - unavailable server now returns HTTP/502.
52 * - increased per-line args limit to 40
53 * - added reqallow/reqdeny to block some request on matches
54 * - added HTTP 400/403 responses
55 * 2002/04/03 : 1.1.5
willy tarreau535ae7a2005-12-17 12:58:00 +010056 * - connection logging displayed incorrect source address.
57 * - added proxy start/stop and server up/down log events.
58 * - replaced log message short buffers with larger trash.
59 * - enlarged buffer to 8 kB and replace buffer to 4 kB.
willy tarreaue39cd132005-12-17 13:00:18 +010060 * 2002/03/25 : 1.1.4
willy tarreaue47c8d72005-12-17 12:55:52 +010061 * - made rise/fall/interval time configurable
willy tarreaue39cd132005-12-17 13:00:18 +010062 * 2002/03/22 : 1.1.3
willy tarreaub719f002005-12-17 12:55:07 +010063 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
64 * which could lead to loops.
willy tarreaue39cd132005-12-17 13:00:18 +010065 * 2002/03/21 : 1.1.2
willy tarreauef900ab2005-12-17 12:52:52 +010066 * - fixed a bug in buffer management where we could have a loop
67 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
68 * => implemented an adjustable buffer limit.
69 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
70 * and running tasks are skipped.
71 * - added some debug lines for accept events.
72 * - send warnings for servers up/down.
willy tarreaue39cd132005-12-17 13:00:18 +010073 * 2002/03/12 : 1.1.1
willy tarreauefae1842005-12-17 12:51:03 +010074 * - fixed a bug in total failure handling
75 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreaue39cd132005-12-17 13:00:18 +010076 * 2002/03/10 : 1.1.0
willy tarreau5cbea6f2005-12-17 12:48:26 +010077 * - fixed a few timeout bugs
78 * - rearranged the task scheduler subsystem to improve performance,
79 * add new tasks, and make it easier to later port to librt ;
80 * - allow multiple accept() for one select() wake up ;
81 * - implemented internal load balancing with basic health-check ;
82 * - cookie insertion and header add/replace/delete, with better strings
83 * support.
84 * 2002/03/08
85 * - reworked buffer handling to fix a few rewrite bugs, and
86 * improve overall performance.
87 * - implement the "purge" option to delete server cookies in direct mode.
88 * 2002/03/07
89 * - fixed some error cases where the maxfd was not decreased.
90 * 2002/02/26
91 * - now supports transparent proxying, at least on linux 2.4.
92 * 2002/02/12
93 * - soft stop works again (fixed select timeout computation).
94 * - it seems that TCP proxies sometimes cannot timeout.
95 * - added a "quiet" mode.
96 * - enforce file descriptor limitation on socket() and accept().
97 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +010098 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +010099 * 2001/12/16 : release of version 1.0.0.
100 * 2001/12/16 : added syslog capability for each accepted connection.
101 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
102 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
103 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
104 * with or without cookies (use keyword http for this).
105 * 2001/09/01 : added client/server header replacing with regexps.
106 * eg:
107 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
108 * srvexp ^Server:\ .* Server:\ Apache
109 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
110 * 2000/11/28 : major rewrite
111 * 2000/11/26 : first write
112 *
willy tarreau5cbea6f2005-12-17 12:48:26 +0100113 * TODO:
114 * - handle properly intermediate incomplete server headers. Done ?
115 * - log proxies start/stop
116 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +0100117 *
118 */
119
120#include <stdio.h>
121#include <stdlib.h>
122#include <unistd.h>
123#include <string.h>
124#include <ctype.h>
125#include <sys/time.h>
126#include <sys/types.h>
127#include <sys/socket.h>
128#include <netinet/tcp.h>
129#include <netinet/in.h>
130#include <arpa/inet.h>
131#include <netdb.h>
132#include <fcntl.h>
133#include <errno.h>
134#include <signal.h>
135#include <stdarg.h>
136#include <sys/resource.h>
137#include <time.h>
138#include <regex.h>
139#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +0100140#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100141#include <linux/netfilter_ipv4.h>
142#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100143
willy tarreauc29948c2005-12-17 13:10:27 +0100144#define HAPROXY_VERSION "1.1.9"
145#define HAPROXY_DATE "2002/04/19"
willy tarreau0f7af912005-12-17 12:21:26 +0100146
147/* this is for libc5 for example */
148#ifndef TCP_NODELAY
149#define TCP_NODELAY 1
150#endif
151
152#ifndef SHUT_RD
153#define SHUT_RD 0
154#endif
155
156#ifndef SHUT_WR
157#define SHUT_WR 1
158#endif
159
willy tarreau535ae7a2005-12-17 12:58:00 +0100160#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +0100161
162// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +0100163#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +0100164#define REQURI_LEN 1024
willy tarreau0f7af912005-12-17 12:21:26 +0100165
willy tarreau5cbea6f2005-12-17 12:48:26 +0100166// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100167#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100168
willy tarreaue39cd132005-12-17 13:00:18 +0100169// max # of added headers per request
170#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100171
172// max # of matches per regexp
173#define MAX_MATCH 10
174
willy tarreau5cbea6f2005-12-17 12:48:26 +0100175/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100176#define COOKIENAME_LEN 16
177#define SERVERID_LEN 16
178#define CONN_RETRIES 3
179
willy tarreau5cbea6f2005-12-17 12:48:26 +0100180#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100181#define DEF_CHKINTR 2000
182#define DEF_FALLTIME 3
183#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100184
willy tarreau9fe663a2005-12-17 13:02:59 +0100185/* default connections limit */
186#define DEFAULT_MAXCONN 2000
187
willy tarreau0f7af912005-12-17 12:21:26 +0100188/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
189#define INTBITS 5
190
191/* show stats this every millisecond, 0 to disable */
192#ifndef STATTIME
193#define STATTIME 2000
194#endif
195
willy tarreau5cbea6f2005-12-17 12:48:26 +0100196/* this reduces the number of calls to select() by choosing appropriate
197 * sheduler precision in milliseconds. It should be near the minimum
198 * time that is needed by select() to collect all events. All timeouts
199 * are rounded up by adding this value prior to pass it to select().
200 */
201#define SCHEDULER_RESOLUTION 9
202
willy tarreau0f7af912005-12-17 12:21:26 +0100203#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
204#define SETNOW(a) (*a=now)
205
willy tarreau9da061b2005-12-17 12:29:56 +0100206/****** string-specific macros and functions ******/
207/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
208#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
209
210/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
211#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
212
213
214#ifndef HAVE_STRLCPY
215/*
216 * copies at most <size-1> chars from <src> to <dst>. Last char is always
217 * set to 0, unless <size> is 0. The number of chars copied is returned
218 * (excluding the terminating zero).
219 * This code has been optimized for size and speed : on x86, it's 45 bytes
220 * long, uses only registers, and consumes only 4 cycles per char.
221 */
222int strlcpy(char *dst, const char *src, int size) {
223 char *orig = dst;
224 if (size) {
225 while (--size && (*dst = *src)) {
226 src++; dst++;
227 }
228 *dst = 0;
229 }
230 return dst - orig;
231}
232#endif
233
234
willy tarreau0f7af912005-12-17 12:21:26 +0100235#define MEM_OPTIM
236#ifdef MEM_OPTIM
237/*
238 * Returns a pointer to type <type> taken from the
239 * pool <pool_type> or dynamically allocated. In the
240 * first case, <pool_type> is updated to point to the
241 * next element in the list.
242 */
243#define pool_alloc(type) ({ \
244 void *p; \
245 if ((p = pool_##type) == NULL) \
246 p = malloc(sizeof_##type); \
247 else { \
248 pool_##type = *(void **)pool_##type; \
249 } \
250 p; \
251})
252
253/*
254 * Puts a memory area back to the corresponding pool.
255 * Items are chained directly through a pointer that
256 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100257 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100258 * that each memory area is at least as big as one
259 * pointer.
260 */
261#define pool_free(type, ptr) ({ \
262 *(void **)ptr = (void *)pool_##type; \
263 pool_##type = (void *)ptr; \
264})
265
266#else
267#define pool_alloc(type) (calloc(1,sizeof_##type));
268#define pool_free(type, ptr) (free(ptr));
269#endif /* MEM_OPTIM */
270
willy tarreau5cbea6f2005-12-17 12:48:26 +0100271#define sizeof_task sizeof(struct task)
272#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100273#define sizeof_buffer sizeof(struct buffer)
274#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100275#define sizeof_requri REQURI_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100276
willy tarreau5cbea6f2005-12-17 12:48:26 +0100277/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100278#define FD_STCLOSE 0
279#define FD_STLISTEN 1
280#define FD_STCONN 2
281#define FD_STREADY 3
282#define FD_STERROR 4
283
willy tarreau5cbea6f2005-12-17 12:48:26 +0100284/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100285#define TASK_IDLE 0
286#define TASK_RUNNING 1
287
willy tarreau5cbea6f2005-12-17 12:48:26 +0100288/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100289#define PR_STNEW 0
290#define PR_STIDLE 1
291#define PR_STRUN 2
292#define PR_STDISABLED 3
293
willy tarreau5cbea6f2005-12-17 12:48:26 +0100294/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100295#define PR_MODE_TCP 0
296#define PR_MODE_HTTP 1
297#define PR_MODE_HEALTH 2
298
willy tarreau5cbea6f2005-12-17 12:48:26 +0100299/* bits for proxy->options */
300#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
301#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
302#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
303#define PR_O_COOK_IND 8 /* keep only indirect cookies */
304#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
305#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
306#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
307#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100308#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
309#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100310#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
311#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau9fe663a2005-12-17 13:02:59 +0100312
willy tarreau5cbea6f2005-12-17 12:48:26 +0100313
willy tarreaue39cd132005-12-17 13:00:18 +0100314/* various session flags */
315#define SN_DIRECT 1 /* connection made on the server matching the client cookie */
316#define SN_CLDENY 2 /* a client header matches a deny regex */
317#define SN_CLALLOW 4 /* a client header matches an allow regex */
318#define SN_SVDENY 8 /* a server header matches a deny regex */
319#define SN_SVALLOW 16 /* a server header matches an allow regex */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100320
321/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100322#define CL_STHEADERS 0
323#define CL_STDATA 1
324#define CL_STSHUTR 2
325#define CL_STSHUTW 3
326#define CL_STCLOSE 4
327
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100329#define SV_STIDLE 0
330#define SV_STCONN 1
331#define SV_STHEADERS 2
332#define SV_STDATA 3
333#define SV_STSHUTR 4
334#define SV_STSHUTW 5
335#define SV_STCLOSE 6
336
337/* result of an I/O event */
338#define RES_SILENT 0 /* didn't happen */
339#define RES_DATA 1 /* data were sent or received */
340#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
341#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
342
willy tarreau9fe663a2005-12-17 13:02:59 +0100343/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100344#define MODE_DEBUG 1
345#define MODE_STATS 2
346#define MODE_LOG 4
347#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100348#define MODE_QUIET 16
349
350/* server flags */
351#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100352
willy tarreaue39cd132005-12-17 13:00:18 +0100353/* what to do when a header matches a regex */
354#define ACT_ALLOW 0 /* allow the request */
355#define ACT_REPLACE 1 /* replace the matching header */
356#define ACT_REMOVE 2 /* remove the matching header */
357#define ACT_DENY 3 /* deny the request */
358
willy tarreau9fe663a2005-12-17 13:02:59 +0100359/* configuration sections */
360#define CFG_NONE 0
361#define CFG_GLOBAL 1
362#define CFG_LISTEN 2
363
willy tarreaua1598082005-12-17 13:08:06 +0100364/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100365#define LW_DATE 1 /* date */
366#define LW_CLIP 2 /* CLient IP */
367#define LW_SVIP 4 /* SerVer IP */
368#define LW_SVID 8 /* server ID */
369#define LW_REQ 16 /* http REQuest */
370#define LW_RESP 32 /* http RESPonse */
371#define LW_PXIP 64 /* proxy IP */
372#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100373#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100374
willy tarreau0f7af912005-12-17 12:21:26 +0100375/*********************************************************************/
376
377#define LIST_HEAD(a) ((void *)(&(a)))
378
379/*********************************************************************/
380
381struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100382 struct hdr_exp *next;
383 regex_t *preg; /* expression to look for */
384 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
385 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100386};
387
388struct buffer {
389 unsigned int l; /* data length */
390 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100391 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100392 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100393 char data[BUFSIZE];
394};
395
396struct server {
397 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100398 int state; /* server state (SRV_*) */
399 int cklen; /* the len of the cookie, to speed up checks */
400 char *cookie; /* the id set in the cookie */
401 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100402 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100403 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100404 int rise, fall; /* time in iterations */
405 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100406 int result; /* 0 = connect OK, -1 = connect KO */
407 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100408 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100409};
410
willy tarreau5cbea6f2005-12-17 12:48:26 +0100411/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100412struct task {
413 struct task *next, *prev; /* chaining ... */
414 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100415 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100416 int state; /* task state : IDLE or RUNNING */
417 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100418 int (*process)(struct task *t); /* the function which processes the task */
419 void *context; /* the task's context */
420};
421
422/* WARNING: if new fields are added, they must be initialized in event_accept() */
423struct session {
424 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100425 /* application specific below */
426 struct timeval crexpire; /* expiration date for a client read */
427 struct timeval cwexpire; /* expiration date for a client write */
428 struct timeval srexpire; /* expiration date for a server read */
429 struct timeval swexpire; /* expiration date for a server write */
430 struct timeval cnexpire; /* expiration date for a connect */
431 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
432 struct proxy *proxy; /* the proxy this socket belongs to */
433 int cli_fd; /* the client side fd */
434 int srv_fd; /* the server side fd */
435 int cli_state; /* state of the client side */
436 int srv_state; /* state of the server side */
437 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100438 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100439 struct buffer *req; /* request buffer */
440 struct buffer *rep; /* response buffer */
441 struct sockaddr_in cli_addr; /* the client address */
442 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100443 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100444 struct {
445 int logwait; /* log fields waiting to be collected : LW_* */
446 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
447 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
448 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
449 long t_data; /* delay before the first data byte from the server ... */
450 unsigned long t_close; /* total session duration */
451 char *uri; /* first line if log needed, NULL otherwise */
452 int status; /* HTTP status from the server, negative if from proxy */
453 long long bytes; /* number of bytes transferred from the server */
454 } logs;
willy tarreau0f7af912005-12-17 12:21:26 +0100455};
456
457struct proxy {
458 int listen_fd; /* the listen socket */
459 int state; /* proxy state */
460 struct sockaddr_in listen_addr; /* the address we listen to */
461 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100462 struct server *srv, *cursrv; /* known servers, current server */
463 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100464 char *cookie_name; /* name of the cookie to look for */
465 int clitimeout; /* client I/O timeout (in milliseconds) */
466 int srvtimeout; /* server I/O timeout (in milliseconds) */
467 int contimeout; /* connect timeout (in milliseconds) */
468 char *id; /* proxy id */
469 int nbconn; /* # of active sessions */
470 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100471 int conn_retries; /* maximum number of connect retries */
472 int options; /* PR_O_REDISP, PR_O_TRANSP */
473 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100474 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100475 struct proxy *next;
476 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
477 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau9fe663a2005-12-17 13:02:59 +0100478 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100479 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100480 int nb_reqadd, nb_rspadd;
481 struct hdr_exp *req_exp; /* regular expressions for request headers */
482 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
483 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100484 int grace; /* grace time after stop request */
485};
486
487/* info about one given fd */
488struct fdtab {
489 int (*read)(int fd); /* read function */
490 int (*write)(int fd); /* write function */
491 struct task *owner; /* the session (or proxy) associated with this fd */
492 int state; /* the state of this fd */
493};
494
495/*********************************************************************/
496
willy tarreau0f7af912005-12-17 12:21:26 +0100497int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100498char *cfg_cfgfile = NULL; /* configuration file */
499char *progname = NULL; /* program name */
500int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100501
502/* global options */
503static struct {
504 int uid;
505 int gid;
506 int nbproc;
507 int maxconn;
508 int maxsock; /* max # of sockets */
509 int mode;
510 char *chroot;
511 int logfac1, logfac2;
512 struct sockaddr_in logsrv1, logsrv2;
513} global = {
514 logfac1 : -1,
515 logfac2 : -1,
516 /* others NULL OK */
517};
518
willy tarreau0f7af912005-12-17 12:21:26 +0100519/*********************************************************************/
520
521fd_set *ReadEvent,
522 *WriteEvent,
523 *StaticReadEvent,
524 *StaticWriteEvent;
525
526void **pool_session = NULL,
527 **pool_buffer = NULL,
528 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100529 **pool_requri = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100530 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100531
532struct proxy *proxy = NULL; /* list of all existing proxies */
533struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100534struct task *rq = NULL; /* global run queue */
535struct task wait_queue = { /* global wait queue */
536 prev:LIST_HEAD(wait_queue),
537 next:LIST_HEAD(wait_queue)
538};
willy tarreau0f7af912005-12-17 12:21:26 +0100539
willy tarreau0f7af912005-12-17 12:21:26 +0100540static int totalconn = 0; /* total # of terminated sessions */
541static int actconn = 0; /* # of active sessions */
542static int maxfd = 0; /* # of the highest fd + 1 */
543static int listeners = 0; /* # of listeners */
544static int stopping = 0; /* non zero means stopping in progress */
545static struct timeval now = {0,0}; /* the current date at any moment */
546
547static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
548static char trash[BUFSIZE];
549
550/*
551 * Syslog facilities and levels
552 */
553
554#define MAX_SYSLOG_LEN 1024
555#define NB_LOG_FACILITIES 24
556const char *log_facilities[NB_LOG_FACILITIES] = {
557 "kern", "user", "mail", "daemon",
558 "auth", "syslog", "lpr", "news",
559 "uucp", "cron", "auth2", "ftp",
560 "ntp", "audit", "alert", "cron2",
561 "local0", "local1", "local2", "local3",
562 "local4", "local5", "local6", "local7"
563};
564
565
566#define NB_LOG_LEVELS 8
567const char *log_levels[NB_LOG_LEVELS] = {
568 "emerg", "alert", "crit", "err",
569 "warning", "notice", "info", "debug"
570};
571
572#define SYSLOG_PORT 514
573
574const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
575 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
576#define MAX_HOSTNAME_LEN 32
577static char hostname[MAX_HOSTNAME_LEN] = "";
578
willy tarreaua1598082005-12-17 13:08:06 +0100579const char *HTTP_400 =
580 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100581 "Cache-Control: no-cache\r\n"
582 "Connection: close\r\n"
583 "\r\n"
willy tarreaua1598082005-12-17 13:08:06 +0100584 "400 Bad request : Your browser sent an invalid request.\r\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100585
willy tarreaua1598082005-12-17 13:08:06 +0100586const char *HTTP_403 =
587 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100588 "Cache-Control: no-cache\r\n"
589 "Connection: close\r\n"
590 "\r\n"
willy tarreaua1598082005-12-17 13:08:06 +0100591 "403 Forbidden : Request forbidden by administrative rules.\r\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100592
593const char *HTTP_502 =
594 "HTTP/1.0 502 Proxy Error\r\n"
595 "Cache-Control: no-cache\r\n"
596 "Connection: close\r\n"
597 "\r\n"
598 "502 Proxy Error : No server is available to handle this request.\r\n";
599
willy tarreau0f7af912005-12-17 12:21:26 +0100600/*********************************************************************/
601/* statistics ******************************************************/
602/*********************************************************************/
603
604static int stats_tsk_lsrch, stats_tsk_rsrch,
605 stats_tsk_good, stats_tsk_right, stats_tsk_left,
606 stats_tsk_new, stats_tsk_nsrch;
607
608
609/*********************************************************************/
610/* function prototypes *********************************************/
611/*********************************************************************/
612
613int event_accept(int fd);
614int event_cli_read(int fd);
615int event_cli_write(int fd);
616int event_srv_read(int fd);
617int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100618int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100619
620/*********************************************************************/
621/* general purpose functions ***************************************/
622/*********************************************************************/
623
624void display_version() {
625 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100626 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100627}
628
629/*
630 * This function prints the command line usage and exits
631 */
632void usage(char *name) {
633 display_version();
634 fprintf(stderr,
635 "Usage : %s -f <cfgfile> [ -vd"
636#if STATTIME > 0
637 "sl"
638#endif
639 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
640 " -v displays version\n"
641 " -d enters debug mode\n"
642#if STATTIME > 0
643 " -s enables statistics output\n"
644 " -l enables long statistics format\n"
645#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100646 " -D goes daemon ; implies -q\n"
647 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100648 " -n sets the maximum total # of connections (%d)\n"
649 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100650 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100651 exit(1);
652}
653
654
655/*
656 * Displays the message on stderr with the date and pid.
657 */
658void Alert(char *fmt, ...) {
659 va_list argp;
660 struct timeval tv;
661 struct tm *tm;
662
willy tarreau9fe663a2005-12-17 13:02:59 +0100663 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100664 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100665
willy tarreau5cbea6f2005-12-17 12:48:26 +0100666 gettimeofday(&tv, NULL);
667 tm=localtime(&tv.tv_sec);
668 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100669 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100670 vfprintf(stderr, fmt, argp);
671 fflush(stderr);
672 va_end(argp);
673 }
willy tarreau0f7af912005-12-17 12:21:26 +0100674}
675
676
677/*
678 * Displays the message on stderr with the date and pid.
679 */
680void Warning(char *fmt, ...) {
681 va_list argp;
682 struct timeval tv;
683 struct tm *tm;
684
willy tarreau9fe663a2005-12-17 13:02:59 +0100685 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100686 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100687
willy tarreau5cbea6f2005-12-17 12:48:26 +0100688 gettimeofday(&tv, NULL);
689 tm=localtime(&tv.tv_sec);
690 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100691 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100692 vfprintf(stderr, fmt, argp);
693 fflush(stderr);
694 va_end(argp);
695 }
696}
697
698/*
699 * Displays the message on <out> only if quiet mode is not set.
700 */
701void qfprintf(FILE *out, char *fmt, ...) {
702 va_list argp;
703
willy tarreau9fe663a2005-12-17 13:02:59 +0100704 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100705 va_start(argp, fmt);
706 vfprintf(out, fmt, argp);
707 fflush(out);
708 va_end(argp);
709 }
willy tarreau0f7af912005-12-17 12:21:26 +0100710}
711
712
713/*
714 * converts <str> to a struct sockaddr_in* which is locally allocated.
715 * The format is "addr:port", where "addr" can be empty or "*" to indicate
716 * INADDR_ANY.
717 */
718struct sockaddr_in *str2sa(char *str) {
719 static struct sockaddr_in sa;
720 char *c;
721 int port;
722
willy tarreaua1598082005-12-17 13:08:06 +0100723 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100724 str=strdup(str);
725
726 if ((c=strrchr(str,':')) != NULL) {
727 *c++=0;
728 port=atol(c);
729 }
730 else
731 port=0;
732
733 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
734 sa.sin_addr.s_addr = INADDR_ANY;
735 }
736 else if (
737#ifndef SOLARIS
738 !inet_aton(str, &sa.sin_addr)
739#else
740 !inet_pton(AF_INET, str, &sa.sin_addr)
741#endif
742 ) {
743 struct hostent *he;
744
745 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100746 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100747 }
748 else
749 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
750 }
751 sa.sin_port=htons(port);
752 sa.sin_family=AF_INET;
753
754 free(str);
755 return &sa;
756}
757
willy tarreau9fe663a2005-12-17 13:02:59 +0100758
759/*
760 * This function sends a syslog message to both log servers of a proxy,
761 * or to global log servers if the proxy is NULL.
762 * It also tries not to waste too much time computing the message header.
763 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100764 */
765void send_log(struct proxy *p, int level, char *message, ...) {
766 static int logfd = -1; /* syslog UDP socket */
767 static long tvsec = -1; /* to force the string to be initialized */
768 struct timeval tv;
769 va_list argp;
770 static char logmsg[MAX_SYSLOG_LEN];
771 static char *dataptr = NULL;
772 int fac_level;
773 int hdr_len, data_len;
774 struct sockaddr_in *sa[2];
775 int facilities[2];
776 int nbloggers = 0;
777 char *log_ptr;
778
779 if (logfd < 0) {
780 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
781 return;
782 }
783
784 if (level < 0 || progname == NULL || message == NULL)
785 return;
786
787 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100788 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100789 /* this string is rebuild only once a second */
790 struct tm *tm = localtime(&tv.tv_sec);
791 tvsec = tv.tv_sec;
792
willy tarreauc29948c2005-12-17 13:10:27 +0100793 hdr_len = snprintf(logmsg, sizeof(logmsg),
794 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
795 monthname[tm->tm_mon],
796 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
797 progname, pid);
798 /* WARNING: depending upon implementations, snprintf may return
799 * either -1 or the number of bytes that would be needed to store
800 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100801 */
willy tarreauc29948c2005-12-17 13:10:27 +0100802 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
803 hdr_len = sizeof(logmsg);
804
805 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100806 }
807
808 va_start(argp, message);
809 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100810 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
811 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100812 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100813 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100814
815 if (p == NULL) {
816 if (global.logfac1 >= 0) {
817 sa[nbloggers] = &global.logsrv1;
818 facilities[nbloggers] = global.logfac1;
819 nbloggers++;
820 }
821 if (global.logfac2 >= 0) {
822 sa[nbloggers] = &global.logsrv2;
823 facilities[nbloggers] = global.logfac2;
824 nbloggers++;
825 }
826 } else {
827 if (p->logfac1 >= 0) {
828 sa[nbloggers] = &p->logsrv1;
829 facilities[nbloggers] = p->logfac1;
830 nbloggers++;
831 }
832 if (p->logfac2 >= 0) {
833 sa[nbloggers] = &p->logsrv2;
834 facilities[nbloggers] = p->logfac2;
835 nbloggers++;
836 }
837 }
838
839 while (nbloggers-- > 0) {
willy tarreauc29948c2005-12-17 13:10:27 +0100840 /* For each target, we may have a different facility.
841 * We can also have a different log level for each message.
842 * This induces variations in the message header length.
843 * Since we don't want to recompute it each time, nor copy it every
844 * time, we only change the facility in the pre-computed header,
845 * and we change the pointer to the header accordingly.
846 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100847 fac_level = (facilities[nbloggers] << 3) + level;
848 log_ptr = logmsg + 3; /* last digit of the log level */
849 do {
850 *log_ptr = '0' + fac_level % 10;
851 fac_level /= 10;
852 log_ptr--;
853 } while (fac_level && log_ptr > logmsg);
854 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100855
willy tarreauc29948c2005-12-17 13:10:27 +0100856 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100857
858#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100859 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100860 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
861#else
willy tarreauc29948c2005-12-17 13:10:27 +0100862 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100863 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
864#endif
865 }
willy tarreau0f7af912005-12-17 12:21:26 +0100866}
867
868
869/* sets <tv> to the current time */
870static inline struct timeval *tv_now(struct timeval *tv) {
871 if (tv)
872 gettimeofday(tv, NULL);
873 return tv;
874}
875
876/*
877 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
878 */
879static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
880 if (!tv || !from)
881 return NULL;
882 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
883 tv->tv_sec = from->tv_sec + (ms/1000);
884 while (tv->tv_usec >= 1000000) {
885 tv->tv_usec -= 1000000;
886 tv->tv_sec++;
887 }
888 return tv;
889}
890
891/*
892 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
893 */
894static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
895 if (tv1->tv_sec > tv2->tv_sec)
896 return 1;
897 else if (tv1->tv_sec < tv2->tv_sec)
898 return -1;
899 else if (tv1->tv_usec > tv2->tv_usec)
900 return 1;
901 else if (tv1->tv_usec < tv2->tv_usec)
902 return -1;
903 else
904 return 0;
905}
906
907/*
908 * returns the absolute difference, in ms, between tv1 and tv2
909 */
910unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
911 int cmp;
912 unsigned long ret;
913
914
willy tarreauef900ab2005-12-17 12:52:52 +0100915 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100916 if (!cmp)
917 return 0; /* same dates, null diff */
918 else if (cmp<0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100919 struct timeval *tmp = tv1;
920 tv1 = tv2;
921 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100922 }
willy tarreauef900ab2005-12-17 12:52:52 +0100923 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100924 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100925 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100926 else
willy tarreauef900ab2005-12-17 12:52:52 +0100927 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100928 return (unsigned long) ret;
929}
930
931/*
932 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
933 */
934static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100935 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100936 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100937 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100938 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100939 return -1;
940 else
941 return 0;
942 }
943 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100944 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100945 return 1;
946 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100947 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100948 return -1;
949 else
950 return 0;
951}
952
953/*
954 * returns the remaining time between tv1=now and event=tv2
955 * if tv2 is passed, 0 is returned.
956 */
957static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
958 unsigned long ret;
959
willy tarreau0f7af912005-12-17 12:21:26 +0100960 if (tv_cmp_ms(tv1, tv2) >= 0)
961 return 0; /* event elapsed */
962
willy tarreauef900ab2005-12-17 12:52:52 +0100963 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100964 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100965 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100966 else
willy tarreauef900ab2005-12-17 12:52:52 +0100967 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100968 return (unsigned long) ret;
969}
970
971
972/*
973 * zeroes a struct timeval
974 */
975
976static inline struct timeval *tv_eternity(struct timeval *tv) {
977 tv->tv_sec = tv->tv_usec = 0;
978 return tv;
979}
980
981/*
982 * returns 1 if tv is null, else 0
983 */
984static inline int tv_iseternity(struct timeval *tv) {
985 if (tv->tv_sec == 0 && tv->tv_usec == 0)
986 return 1;
987 else
988 return 0;
989}
990
991/*
992 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
993 * considering that 0 is the eternity.
994 */
995static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
996 if (tv_iseternity(tv1))
997 if (tv_iseternity(tv2))
998 return 0; /* same */
999 else
1000 return 1; /* tv1 later than tv2 */
1001 else if (tv_iseternity(tv2))
1002 return -1; /* tv2 later than tv1 */
1003
1004 if (tv1->tv_sec > tv2->tv_sec)
1005 return 1;
1006 else if (tv1->tv_sec < tv2->tv_sec)
1007 return -1;
1008 else if (tv1->tv_usec > tv2->tv_usec)
1009 return 1;
1010 else if (tv1->tv_usec < tv2->tv_usec)
1011 return -1;
1012 else
1013 return 0;
1014}
1015
1016/*
1017 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1018 * considering that 0 is the eternity.
1019 */
1020static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1021 if (tv_iseternity(tv1))
1022 if (tv_iseternity(tv2))
1023 return 0; /* same */
1024 else
1025 return 1; /* tv1 later than tv2 */
1026 else if (tv_iseternity(tv2))
1027 return -1; /* tv2 later than tv1 */
1028
willy tarreauefae1842005-12-17 12:51:03 +01001029 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001030 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001031 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001032 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001033 return -1;
1034 else
1035 return 0;
1036 }
1037 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001038 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001039 return 1;
1040 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001041 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001042 return -1;
1043 else
1044 return 0;
1045}
1046
1047/*
1048 * returns the first event between tv1 and tv2 into tvmin.
1049 * a zero tv is ignored. tvmin is returned.
1050 */
1051static inline struct timeval *tv_min(struct timeval *tvmin,
1052 struct timeval *tv1, struct timeval *tv2) {
1053
1054 if (tv_cmp2(tv1, tv2) <= 0)
1055 *tvmin = *tv1;
1056 else
1057 *tvmin = *tv2;
1058
1059 return tvmin;
1060}
1061
1062
1063
1064/***********************************************************/
1065/* fd management ***************************************/
1066/***********************************************************/
1067
1068
1069
willy tarreau5cbea6f2005-12-17 12:48:26 +01001070/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1071 * The file descriptor is also closed.
1072 */
willy tarreau0f7af912005-12-17 12:21:26 +01001073static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001074 FD_CLR(fd, StaticReadEvent);
1075 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001076 close(fd);
1077 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001078
1079 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1080 maxfd--;
1081}
1082
1083/* recomputes the maxfd limit from the fd */
1084static inline void fd_insert(int fd) {
1085 if (fd+1 > maxfd)
1086 maxfd = fd+1;
1087}
1088
1089/*************************************************************/
1090/* task management ***************************************/
1091/*************************************************************/
1092
willy tarreau5cbea6f2005-12-17 12:48:26 +01001093/* puts the task <t> in run queue <q>, and returns <t> */
1094static inline struct task *task_wakeup(struct task **q, struct task *t) {
1095 if (t->state == TASK_RUNNING)
1096 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001097 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001098 t->rqnext = *q;
1099 t->state = TASK_RUNNING;
1100 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001101 }
1102}
1103
willy tarreau5cbea6f2005-12-17 12:48:26 +01001104/* removes the task <t> from the queue <q>
1105 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001106 * set the run queue to point to the next one, and return it
1107 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001108static inline struct task *task_sleep(struct task **q, struct task *t) {
1109 if (t->state == TASK_RUNNING) {
1110 *q = t->rqnext;
1111 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001112 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001113 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001114}
1115
1116/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001117 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001118 * from the run queue. A pointer to the task itself is returned.
1119 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001120static inline struct task *task_delete(struct task *t) {
1121 t->prev->next = t->next;
1122 t->next->prev = t->prev;
1123 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001124}
1125
1126/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001127 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001128 */
1129static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001130 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001131}
1132
willy tarreau5cbea6f2005-12-17 12:48:26 +01001133/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001134 * may be only moved or left where it was, depending on its timing requirements.
1135 * <task> is returned.
1136 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001137struct task *task_queue(struct task *task) {
1138 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001139 struct task *start_from;
1140
1141 /* first, test if the task was already in a list */
1142 if (task->prev == NULL) {
1143 // start_from = list;
1144 start_from = list->prev;
1145 stats_tsk_new++;
1146
1147 /* insert the unlinked <task> into the list, searching back from the last entry */
1148 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1149 start_from = start_from->prev;
1150 stats_tsk_nsrch++;
1151 }
1152
1153 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1154 // start_from = start_from->next;
1155 // stats_tsk_nsrch++;
1156 // }
1157 }
1158 else if (task->prev == list ||
1159 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1160 start_from = task->next;
1161 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
1162 stats_tsk_good++;
1163 return task; /* it's already in the right place */
1164 }
1165
1166 stats_tsk_right++;
1167 /* insert the unlinked <task> into the list, searching after position <start_from> */
1168 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1169 start_from = start_from->next;
1170 stats_tsk_rsrch++;
1171 }
1172 /* we need to unlink it now */
1173 task_delete(task);
1174 }
1175 else { /* walk left. */
1176 stats_tsk_left++;
1177#ifdef LEFT_TO_TOP /* not very good */
1178 start_from = list;
1179 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1180 start_from = start_from->next;
1181 stats_tsk_lsrch++;
1182 }
1183#else
1184 start_from = task->prev->prev; /* valid because of the previous test above */
1185 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1186 start_from = start_from->prev;
1187 stats_tsk_lsrch++;
1188 }
1189#endif
1190 /* we need to unlink it now */
1191 task_delete(task);
1192 }
1193 task->prev = start_from;
1194 task->next = start_from->next;
1195 task->next->prev = task;
1196 start_from->next = task;
1197 return task;
1198}
1199
1200
1201/*********************************************************************/
1202/* more specific functions ***************************************/
1203/*********************************************************************/
1204
1205/* some prototypes */
1206static int maintain_proxies(void);
1207
willy tarreau5cbea6f2005-12-17 12:48:26 +01001208/* this either returns the sockname or the original destination address. Code
1209 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1210 */
1211static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001212#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001213 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1214#else
willy tarreaua1598082005-12-17 13:08:06 +01001215#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001216 return getsockname(fd, (struct sockaddr *)sa, salen);
1217#else
1218 return -1;
1219#endif
1220#endif
1221}
1222
1223/*
1224 * frees the context associated to a session. It must have been removed first.
1225 */
1226static inline void session_free(struct session *s) {
1227 if (s->req)
1228 pool_free(buffer, s->req);
1229 if (s->rep)
1230 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001231 if (s->logs.uri)
1232 pool_free(requri, s->logs.uri);
willy tarreau9fe663a2005-12-17 13:02:59 +01001233
willy tarreau5cbea6f2005-12-17 12:48:26 +01001234 pool_free(session, s);
1235}
1236
willy tarreau0f7af912005-12-17 12:21:26 +01001237
1238/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001239 * This function initiates a connection to the current server (s->srv) if (s->direct)
1240 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001241 * it's OK, -1 if it's impossible.
1242 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001243int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001244 int one = 1;
1245 int fd;
1246
1247 // fprintf(stderr,"connect_server : s=%p\n",s);
1248
willy tarreaue39cd132005-12-17 13:00:18 +01001249 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001250 s->srv_addr = s->srv->addr;
1251 }
1252 else if (s->proxy->options & PR_O_BALANCE) {
1253 if (s->proxy->options & PR_O_BALANCE_RR) {
1254 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001255 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001256 if (s->proxy->cursrv == NULL)
1257 s->proxy->cursrv = s->proxy->srv;
1258 if (s->proxy->cursrv->state & SRV_RUNNING)
1259 break;
1260 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001261 retry--;
1262 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001263
1264 if (retry == 0) /* no server left */
1265 return -1;
1266
1267 s->srv = s->proxy->cursrv;
1268 s->srv_addr = s->srv->addr;
1269 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001270 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001271 else /* unknown balancing algorithm */
1272 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001273 }
willy tarreaua1598082005-12-17 13:08:06 +01001274 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001275 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001276 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001277 }
1278 else if (s->proxy->options & PR_O_TRANSP) {
1279 /* in transparent mode, use the original dest addr if no dispatch specified */
1280 int salen = sizeof(struct sockaddr_in);
1281 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1282 qfprintf(stderr, "Cannot get original server address.\n");
1283 return -1;
1284 }
1285 }
willy tarreau0f7af912005-12-17 12:21:26 +01001286
1287 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001288 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001289 return -1;
1290 }
1291
willy tarreau9fe663a2005-12-17 13:02:59 +01001292 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001293 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1294 close(fd);
1295 return -1;
1296 }
1297
willy tarreau0f7af912005-12-17 12:21:26 +01001298 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1299 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001300 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001301 close(fd);
1302 return -1;
1303 }
1304
willy tarreaua1598082005-12-17 13:08:06 +01001305 /* allow specific binding */
1306 if (s->proxy->options & PR_O_BIND_SRC &&
1307 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1308 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1309 close(fd);
1310 return -1;
1311 }
1312
willy tarreau0f7af912005-12-17 12:21:26 +01001313 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1314 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001315 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001316 close(fd);
1317 return -1;
1318 }
1319 else if (errno != EALREADY && errno != EISCONN) {
1320 close(fd);
1321 return -1;
1322 }
1323 }
1324
willy tarreau5cbea6f2005-12-17 12:48:26 +01001325 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001326 fdtab[fd].read = &event_srv_read;
1327 fdtab[fd].write = &event_srv_write;
1328 fdtab[fd].state = FD_STCONN; /* connection in progress */
1329
1330 FD_SET(fd, StaticWriteEvent); /* for connect status */
1331
1332 fd_insert(fd);
1333
1334 if (s->proxy->contimeout)
1335 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1336 else
1337 tv_eternity(&s->cnexpire);
1338 return 0;
1339}
1340
1341/*
1342 * this function is called on a read event from a client socket.
1343 * It returns 0.
1344 */
1345int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001346 struct task *t = fdtab[fd].owner;
1347 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001348 struct buffer *b = s->req;
1349 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001350
1351 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1352
willy tarreau0f7af912005-12-17 12:21:26 +01001353 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001354 while (1) {
1355 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1356 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001357 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001358 }
1359 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001360 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001361 }
1362 else {
1363 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001364 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1365 * since it means that the rewrite protection has been removed. This
1366 * implies that the if statement can be removed.
1367 */
1368 if (max > b->rlim - b->data)
1369 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001370 }
1371
1372 if (max == 0) { /* not anymore room to store data */
1373 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001374 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001375 }
1376
willy tarreau3242e862005-12-17 12:27:53 +01001377#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001378 {
1379 int skerr, lskerr;
1380
1381 lskerr = sizeof(skerr);
1382 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1383 if (skerr)
1384 ret = -1;
1385 else
1386 ret = recv(fd, b->r, max, 0);
1387 }
willy tarreau3242e862005-12-17 12:27:53 +01001388#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001389 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001390#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001391 if (ret > 0) {
1392 b->r += ret;
1393 b->l += ret;
1394 s->res_cr = RES_DATA;
1395
1396 if (b->r == b->data + BUFSIZE) {
1397 b->r = b->data; /* wrap around the buffer */
1398 }
willy tarreaua1598082005-12-17 13:08:06 +01001399
1400 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001401 /* we hope to read more data or to get a close on next round */
1402 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001403 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001404 else if (ret == 0) {
1405 s->res_cr = RES_NULL;
1406 break;
1407 }
1408 else if (errno == EAGAIN) {/* ignore EAGAIN */
1409 break;
1410 }
1411 else {
1412 s->res_cr = RES_ERROR;
1413 fdtab[fd].state = FD_STERROR;
1414 break;
1415 }
1416 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001417 }
1418 else {
1419 s->res_cr = RES_ERROR;
1420 fdtab[fd].state = FD_STERROR;
1421 }
1422
willy tarreau5cbea6f2005-12-17 12:48:26 +01001423 if (s->res_cr != RES_SILENT) {
1424 if (s->proxy->clitimeout)
1425 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1426 else
1427 tv_eternity(&s->crexpire);
1428
1429 task_wakeup(&rq, t);
1430 }
willy tarreau0f7af912005-12-17 12:21:26 +01001431
willy tarreau0f7af912005-12-17 12:21:26 +01001432 return 0;
1433}
1434
1435
1436/*
1437 * this function is called on a read event from a server socket.
1438 * It returns 0.
1439 */
1440int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001441 struct task *t = fdtab[fd].owner;
1442 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001443 struct buffer *b = s->rep;
1444 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001445
1446 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1447
willy tarreau0f7af912005-12-17 12:21:26 +01001448 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001449 while (1) {
1450 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1451 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001452 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001453 }
1454 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001455 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001456 }
1457 else {
1458 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001459 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1460 * since it means that the rewrite protection has been removed. This
1461 * implies that the if statement can be removed.
1462 */
1463 if (max > b->rlim - b->data)
1464 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001465 }
1466
1467 if (max == 0) { /* not anymore room to store data */
1468 FD_CLR(fd, StaticReadEvent);
1469 break;
1470 }
1471
willy tarreau3242e862005-12-17 12:27:53 +01001472#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001473 {
1474 int skerr, lskerr;
1475
1476 lskerr = sizeof(skerr);
1477 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1478 if (skerr)
1479 ret = -1;
1480 else
1481 ret = recv(fd, b->r, max, 0);
1482 }
willy tarreau3242e862005-12-17 12:27:53 +01001483#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001484 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001485#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001486 if (ret > 0) {
1487 b->r += ret;
1488 b->l += ret;
1489 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001490
willy tarreau5cbea6f2005-12-17 12:48:26 +01001491 if (b->r == b->data + BUFSIZE) {
1492 b->r = b->data; /* wrap around the buffer */
1493 }
willy tarreaua1598082005-12-17 13:08:06 +01001494
1495 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001496 /* we hope to read more data or to get a close on next round */
1497 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001498 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001499 else if (ret == 0) {
1500 s->res_sr = RES_NULL;
1501 break;
1502 }
1503 else if (errno == EAGAIN) {/* ignore EAGAIN */
1504 break;
1505 }
1506 else {
1507 s->res_sr = RES_ERROR;
1508 fdtab[fd].state = FD_STERROR;
1509 break;
1510 }
1511 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001512 }
1513 else {
1514 s->res_sr = RES_ERROR;
1515 fdtab[fd].state = FD_STERROR;
1516 }
1517
willy tarreau5cbea6f2005-12-17 12:48:26 +01001518 if (s->res_sr != RES_SILENT) {
1519 if (s->proxy->srvtimeout)
1520 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1521 else
1522 tv_eternity(&s->srexpire);
1523
1524 task_wakeup(&rq, t);
1525 }
willy tarreau0f7af912005-12-17 12:21:26 +01001526
willy tarreau0f7af912005-12-17 12:21:26 +01001527 return 0;
1528}
1529
1530/*
1531 * this function is called on a write event from a client socket.
1532 * It returns 0.
1533 */
1534int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001535 struct task *t = fdtab[fd].owner;
1536 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001537 struct buffer *b = s->rep;
1538 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001539
1540 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1541
1542 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001543 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001544 // max = BUFSIZE; BUG !!!!
1545 max = 0;
1546 }
1547 else if (b->r > b->w) {
1548 max = b->r - b->w;
1549 }
1550 else
1551 max = b->data + BUFSIZE - b->w;
1552
willy tarreau0f7af912005-12-17 12:21:26 +01001553 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001554#ifndef MSG_NOSIGNAL
1555 int skerr, lskerr;
1556#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001557
1558 if (max == 0) {
1559 s->res_cw = RES_NULL;
1560 task_wakeup(&rq, t);
1561 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001562 }
1563
willy tarreau3242e862005-12-17 12:27:53 +01001564#ifndef MSG_NOSIGNAL
1565 lskerr=sizeof(skerr);
1566 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1567 if (skerr)
1568 ret = -1;
1569 else
1570 ret = send(fd, b->w, max, MSG_DONTWAIT);
1571#else
willy tarreau0f7af912005-12-17 12:21:26 +01001572 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001573#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001574
1575 if (ret > 0) {
1576 b->l -= ret;
1577 b->w += ret;
1578
1579 s->res_cw = RES_DATA;
1580
1581 if (b->w == b->data + BUFSIZE) {
1582 b->w = b->data; /* wrap around the buffer */
1583 }
1584 }
1585 else if (ret == 0) {
1586 /* nothing written, just make as if we were never called */
1587// s->res_cw = RES_NULL;
1588 return 0;
1589 }
1590 else if (errno == EAGAIN) /* ignore EAGAIN */
1591 return 0;
1592 else {
1593 s->res_cw = RES_ERROR;
1594 fdtab[fd].state = FD_STERROR;
1595 }
1596 }
1597 else {
1598 s->res_cw = RES_ERROR;
1599 fdtab[fd].state = FD_STERROR;
1600 }
1601
1602 if (s->proxy->clitimeout)
1603 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1604 else
1605 tv_eternity(&s->cwexpire);
1606
willy tarreau5cbea6f2005-12-17 12:48:26 +01001607 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001608 return 0;
1609}
1610
1611
1612/*
1613 * this function is called on a write event from a server socket.
1614 * It returns 0.
1615 */
1616int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001617 struct task *t = fdtab[fd].owner;
1618 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001619 struct buffer *b = s->req;
1620 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001621
1622 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1623
1624 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001625 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001626 // max = BUFSIZE; BUG !!!!
1627 max = 0;
1628 }
1629 else if (b->r > b->w) {
1630 max = b->r - b->w;
1631 }
1632 else
1633 max = b->data + BUFSIZE - b->w;
1634
willy tarreau0f7af912005-12-17 12:21:26 +01001635 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001636#ifndef MSG_NOSIGNAL
1637 int skerr, lskerr;
1638#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001639 if (max == 0) {
1640 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001641 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001642 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001643 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001644 return 0;
1645 }
1646
willy tarreauef900ab2005-12-17 12:52:52 +01001647
willy tarreau3242e862005-12-17 12:27:53 +01001648#ifndef MSG_NOSIGNAL
1649 lskerr=sizeof(skerr);
1650 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1651 if (skerr)
1652 ret = -1;
1653 else
1654 ret = send(fd, b->w, max, MSG_DONTWAIT);
1655#else
willy tarreau0f7af912005-12-17 12:21:26 +01001656 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001657#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001658 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001659 if (ret > 0) {
1660 b->l -= ret;
1661 b->w += ret;
1662
1663 s->res_sw = RES_DATA;
1664
1665 if (b->w == b->data + BUFSIZE) {
1666 b->w = b->data; /* wrap around the buffer */
1667 }
1668 }
1669 else if (ret == 0) {
1670 /* nothing written, just make as if we were never called */
1671 // s->res_sw = RES_NULL;
1672 return 0;
1673 }
1674 else if (errno == EAGAIN) /* ignore EAGAIN */
1675 return 0;
1676 else {
1677 s->res_sw = RES_ERROR;
1678 fdtab[fd].state = FD_STERROR;
1679 }
1680 }
1681 else {
1682 s->res_sw = RES_ERROR;
1683 fdtab[fd].state = FD_STERROR;
1684 }
1685
1686 if (s->proxy->srvtimeout)
1687 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1688 else
1689 tv_eternity(&s->swexpire);
1690
willy tarreau5cbea6f2005-12-17 12:48:26 +01001691 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001692 return 0;
1693}
1694
1695
1696/*
willy tarreaue39cd132005-12-17 13:00:18 +01001697 * returns a message to the client ; the connection is shut down for read,
1698 * and the request is cleared so that no server connection can be initiated.
1699 * The client must be in a valid state for this (HEADER, DATA ...).
1700 * Nothing is performed on the server side.
1701 * The reply buffer must be empty before this.
1702 */
1703void client_retnclose(struct session *s, int len, const char *msg) {
1704 FD_CLR(s->cli_fd, StaticReadEvent);
1705 FD_SET(s->cli_fd, StaticWriteEvent);
1706 tv_eternity(&s->crexpire);
1707 shutdown(s->cli_fd, SHUT_RD);
1708 s->cli_state = CL_STSHUTR;
1709 strcpy(s->rep->data, msg);
1710 s->rep->l = len;
1711 s->rep->r += len;
1712 s->req->l = 0;
1713}
1714
1715
1716/*
1717 * returns a message into the rep buffer, and flushes the req buffer.
1718 * The reply buffer must be empty before this.
1719 */
1720void client_return(struct session *s, int len, const char *msg) {
1721 strcpy(s->rep->data, msg);
1722 s->rep->l = len;
1723 s->rep->r += len;
1724 s->req->l = 0;
1725}
1726
willy tarreau9fe663a2005-12-17 13:02:59 +01001727/*
1728 * send a log for the session when we have enough info about it
1729 */
1730void sess_log(struct session *s) {
1731 unsigned char *pn;
1732 struct proxy *p = s->proxy;
1733 int log;
1734 char *uri;
1735 char *pxid;
1736 char *srv;
1737
1738 /* This is a first attempt at a better logging system.
1739 * For now, we rely on send_log() to provide the date, although it obviously
1740 * is the date of the log and not of the request, and most fields are not
1741 * computed.
1742 */
1743
willy tarreaua1598082005-12-17 13:08:06 +01001744 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001745
1746 pn = (log & LW_CLIP) ?
1747 (unsigned char *)&s->cli_addr.sin_addr :
1748 (unsigned char *)"\0\0\0\0";
1749
willy tarreaua1598082005-12-17 13:08:06 +01001750 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001751 pxid = p->id;
1752 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001753 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1754
1755 if (p->to_log & LW_DATE) {
1756 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1757
1758 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",
1759 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1760 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1761 tm->tm_hour, tm->tm_min, tm->tm_sec,
1762 pxid, srv,
1763 s->logs.t_request,
1764 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1765 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1766 s->logs.t_close,
1767 s->logs.status, s->logs.bytes,
1768 uri);
1769 }
1770 else {
1771 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %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 pxid, srv,
1774 s->logs.t_request,
1775 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1776 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1777 s->logs.t_close,
1778 s->logs.status, s->logs.bytes,
1779 uri);
1780 }
1781
1782 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001783}
1784
willy tarreaue39cd132005-12-17 13:00:18 +01001785
1786/*
willy tarreau0f7af912005-12-17 12:21:26 +01001787 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001788 * to an accept. It tries to accept as many connections as possible.
1789 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001790 */
1791int event_accept(int fd) {
1792 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001793 struct session *s;
1794 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001795 int cfd;
1796 int one = 1;
1797
willy tarreau5cbea6f2005-12-17 12:48:26 +01001798 while (p->nbconn < p->maxconn) {
1799 struct sockaddr_in addr;
1800 int laddr = sizeof(addr);
1801 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1802 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001803
willy tarreau5cbea6f2005-12-17 12:48:26 +01001804 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1805 Alert("out of memory in event_accept().\n");
1806 FD_CLR(fd, StaticReadEvent);
1807 p->state = PR_STIDLE;
1808 close(cfd);
1809 return 0;
1810 }
willy tarreau0f7af912005-12-17 12:21:26 +01001811
willy tarreau5cbea6f2005-12-17 12:48:26 +01001812 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1813 Alert("out of memory in event_accept().\n");
1814 FD_CLR(fd, StaticReadEvent);
1815 p->state = PR_STIDLE;
1816 close(cfd);
1817 pool_free(session, s);
1818 return 0;
1819 }
willy tarreau0f7af912005-12-17 12:21:26 +01001820
willy tarreau5cbea6f2005-12-17 12:48:26 +01001821 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001822 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001823 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1824 close(cfd);
1825 pool_free(task, t);
1826 pool_free(session, s);
1827 return 0;
1828 }
willy tarreau0f7af912005-12-17 12:21:26 +01001829
willy tarreau5cbea6f2005-12-17 12:48:26 +01001830 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1831 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1832 (char *) &one, sizeof(one)) == -1)) {
1833 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1834 close(cfd);
1835 pool_free(task, t);
1836 pool_free(session, s);
1837 return 0;
1838 }
willy tarreau0f7af912005-12-17 12:21:26 +01001839
willy tarreau9fe663a2005-12-17 13:02:59 +01001840 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1841 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1842 t->state = TASK_IDLE;
1843 t->process = process_session;
1844 t->context = s;
1845
1846 s->task = t;
1847 s->proxy = p;
1848 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1849 s->srv_state = SV_STIDLE;
1850 s->req = s->rep = NULL; /* will be allocated later */
1851 s->flags = 0;
1852 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1853 s->cli_fd = cfd;
1854 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01001855 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01001856 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01001857
1858 s->logs.logwait = p->to_log;
1859 s->logs.tv_accept = now;
1860 s->logs.t_request = -1;
1861 s->logs.t_connect = -1;
1862 s->logs.t_data = -1;
1863 s->logs.t_close = 0;
1864 s->logs.uri = NULL;
1865 s->logs.status = -1;
1866 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001867
willy tarreau5cbea6f2005-12-17 12:48:26 +01001868 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1869 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01001870 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001871 unsigned char *pn, *sn;
1872 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01001873
willy tarreau5cbea6f2005-12-17 12:48:26 +01001874 namelen = sizeof(sockname);
1875 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1876 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1877 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01001878 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001879
willy tarreau9fe663a2005-12-17 13:02:59 +01001880 if (p->to_log) {
1881 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01001882 if (s->logs.logwait & LW_CLIP)
1883 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01001884 sess_log(s);
1885 }
1886 else
1887 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1888 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1889 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1890 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01001891 }
willy tarreau0f7af912005-12-17 12:21:26 +01001892
willy tarreau9fe663a2005-12-17 13:02:59 +01001893 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreauef900ab2005-12-17 12:52:52 +01001894 int len;
1895 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1896 write(1, trash, len);
1897 }
willy tarreau0f7af912005-12-17 12:21:26 +01001898
willy tarreau5cbea6f2005-12-17 12:48:26 +01001899 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1900 close(cfd); /* nothing can be done for this fd without memory */
1901 pool_free(task, t);
1902 pool_free(session, s);
1903 return 0;
1904 }
1905 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01001906 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001907 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1908 s->req->rlim = s->req->data + BUFSIZE;
1909 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
1910 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01001911
willy tarreau5cbea6f2005-12-17 12:48:26 +01001912 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1913 pool_free(buffer, s->req);
1914 close(cfd); /* nothing can be done for this fd without memory */
1915 pool_free(task, t);
1916 pool_free(session, s);
1917 return 0;
1918 }
1919 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01001920 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001921 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 +01001922
willy tarreau5cbea6f2005-12-17 12:48:26 +01001923 fdtab[cfd].read = &event_cli_read;
1924 fdtab[cfd].write = &event_cli_write;
1925 fdtab[cfd].owner = t;
1926 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001927
willy tarreau5cbea6f2005-12-17 12:48:26 +01001928 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01001929 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001930 }
1931 else {
1932 FD_SET(cfd, StaticReadEvent);
1933 }
1934
1935 fd_insert(cfd);
1936
1937 tv_eternity(&s->cnexpire);
1938 tv_eternity(&s->srexpire);
1939 tv_eternity(&s->swexpire);
1940 tv_eternity(&s->cwexpire);
1941
1942 if (s->proxy->clitimeout)
1943 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1944 else
1945 tv_eternity(&s->crexpire);
1946
1947 t->expire = s->crexpire;
1948
1949 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01001950
1951 if (p->mode != PR_MODE_HEALTH)
1952 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001953
1954 p->nbconn++;
1955 actconn++;
1956 totalconn++;
1957
1958 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1959 } /* end of while (p->nbconn < p->maxconn) */
1960 return 0;
1961}
willy tarreau0f7af912005-12-17 12:21:26 +01001962
willy tarreau0f7af912005-12-17 12:21:26 +01001963
willy tarreau5cbea6f2005-12-17 12:48:26 +01001964/*
1965 * This function is used only for server health-checks. It handles
1966 * the connection acknowledgement and returns 1 if the socket is OK,
1967 * or -1 if an error occured.
1968 */
1969int event_srv_hck(int fd) {
1970 struct task *t = fdtab[fd].owner;
1971 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001972
willy tarreau5cbea6f2005-12-17 12:48:26 +01001973 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01001974 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001975 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1976 if (skerr)
1977 s->result = -1;
1978 else
1979 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001980
willy tarreau5cbea6f2005-12-17 12:48:26 +01001981 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001982 return 0;
1983}
1984
1985
1986/*
1987 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1988 * and moves <end> just after the end of <str>.
1989 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1990 * the shift value (positive or negative) is returned.
1991 * If there's no space left, the move is not done.
1992 *
1993 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001994int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01001995 int delta;
1996 int len;
1997
1998 len = strlen(str);
1999 delta = len - (end - pos);
2000
2001 if (delta + b->r >= b->data + BUFSIZE)
2002 return 0; /* no space left */
2003
2004 /* first, protect the end of the buffer */
2005 memmove(end + delta, end, b->data + b->l - end);
2006
2007 /* now, copy str over pos */
2008 memcpy(pos, str,len);
2009
willy tarreau5cbea6f2005-12-17 12:48:26 +01002010 /* we only move data after the displaced zone */
2011 if (b->r > pos) b->r += delta;
2012 if (b->w > pos) b->w += delta;
2013 if (b->h > pos) b->h += delta;
2014 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002015 b->l += delta;
2016
2017 return delta;
2018}
2019
2020/* same except that the string len is given */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002021int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002022 int delta;
2023
2024 delta = len - (end - pos);
2025
2026 if (delta + b->r >= b->data + BUFSIZE)
2027 return 0; /* no space left */
2028
2029 /* first, protect the end of the buffer */
2030 memmove(end + delta, end, b->data + b->l - end);
2031
2032 /* now, copy str over pos */
2033 memcpy(pos, str,len);
2034
willy tarreau5cbea6f2005-12-17 12:48:26 +01002035 /* we only move data after the displaced zone */
2036 if (b->r > pos) b->r += delta;
2037 if (b->w > pos) b->w += delta;
2038 if (b->h > pos) b->h += delta;
2039 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002040 b->l += delta;
2041
2042 return delta;
2043}
2044
2045
2046int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2047 char *old_dst = dst;
2048
2049 while (*str) {
2050 if (*str == '\\') {
2051 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002052 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002053 int len, num;
2054
2055 num = *str - '0';
2056 str++;
2057
2058 if (matches[num].rm_so > -1) {
2059 len = matches[num].rm_eo - matches[num].rm_so;
2060 memcpy(dst, src + matches[num].rm_so, len);
2061 dst += len;
2062 }
2063
2064 }
2065 else if (*str == 'x') {
2066 unsigned char hex1, hex2;
2067 str++;
2068
2069 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2070
2071 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2072 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2073 *dst++ = (hex1<<4) + hex2;
2074 }
2075 else
2076 *dst++ = *str++;
2077 }
2078 else
2079 *dst++ = *str++;
2080 }
2081 *dst = 0;
2082 return dst - old_dst;
2083}
2084
willy tarreau9fe663a2005-12-17 13:02:59 +01002085
willy tarreau0f7af912005-12-17 12:21:26 +01002086/*
2087 * manages the client FSM and its socket. BTW, it also tries to handle the
2088 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2089 * 0 else.
2090 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002091int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002092 int s = t->srv_state;
2093 int c = t->cli_state;
2094 struct buffer *req = t->req;
2095 struct buffer *rep = t->rep;
2096
2097 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2098 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2099 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2100 //);
2101 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002102 /* now parse the partial (or complete) headers */
2103 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2104 char *ptr;
2105 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002106
willy tarreau5cbea6f2005-12-17 12:48:26 +01002107 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002108
willy tarreau0f7af912005-12-17 12:21:26 +01002109 /* look for the end of the current header */
2110 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2111 ptr++;
2112
willy tarreau5cbea6f2005-12-17 12:48:26 +01002113 if (ptr == req->h) { /* empty line, end of headers */
2114 char newhdr[MAXREWRITE + 1];
2115 int line, len;
2116 /* we can only get here after an end of headers */
2117 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002118
willy tarreaue39cd132005-12-17 13:00:18 +01002119 if (t->flags & SN_CLDENY) {
2120 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002121 t->logs.status = 403;
willy tarreaue39cd132005-12-17 13:00:18 +01002122 client_retnclose(t, strlen(HTTP_403), HTTP_403);
2123 return 1;
2124 }
2125
willy tarreau5cbea6f2005-12-17 12:48:26 +01002126 for (line = 0; line < t->proxy->nb_reqadd; line++) {
2127 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
2128 buffer_replace2(req, req->h, req->h, newhdr, len);
2129 }
willy tarreau0f7af912005-12-17 12:21:26 +01002130
willy tarreau9fe663a2005-12-17 13:02:59 +01002131 if (t->proxy->options & PR_O_FWDFOR) {
2132 /* insert an X-Forwarded-For header */
2133 unsigned char *pn;
2134 pn = (unsigned char *)&t->cli_addr.sin_addr;
2135 len = sprintf(newhdr, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2136 pn[0], pn[1], pn[2], pn[3]);
2137 buffer_replace2(req, req->h, req->h, newhdr, len);
2138 }
2139
willy tarreau5cbea6f2005-12-17 12:48:26 +01002140 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002141 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002142
willy tarreaua1598082005-12-17 13:08:06 +01002143 t->logs.t_request = tv_delta(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002144 /* FIXME: we'll set the client in a wait state while we try to
2145 * connect to the server. Is this really needed ? wouldn't it be
2146 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002147 //FD_CLR(t->cli_fd, StaticReadEvent);
2148 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002149 break;
2150 }
willy tarreau0f7af912005-12-17 12:21:26 +01002151
willy tarreau5cbea6f2005-12-17 12:48:26 +01002152 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2153 if (ptr > req->r - 2) {
2154 /* this is a partial header, let's wait for more to come */
2155 req->lr = ptr;
2156 break;
2157 }
willy tarreau0f7af912005-12-17 12:21:26 +01002158
willy tarreau5cbea6f2005-12-17 12:48:26 +01002159 /* now we know that *ptr is either \r or \n,
2160 * and that there are at least 1 char after it.
2161 */
2162 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2163 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2164 else
2165 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002166
willy tarreau5cbea6f2005-12-17 12:48:26 +01002167 /*
2168 * now we know that we have a full header ; we can do whatever
2169 * we want with these pointers :
2170 * req->h = beginning of header
2171 * ptr = end of header (first \r or \n)
2172 * req->lr = beginning of next line (next rep->h)
2173 * req->r = end of data (not used at this stage)
2174 */
willy tarreau0f7af912005-12-17 12:21:26 +01002175
willy tarreaua1598082005-12-17 13:08:06 +01002176 if (t->logs.logwait & LW_REQ &&
2177 t->proxy->mode & PR_MODE_HTTP) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002178 /* we have a complete HTTP request that we must log */
2179 int urilen;
2180
willy tarreaua1598082005-12-17 13:08:06 +01002181 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002182 Alert("HTTP logging : out of memory.\n");
willy tarreaua1598082005-12-17 13:08:06 +01002183 t->logs.status = 502;
2184 client_retnclose(t, strlen(HTTP_502), HTTP_502);
willy tarreau9fe663a2005-12-17 13:02:59 +01002185 return 1;
2186 }
2187
2188 urilen = ptr - req->h;
2189 if (urilen >= REQURI_LEN)
2190 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002191 memcpy(t->logs.uri, req->h, urilen);
2192 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002193
willy tarreaua1598082005-12-17 13:08:06 +01002194 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002195 sess_log(t);
2196 }
2197
willy tarreau5cbea6f2005-12-17 12:48:26 +01002198 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002199
willy tarreau9fe663a2005-12-17 13:02:59 +01002200 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002201 int len, max;
2202 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2203 max = ptr - req->h;
2204 UBOUND(max, sizeof(trash) - len - 1);
2205 len += strlcpy(trash + len, req->h, max + 1);
2206 trash[len++] = '\n';
2207 write(1, trash, len);
2208 }
willy tarreau0f7af912005-12-17 12:21:26 +01002209
willy tarreau5cbea6f2005-12-17 12:48:26 +01002210 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002211 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2212 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002213 char term;
2214
2215 term = *ptr;
2216 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002217 exp = t->proxy->req_exp;
2218 do {
2219 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2220 switch (exp->action) {
2221 case ACT_ALLOW:
2222 if (!(t->flags & SN_CLDENY))
2223 t->flags |= SN_CLALLOW;
2224 break;
2225 case ACT_REPLACE:
2226 if (!(t->flags & SN_CLDENY)) {
2227 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2228 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2229 }
2230 break;
2231 case ACT_REMOVE:
2232 if (!(t->flags & SN_CLDENY))
2233 delete_header = 1;
2234 break;
2235 case ACT_DENY:
2236 if (!(t->flags & SN_CLALLOW))
2237 t->flags |= SN_CLDENY;
2238 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002239 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002240 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002241 }
willy tarreaue39cd132005-12-17 13:00:18 +01002242 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002243 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002244 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002245
2246 /* now look for cookies */
2247 if (!delete_header && (req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
2248 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
2249 char *p1, *p2, *p3, *p4;
2250
2251 p1 = req->h + 8; /* first char after 'Cookie: ' */
2252
2253 while (p1 < ptr) {
willy tarreauc29948c2005-12-17 13:10:27 +01002254 while (p1 < ptr && (isspace((int)*p1) || *p1 == ';'))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002255 p1++;
2256
2257 if (p1 == ptr)
2258 break;
2259 else if (*p1 == ';') { /* next cookie */
2260 ++p1;
2261 continue;
2262 }
2263
2264 /* p1 is at the beginning of the cookie name */
2265 p2 = p1;
2266
2267 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2268 p2++;
2269
2270 if (p2 == ptr)
2271 break;
2272 else if (*p2 == ';') { /* next cookie */
2273 p1=++p2;
2274 continue;
2275 }
2276
2277 p3 = p2 + 1; /* skips the '=' sign */
2278 if (p3 == ptr)
2279 break;
2280
2281 p4=p3;
willy tarreauc29948c2005-12-17 13:10:27 +01002282 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002283 p4++;
2284
2285 /* here, we have the cookie name between p1 and p2,
2286 * and its value between p3 and p4.
2287 * we can process it.
2288 */
2289
2290 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2291 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2292 /* Cool... it's the right one */
2293 struct server *srv = t->proxy->srv;
2294
2295 while (srv &&
2296 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2297 srv = srv->next;
2298 }
2299
2300 if (srv) { /* we found the server */
willy tarreaue39cd132005-12-17 13:00:18 +01002301 t->flags |= SN_DIRECT;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002302 t->srv = srv;
2303 }
2304
2305 break;
2306 }
2307 else {
2308 // fprintf(stderr,"Ignoring unknown cookie : ");
2309 // write(2, p1, p2-p1);
2310 // fprintf(stderr," = ");
2311 // write(2, p3, p4-p3);
2312 // fprintf(stderr,"\n");
2313 }
2314 /* we'll have to look for another cookie ... */
2315 p1 = p4;
2316 } /* while (p1 < ptr) */
2317 } /* end of cookie processing */
2318
2319 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002320 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 buffer_replace2(req, req->h, req->lr, "", 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002322 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002323 req->h = req->lr;
2324 } /* while (req->lr < req->r) */
2325
2326 /* end of header processing (even if incomplete) */
2327
willy tarreauef900ab2005-12-17 12:52:52 +01002328 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2329 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2330 * full. We cannot loop here since event_cli_read will disable it only if
2331 * req->l == rlim-data
2332 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002333 FD_SET(t->cli_fd, StaticReadEvent);
2334 if (t->proxy->clitimeout)
2335 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2336 else
2337 tv_eternity(&t->crexpire);
2338 }
2339
willy tarreaue39cd132005-12-17 13:00:18 +01002340 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002341 * won't be able to free more later, so the session will never terminate.
2342 */
willy tarreaue39cd132005-12-17 13:00:18 +01002343 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002344 t->logs.status = 400;
willy tarreaue39cd132005-12-17 13:00:18 +01002345 client_retnclose(t, strlen(HTTP_400), HTTP_400);
2346 return 1;
2347 }
2348 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2349 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2350
2351 /* read timeout, read error, or last read : give up.
2352 * since we are in header mode, if there's no space left for headers, we
2353 * won't be able to free more later, so the session will never terminate.
2354 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002355 tv_eternity(&t->crexpire);
2356 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002357 t->cli_state = CL_STCLOSE;
2358 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002359 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002360
2361 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002362 }
2363 else if (c == CL_STDATA) {
2364 /* read or write error */
2365 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002366 tv_eternity(&t->crexpire);
2367 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002368 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002369 t->cli_state = CL_STCLOSE;
2370 return 1;
2371 }
2372 /* read timeout, last read, or end of server write */
2373 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2374 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002375 FD_CLR(t->cli_fd, StaticReadEvent);
2376 // if (req->l == 0) /* nothing to write on the server side */
2377 // FD_CLR(t->srv_fd, StaticWriteEvent);
2378 tv_eternity(&t->crexpire);
2379 shutdown(t->cli_fd, SHUT_RD);
2380 t->cli_state = CL_STSHUTR;
2381 return 1;
2382 }
2383 /* write timeout, or last server read and buffer empty */
2384 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2385 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002386 FD_CLR(t->cli_fd, StaticWriteEvent);
2387 tv_eternity(&t->cwexpire);
2388 shutdown(t->cli_fd, SHUT_WR);
2389 t->cli_state = CL_STSHUTW;
2390 return 1;
2391 }
2392
willy tarreauef900ab2005-12-17 12:52:52 +01002393 if (req->l >= req->rlim - req->data) {
2394 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002395 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002396 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002397 FD_CLR(t->cli_fd, StaticReadEvent);
2398 tv_eternity(&t->crexpire);
2399 }
2400 }
2401 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002402 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002403 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2404 FD_SET(t->cli_fd, StaticReadEvent);
2405 if (t->proxy->clitimeout)
2406 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2407 else
2408 tv_eternity(&t->crexpire);
2409 }
2410 }
2411
2412 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002413 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002414 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2415 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2416 tv_eternity(&t->cwexpire);
2417 }
2418 }
2419 else { /* buffer not empty */
2420 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2421 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2422 if (t->proxy->clitimeout)
2423 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2424 else
2425 tv_eternity(&t->cwexpire);
2426 }
2427 }
2428 return 0; /* other cases change nothing */
2429 }
2430 else if (c == CL_STSHUTR) {
2431 if ((t->res_cw == RES_ERROR) ||
2432 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002433 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002434 tv_eternity(&t->cwexpire);
2435 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002436 t->cli_state = CL_STCLOSE;
2437 return 1;
2438 }
2439 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002440 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002441 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2442 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2443 tv_eternity(&t->cwexpire);
2444 }
2445 }
2446 else { /* buffer not empty */
2447 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2448 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2449 if (t->proxy->clitimeout)
2450 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2451 else
2452 tv_eternity(&t->cwexpire);
2453 }
2454 }
2455 return 0;
2456 }
2457 else if (c == CL_STSHUTW) {
2458 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002459 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002460 tv_eternity(&t->crexpire);
2461 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002462 t->cli_state = CL_STCLOSE;
2463 return 1;
2464 }
willy tarreauef900ab2005-12-17 12:52:52 +01002465 else if (req->l >= req->rlim - req->data) {
2466 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002467 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002468 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002469 FD_CLR(t->cli_fd, StaticReadEvent);
2470 tv_eternity(&t->crexpire);
2471 }
2472 }
2473 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002474 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002475 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2476 FD_SET(t->cli_fd, StaticReadEvent);
2477 if (t->proxy->clitimeout)
2478 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2479 else
2480 tv_eternity(&t->crexpire);
2481 }
2482 }
2483 return 0;
2484 }
2485 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002486 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002487 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002488 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002489 write(1, trash, len);
2490 }
2491 return 0;
2492 }
2493 return 0;
2494}
2495
2496
2497/*
2498 * manages the server FSM and its socket. It returns 1 if a state has changed
2499 * (and a resync may be needed), 0 else.
2500 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002501int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002502 int s = t->srv_state;
2503 int c = t->cli_state;
2504 struct buffer *req = t->req;
2505 struct buffer *rep = t->rep;
2506
willy tarreau5cbea6f2005-12-17 12:48:26 +01002507 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2508 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2509 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2510 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2511 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002512 if (s == SV_STIDLE) {
2513 if (c == CL_STHEADERS)
2514 return 0; /* stay in idle, waiting for data to reach the client side */
2515 else if (c == CL_STCLOSE ||
2516 c == CL_STSHUTW ||
2517 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2518 tv_eternity(&t->cnexpire);
2519 t->srv_state = SV_STCLOSE;
2520 return 1;
2521 }
2522 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002523 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002524 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2525 t->srv_state = SV_STCONN;
2526 }
2527 else { /* try again */
2528 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002529 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002530 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002531 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2532 }
2533
2534 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002535 t->srv_state = SV_STCONN;
2536 break;
2537 }
2538 }
2539 if (t->conn_retries < 0) {
2540 /* if conn_retries < 0 or other error, let's abort */
2541 tv_eternity(&t->cnexpire);
2542 t->srv_state = SV_STCLOSE;
willy tarreaua1598082005-12-17 13:08:06 +01002543 t->logs.status = 502;
willy tarreaue39cd132005-12-17 13:00:18 +01002544 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002545 }
2546 }
2547 return 1;
2548 }
2549 }
2550 else if (s == SV_STCONN) { /* connection in progress */
2551 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2552 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2553 return 0; /* nothing changed */
2554 }
2555 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2556 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2557 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002558 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002559 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002560 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002561 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002562 if (t->conn_retries >= 0) {
2563 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002564 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002565 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2566 }
2567 if (connect_server(t) == 0)
2568 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002569 }
2570 /* if conn_retries < 0 or other error, let's abort */
2571 tv_eternity(&t->cnexpire);
2572 t->srv_state = SV_STCLOSE;
2573 return 1;
2574 }
2575 else { /* no error or write 0 */
willy tarreaua1598082005-12-17 13:08:06 +01002576 t->logs.t_connect = tv_delta(&t->logs.tv_accept, &now);
2577
willy tarreau0f7af912005-12-17 12:21:26 +01002578 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2579 if (req->l == 0) /* nothing to write */
2580 FD_CLR(t->srv_fd, StaticWriteEvent);
2581 else /* need the right to write */
2582 FD_SET(t->srv_fd, StaticWriteEvent);
2583
2584 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2585 FD_SET(t->srv_fd, StaticReadEvent);
2586 if (t->proxy->srvtimeout)
2587 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2588 else
2589 tv_eternity(&t->srexpire);
2590
2591 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002592 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002593 }
willy tarreauef900ab2005-12-17 12:52:52 +01002594 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002595 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002596 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2597 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002598 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002599 return 1;
2600 }
2601 }
2602 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603
2604 /* now parse the partial (or complete) headers */
2605 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2606 char *ptr;
2607 int delete_header;
2608
2609 ptr = rep->lr;
2610
2611 /* look for the end of the current header */
2612 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2613 ptr++;
2614
2615 if (ptr == rep->h) {
2616 char newhdr[MAXREWRITE + 1];
2617 int line, len;
2618
2619 /* we can only get here after an end of headers */
2620 /* we'll have something else to do here : add new headers ... */
2621
willy tarreaue39cd132005-12-17 13:00:18 +01002622 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002623 /* the server is known, it's not the one the client requested, we have to
2624 * insert a set-cookie here.
2625 */
2626 len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
2627 t->proxy->cookie_name, t->srv->cookie);
2628 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2629 }
2630
2631 /* headers to be added */
2632 for (line = 0; line < t->proxy->nb_rspadd; line++) {
2633 len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
2634 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2635 }
2636
2637 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002638 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreaua1598082005-12-17 13:08:06 +01002639 t->logs.t_data = tv_delta(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640 break;
2641 }
2642
2643 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2644 if (ptr > rep->r - 2) {
2645 /* this is a partial header, let's wait for more to come */
2646 rep->lr = ptr;
2647 break;
2648 }
2649
2650 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2651 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2652
2653 /* now we know that *ptr is either \r or \n,
2654 * and that there are at least 1 char after it.
2655 */
2656 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2657 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2658 else
2659 rep->lr = ptr + 2; /* \r\n or \n\r */
2660
2661 /*
2662 * now we know that we have a full header ; we can do whatever
2663 * we want with these pointers :
2664 * rep->h = beginning of header
2665 * ptr = end of header (first \r or \n)
2666 * rep->lr = beginning of next line (next rep->h)
2667 * rep->r = end of data (not used at this stage)
2668 */
2669
willy tarreaua1598082005-12-17 13:08:06 +01002670
2671 if (t->logs.logwait & LW_RESP) {
2672 t->logs.logwait &= ~LW_RESP;
2673 t->logs.status = atoi(rep->h + 9);
2674 }
2675
willy tarreau5cbea6f2005-12-17 12:48:26 +01002676 delete_header = 0;
2677
willy tarreau9fe663a2005-12-17 13:02:59 +01002678 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002679 int len, max;
2680 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2681 max = ptr - rep->h;
2682 UBOUND(max, sizeof(trash) - len - 1);
2683 len += strlcpy(trash + len, rep->h, max + 1);
2684 trash[len++] = '\n';
2685 write(1, trash, len);
2686 }
2687
2688 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002689 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
2690 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002691 char term;
2692
2693 term = *ptr;
2694 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002695 exp = t->proxy->rsp_exp;
2696 do {
2697 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2698 switch (exp->action) {
2699 case ACT_ALLOW:
2700 if (!(t->flags & SN_SVDENY))
2701 t->flags |= SN_SVALLOW;
2702 break;
2703 case ACT_REPLACE:
2704 if (!(t->flags & SN_SVDENY)) {
2705 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2706 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2707 }
2708 break;
2709 case ACT_REMOVE:
2710 if (!(t->flags & SN_SVDENY))
2711 delete_header = 1;
2712 break;
2713 case ACT_DENY:
2714 if (!(t->flags & SN_SVALLOW))
2715 t->flags |= SN_SVDENY;
2716 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002717 }
2718 break;
2719 }
willy tarreaue39cd132005-12-17 13:00:18 +01002720 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002721 *ptr = term; /* restore the string terminator */
2722 }
2723
2724 /* check for server cookies */
2725 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY) && (rep->r >= rep->h + 12) &&
2726 (t->proxy->cookie_name != NULL) && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2727 char *p1, *p2, *p3, *p4;
2728
2729 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2730
2731 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01002732 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002733 p1++;
2734
2735 if (p1 == ptr || *p1 == ';') /* end of cookie */
2736 break;
2737
2738 /* p1 is at the beginning of the cookie name */
2739 p2 = p1;
2740
2741 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2742 p2++;
2743
2744 if (p2 == ptr || *p2 == ';') /* next cookie */
2745 break;
2746
2747 p3 = p2 + 1; /* skips the '=' sign */
2748 if (p3 == ptr)
2749 break;
2750
2751 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01002752 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002753 p4++;
2754
2755 /* here, we have the cookie name between p1 and p2,
2756 * and its value between p3 and p4.
2757 * we can process it.
2758 */
2759
2760 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2761 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2762 /* Cool... it's the right one */
2763
2764 /* If the cookie is in insert mode on a known server, we'll delete
2765 * this occurrence because we'll insert another one later.
2766 * We'll delete it too if the "indirect" option is set and we're in
2767 * a direct access. */
2768 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01002769 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002770 /* this header must be deleted */
2771 delete_header = 1;
2772 }
2773 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2774 /* replace bytes p3->p4 with the cookie name associated
2775 * with this server since we know it.
2776 */
2777 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2778 }
2779 break;
2780 }
2781 else {
2782 // fprintf(stderr,"Ignoring unknown cookie : ");
2783 // write(2, p1, p2-p1);
2784 // fprintf(stderr," = ");
2785 // write(2, p3, p4-p3);
2786 // fprintf(stderr,"\n");
2787 }
2788 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2789 } /* we're now at the end of the cookie value */
2790 } /* end of cookie processing */
2791
2792 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002793 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002794 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01002795
willy tarreau5cbea6f2005-12-17 12:48:26 +01002796 rep->h = rep->lr;
2797 } /* while (rep->lr < rep->r) */
2798
2799 /* end of header processing (even if incomplete) */
2800
willy tarreauef900ab2005-12-17 12:52:52 +01002801 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2802 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2803 * full. We cannot loop here since event_srv_read will disable it only if
2804 * rep->l == rlim-data
2805 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002806 FD_SET(t->srv_fd, StaticReadEvent);
2807 if (t->proxy->srvtimeout)
2808 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2809 else
2810 tv_eternity(&t->srexpire);
2811 }
willy tarreau0f7af912005-12-17 12:21:26 +01002812
2813 /* read or write error */
2814 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002815 tv_eternity(&t->srexpire);
2816 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002817 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002818 t->srv_state = SV_STCLOSE;
2819 return 1;
2820 }
willy tarreauef900ab2005-12-17 12:52:52 +01002821 /* read timeout, last read, or end of client write
2822 * since we are in header mode, if there's no space left for headers, we
2823 * won't be able to free more later, so the session will never terminate.
2824 */
2825 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2826 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002827 FD_CLR(t->srv_fd, StaticReadEvent);
2828 tv_eternity(&t->srexpire);
2829 shutdown(t->srv_fd, SHUT_RD);
2830 t->srv_state = SV_STSHUTR;
2831 return 1;
2832
2833 }
2834 /* write timeout, or last client read and buffer empty */
2835 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2836 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2837 FD_CLR(t->srv_fd, StaticWriteEvent);
2838 tv_eternity(&t->swexpire);
2839 shutdown(t->srv_fd, SHUT_WR);
2840 t->srv_state = SV_STSHUTW;
2841 return 1;
2842 }
2843
2844 if (req->l == 0) {
2845 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2846 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2847 tv_eternity(&t->swexpire);
2848 }
2849 }
2850 else { /* client buffer not empty */
2851 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2852 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2853 if (t->proxy->srvtimeout)
2854 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2855 else
2856 tv_eternity(&t->swexpire);
2857 }
2858 }
2859
willy tarreau5cbea6f2005-12-17 12:48:26 +01002860 /* be nice with the client side which would like to send a complete header
2861 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2862 * would read all remaining data at once ! The client should not write past rep->lr
2863 * when the server is in header state.
2864 */
2865 //return header_processed;
2866 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002867 }
2868 else if (s == SV_STDATA) {
2869 /* read or write error */
2870 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002871 tv_eternity(&t->srexpire);
2872 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002873 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002874 t->srv_state = SV_STCLOSE;
2875 return 1;
2876 }
2877 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01002878 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2879 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002880 FD_CLR(t->srv_fd, StaticReadEvent);
2881 tv_eternity(&t->srexpire);
2882 shutdown(t->srv_fd, SHUT_RD);
2883 t->srv_state = SV_STSHUTR;
2884 return 1;
2885
2886 }
2887 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01002888 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
2889 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002890 FD_CLR(t->srv_fd, StaticWriteEvent);
2891 tv_eternity(&t->swexpire);
2892 shutdown(t->srv_fd, SHUT_WR);
2893 t->srv_state = SV_STSHUTW;
2894 return 1;
2895 }
2896 else if (req->l == 0) {
2897 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2898 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2899 tv_eternity(&t->swexpire);
2900 }
2901 }
2902 else { /* buffer not empty */
2903 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2904 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2905 if (t->proxy->srvtimeout)
2906 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2907 else
2908 tv_eternity(&t->swexpire);
2909 }
2910 }
2911
2912 if (rep->l == BUFSIZE) { /* no room to read more data */
2913 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2914 FD_CLR(t->srv_fd, StaticReadEvent);
2915 tv_eternity(&t->srexpire);
2916 }
2917 }
2918 else {
2919 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2920 FD_SET(t->srv_fd, StaticReadEvent);
2921 if (t->proxy->srvtimeout)
2922 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2923 else
2924 tv_eternity(&t->srexpire);
2925 }
2926 }
2927
2928 return 0; /* other cases change nothing */
2929 }
2930 else if (s == SV_STSHUTR) {
2931 if ((t->res_sw == RES_ERROR) ||
2932 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2933 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002934 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002935 tv_eternity(&t->swexpire);
2936 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002937 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002938 t->srv_state = SV_STCLOSE;
2939 return 1;
2940 }
2941 else if (req->l == 0) {
2942 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2943 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2944 tv_eternity(&t->swexpire);
2945 }
2946 }
2947 else { /* buffer not empty */
2948 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2949 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2950 if (t->proxy->srvtimeout)
2951 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2952 else
2953 tv_eternity(&t->swexpire);
2954 }
2955 }
2956 return 0;
2957 }
2958 else if (s == SV_STSHUTW) {
2959 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
2960 c == CL_STSHUTW || c == CL_STCLOSE ||
2961 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002962 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002963 tv_eternity(&t->srexpire);
2964 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002965 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002966 t->srv_state = SV_STCLOSE;
2967 return 1;
2968 }
2969 else if (rep->l == BUFSIZE) { /* no room to read more data */
2970 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2971 FD_CLR(t->srv_fd, StaticReadEvent);
2972 tv_eternity(&t->srexpire);
2973 }
2974 }
2975 else {
2976 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2977 FD_SET(t->srv_fd, StaticReadEvent);
2978 if (t->proxy->srvtimeout)
2979 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2980 else
2981 tv_eternity(&t->srexpire);
2982 }
2983 }
2984 return 0;
2985 }
2986 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002987 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002988 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002989 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002990 write(1, trash, len);
2991 }
2992 return 0;
2993 }
2994 return 0;
2995}
2996
2997
willy tarreau5cbea6f2005-12-17 12:48:26 +01002998/* Processes the client and server jobs of a session task, then
2999 * puts it back to the wait queue in a clean state, or
3000 * cleans up its resources if it must be deleted. Returns
3001 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003002 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003003int process_session(struct task *t) {
3004 struct session *s = t->context;
3005 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003006
willy tarreau5cbea6f2005-12-17 12:48:26 +01003007 do {
3008 fsm_resync = 0;
3009 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3010 fsm_resync |= process_cli(s);
3011 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3012 fsm_resync |= process_srv(s);
3013 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3014 } while (fsm_resync);
3015
3016 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003017 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003018 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003019
willy tarreau5cbea6f2005-12-17 12:48:26 +01003020 tv_min(&min1, &s->crexpire, &s->cwexpire);
3021 tv_min(&min2, &s->srexpire, &s->swexpire);
3022 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003023 tv_min(&t->expire, &min1, &min2);
3024
3025 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003026 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003027
willy tarreau5cbea6f2005-12-17 12:48:26 +01003028 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003029 }
3030
willy tarreau5cbea6f2005-12-17 12:48:26 +01003031 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003032 actconn--;
3033
willy tarreau9fe663a2005-12-17 13:02:59 +01003034 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003035 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003036 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003037 write(1, trash, len);
3038 }
3039
willy tarreaua1598082005-12-17 13:08:06 +01003040 s->logs.t_close = tv_delta(&s->logs.tv_accept, &now);
3041 if (s->rep != NULL)
3042 s->logs.bytes = s->rep->total;
3043
willy tarreau9fe663a2005-12-17 13:02:59 +01003044 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003045 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003046 sess_log(s);
3047
willy tarreau0f7af912005-12-17 12:21:26 +01003048 /* the task MUST not be in the run queue anymore */
3049 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003050 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003051 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003052 return -1; /* rest in peace for eternity */
3053}
3054
3055
3056
3057/*
3058 * manages a server health-check. Returns
3059 * the time the task accepts to wait, or -1 for infinity.
3060 */
3061int process_chk(struct task *t) {
3062 struct server *s = t->context;
3063 int fd = s->curfd;
3064 int one = 1;
3065
willy tarreauef900ab2005-12-17 12:52:52 +01003066 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003067
3068 if (fd < 0) { /* no check currently running */
3069 //fprintf(stderr, "process_chk: 2\n");
3070 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3071 task_queue(t); /* restore t to its place in the task list */
3072 return tv_remain(&now, &t->expire);
3073 }
3074
3075 /* we'll initiate a new check */
3076 s->result = 0; /* no result yet */
3077 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003078 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003079 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3080 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3081 //fprintf(stderr, "process_chk: 3\n");
3082
3083 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
3084 /* OK, connection in progress or established */
3085
3086 //fprintf(stderr, "process_chk: 4\n");
3087
3088 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3089 fdtab[fd].owner = t;
3090 fdtab[fd].read = NULL;
3091 fdtab[fd].write = &event_srv_hck;
3092 fdtab[fd].state = FD_STCONN; /* connection in progress */
3093 FD_SET(fd, StaticWriteEvent); /* for connect status */
3094 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003095 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3096 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003097 task_queue(t); /* restore t to its place in the task list */
3098 return tv_remain(&now, &t->expire);
3099 }
3100 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3101 s->result = -1; /* a real error */
3102 }
3103 }
3104 //fprintf(stderr, "process_chk: 5\n");
3105 close(fd);
3106 }
3107
3108 if (!s->result) { /* nothing done */
3109 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003110 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003111 task_queue(t); /* restore t to its place in the task list */
3112 return tv_remain(&now, &t->expire);
3113 }
3114
3115 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003116 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003117 s->health--; /* still good */
3118 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003119 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003120 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003121 Warning("server %s DOWN.\n", s->id);
3122
willy tarreau9fe663a2005-12-17 13:02:59 +01003123 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003124 }
willy tarreauef900ab2005-12-17 12:52:52 +01003125
willy tarreau5cbea6f2005-12-17 12:48:26 +01003126 s->health = 0; /* failure */
3127 s->state &= ~SRV_RUNNING;
3128 }
3129
3130 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003131 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3132 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003133 }
3134 else {
3135 //fprintf(stderr, "process_chk: 8\n");
3136 /* there was a test running */
3137 if (s->result > 0) { /* good server detected */
3138 //fprintf(stderr, "process_chk: 9\n");
3139 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003140 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003141 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003142 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003143 Warning("server %s UP.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003144 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003145 }
willy tarreauef900ab2005-12-17 12:52:52 +01003146
willy tarreaue47c8d72005-12-17 12:55:52 +01003147 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003148 s->state |= SRV_RUNNING;
3149 }
willy tarreauef900ab2005-12-17 12:52:52 +01003150 s->curfd = -1; /* no check running anymore */
3151 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003152 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003153 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003154 }
3155 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3156 //fprintf(stderr, "process_chk: 10\n");
3157 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003158 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003159 s->health--; /* still good */
3160 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003161 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003162 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003163 Warning("server %s DOWN.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003164
3165 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003166 }
willy tarreauef900ab2005-12-17 12:52:52 +01003167
willy tarreau5cbea6f2005-12-17 12:48:26 +01003168 s->health = 0; /* failure */
3169 s->state &= ~SRV_RUNNING;
3170 }
3171 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003172 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003173 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003174 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003175 }
3176 /* if result is 0 and there's no timeout, we have to wait again */
3177 }
3178 //fprintf(stderr, "process_chk: 11\n");
3179 s->result = 0;
3180 task_queue(t); /* restore t to its place in the task list */
3181 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003182}
3183
3184
willy tarreau5cbea6f2005-12-17 12:48:26 +01003185
willy tarreau0f7af912005-12-17 12:21:26 +01003186#if STATTIME > 0
3187int stats(void);
3188#endif
3189
3190/*
3191 * Main select() loop.
3192 */
3193
3194void select_loop() {
3195 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003196 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003197 int status;
3198 int fd,i;
3199 struct timeval delta;
3200 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003201 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003202
willy tarreau5cbea6f2005-12-17 12:48:26 +01003203 tv_now(&now);
3204
3205 while (1) {
3206 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003207
willy tarreau5cbea6f2005-12-17 12:48:26 +01003208 /* look for expired tasks and add them to the run queue.
3209 */
3210 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3211 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3212 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003213 if (t->state & TASK_RUNNING)
3214 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003215
3216 /* wakeup expired entries. It doesn't matter if they are
3217 * already running because of a previous event
3218 */
3219 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003220 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003221 task_wakeup(&rq, t);
3222 }
3223 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003224 /* first non-runnable task. Use its expiration date as an upper bound */
3225 int temp_time = tv_remain(&now, &t->expire);
3226 if (temp_time)
3227 next_time = temp_time;
3228 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003229 break;
3230 }
3231 }
3232
3233 /* process each task in the run queue now. Each task may be deleted
3234 * since we only use tnext.
3235 */
3236 tnext = rq;
3237 while ((t = tnext) != NULL) {
3238 int temp_time;
3239
3240 tnext = t->rqnext;
3241 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003242 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003243 temp_time = t->process(t);
3244 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003245 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003246 }
3247
willy tarreauef900ab2005-12-17 12:52:52 +01003248 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003249
3250 /* maintain all proxies in a consistent state. This should quickly become a task */
3251 time2 = maintain_proxies();
3252 next_time = MINTIME(time2, next_time);
3253
3254 /* stop when there's no connection left and we don't allow them anymore */
3255 if (!actconn && listeners == 0)
3256 break;
3257
willy tarreau0f7af912005-12-17 12:21:26 +01003258
3259#if STATTIME > 0
3260 time2 = stats();
3261 // fprintf(stderr," stats = %d\n", time2);
3262 next_time = MINTIME(time2, next_time);
3263#endif
3264
willy tarreau5cbea6f2005-12-17 12:48:26 +01003265 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003266 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003267 /* to avoid eventual select loops due to timer precision */
3268 next_time += SCHEDULER_RESOLUTION;
3269 delta.tv_sec = next_time / 1000;
3270 delta.tv_usec = (next_time % 1000) * 1000;
3271 }
3272 else if (next_time == 0) { /* allow select to return immediately when needed */
3273 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003274 }
3275
3276
3277 /* let's restore fdset state */
3278
3279 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003280 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003281 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3282 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3283 }
3284
3285// /* just a verification code, needs to be removed for performance */
3286// for (i=0; i<maxfd; i++) {
3287// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3288// abort();
3289// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3290// abort();
3291//
3292// }
3293
3294 status=select(maxfd,
3295 readnotnull ? ReadEvent : NULL,
3296 writenotnull ? WriteEvent : NULL,
3297 NULL,
3298 (next_time >= 0) ? &delta : NULL);
3299
willy tarreau5cbea6f2005-12-17 12:48:26 +01003300 /* this is an experiment on the separation of the select work */
3301 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3302 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3303
willy tarreau0f7af912005-12-17 12:21:26 +01003304 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003305
willy tarreau0f7af912005-12-17 12:21:26 +01003306 if (status > 0) { /* must proceed with events */
3307
3308 int fds;
3309 char count;
3310
3311 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3312 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3313 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3314
willy tarreau5cbea6f2005-12-17 12:48:26 +01003315 /* if we specify read first, the accepts and zero reads will be
3316 * seen first. Moreover, system buffers will be flushed faster.
3317 */
willy tarreau0f7af912005-12-17 12:21:26 +01003318 if (fdtab[fd].state == FD_STCLOSE)
3319 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003320
3321 if (FD_ISSET(fd, ReadEvent))
3322 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003323
willy tarreau5cbea6f2005-12-17 12:48:26 +01003324 if (FD_ISSET(fd, WriteEvent))
3325 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003326 }
3327 }
3328 else {
3329 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3330 }
willy tarreau0f7af912005-12-17 12:21:26 +01003331 }
3332}
3333
3334
3335#if STATTIME > 0
3336/*
3337 * Display proxy statistics regularly. It is designed to be called from the
3338 * select_loop().
3339 */
3340int stats(void) {
3341 static int lines;
3342 static struct timeval nextevt;
3343 static struct timeval lastevt;
3344 static struct timeval starttime = {0,0};
3345 unsigned long totaltime, deltatime;
3346 int ret;
3347
3348 if (tv_remain(&now, &nextevt) == 0) {
3349 deltatime = (tv_delta(&now, &lastevt)?:1);
3350 totaltime = (tv_delta(&now, &starttime)?:1);
3351
willy tarreau9fe663a2005-12-17 13:02:59 +01003352 if (global.mode & MODE_STATS) {
3353 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003354 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003355 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3356 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003357 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003358 actconn, totalconn,
3359 stats_tsk_new, stats_tsk_good,
3360 stats_tsk_left, stats_tsk_right,
3361 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3362 }
3363 }
3364
3365 tv_delayfrom(&nextevt, &now, STATTIME);
3366
3367 lastevt=now;
3368 }
3369 ret = tv_remain(&now, &nextevt);
3370 return ret;
3371}
3372#endif
3373
3374
3375/*
3376 * this function enables proxies when there are enough free sessions,
3377 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003378 * select_loop(). It returns the time left before next expiration event
3379 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003380 */
3381static int maintain_proxies(void) {
3382 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003383 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003384
3385 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003386 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003387
3388 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003389 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003390 while (p) {
3391 if (p->nbconn < p->maxconn) {
3392 if (p->state == PR_STIDLE) {
3393 FD_SET(p->listen_fd, StaticReadEvent);
3394 p->state = PR_STRUN;
3395 }
3396 }
3397 else {
3398 if (p->state == PR_STRUN) {
3399 FD_CLR(p->listen_fd, StaticReadEvent);
3400 p->state = PR_STIDLE;
3401 }
3402 }
3403 p = p->next;
3404 }
3405 }
3406 else { /* block all proxies */
3407 while (p) {
3408 if (p->state == PR_STRUN) {
3409 FD_CLR(p->listen_fd, StaticReadEvent);
3410 p->state = PR_STIDLE;
3411 }
3412 p = p->next;
3413 }
3414 }
3415
willy tarreau5cbea6f2005-12-17 12:48:26 +01003416 if (stopping) {
3417 p = proxy;
3418 while (p) {
3419 if (p->state != PR_STDISABLED) {
3420 int t;
3421 t = tv_remain(&now, &p->stop_time);
3422 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003423 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003424 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003425
willy tarreau5cbea6f2005-12-17 12:48:26 +01003426 fd_delete(p->listen_fd);
3427 p->state = PR_STDISABLED;
3428 listeners--;
3429 }
3430 else {
3431 tleft = MINTIME(t, tleft);
3432 }
3433 }
3434 p = p->next;
3435 }
3436 }
3437 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003438}
3439
3440/*
3441 * this function disables health-check servers so that the process will quickly be ignored
3442 * by load balancers.
3443 */
3444static void soft_stop(void) {
3445 struct proxy *p;
3446
3447 stopping = 1;
3448 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003449 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003450 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003451 if (p->state != PR_STDISABLED) {
3452 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01003453 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01003454 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01003455 }
willy tarreau0f7af912005-12-17 12:21:26 +01003456 p = p->next;
3457 }
3458}
3459
3460/*
3461 * upon SIGUSR1, let's have a soft stop.
3462 */
3463void sig_soft_stop(int sig) {
3464 soft_stop();
3465 signal(sig, SIG_IGN);
3466}
3467
3468
3469void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003470 struct task *t, *tnext;
3471 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003472
willy tarreau5cbea6f2005-12-17 12:48:26 +01003473 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3474 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3475 tnext = t->next;
3476 s = t->context;
3477 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3478 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3479 "req=%d, rep=%d, clifd=%d\n",
3480 s, tv_remain(&now, &t->expire),
3481 s->cli_state,
3482 s->srv_state,
3483 FD_ISSET(s->cli_fd, StaticReadEvent),
3484 FD_ISSET(s->cli_fd, StaticWriteEvent),
3485 FD_ISSET(s->srv_fd, StaticReadEvent),
3486 FD_ISSET(s->srv_fd, StaticWriteEvent),
3487 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3488 );
willy tarreau0f7af912005-12-17 12:21:26 +01003489 }
3490}
3491
willy tarreaue39cd132005-12-17 13:00:18 +01003492void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
3493 struct hdr_exp *exp;
3494
3495 while (*head != NULL)
3496 head = &(*head)->next;
3497
3498 exp = calloc(1, sizeof(struct hdr_exp));
3499
3500 exp->preg = preg;
3501 exp->replace = replace;
3502 exp->action = action;
3503 *head = exp;
3504}
3505
willy tarreau9fe663a2005-12-17 13:02:59 +01003506
willy tarreau0f7af912005-12-17 12:21:26 +01003507/*
willy tarreau9fe663a2005-12-17 13:02:59 +01003508 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01003509 */
willy tarreau9fe663a2005-12-17 13:02:59 +01003510int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01003511
willy tarreau9fe663a2005-12-17 13:02:59 +01003512 if (!strcmp(args[0], "global")) { /* new section */
3513 /* no option, nothing special to do */
3514 return 0;
3515 }
3516 else if (!strcmp(args[0], "daemon")) {
3517 global.mode |= MODE_DAEMON;
3518 }
3519 else if (!strcmp(args[0], "debug")) {
3520 global.mode |= MODE_DEBUG;
3521 }
3522 else if (!strcmp(args[0], "quiet")) {
3523 global.mode |= MODE_QUIET;
3524 }
3525 else if (!strcmp(args[0], "stats")) {
3526 global.mode |= MODE_STATS;
3527 }
3528 else if (!strcmp(args[0], "uid")) {
3529 if (global.uid != 0) {
3530 Alert("parsing [%s:%d] : <uid> already specified. Continuing.\n", file, linenum);
3531 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003532 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003533 if (*(args[1]) == 0) {
3534 Alert("parsing [%s:%d] : <uid> expects an integer argument.\n", file, linenum);
3535 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003536 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003537 global.uid = atol(args[1]);
3538 }
3539 else if (!strcmp(args[0], "gid")) {
3540 if (global.gid != 0) {
3541 Alert("parsing [%s:%d] : <gid> already specified. Continuing.\n", file, linenum);
3542 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003543 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003544 if (*(args[1]) == 0) {
3545 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003546 return -1;
3547 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003548 global.gid = atol(args[1]);
3549 }
3550 else if (!strcmp(args[0], "nbproc")) {
3551 if (global.nbproc != 0) {
3552 Alert("parsing [%s:%d] : <nbproc> already specified. Continuing.\n", file, linenum);
3553 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003554 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003555 if (*(args[1]) == 0) {
3556 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
3557 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003558 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003559 global.nbproc = atol(args[1]);
3560 }
3561 else if (!strcmp(args[0], "maxconn")) {
3562 if (global.maxconn != 0) {
3563 Alert("parsing [%s:%d] : <maxconn> already specified. Continuing.\n", file, linenum);
3564 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003565 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003566 if (*(args[1]) == 0) {
3567 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3568 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003569 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003570 global.maxconn = atol(args[1]);
3571 }
3572 else if (!strcmp(args[0], "chroot")) {
3573 if (global.chroot != NULL) {
3574 Alert("parsing [%s:%d] : <chroot> already specified. Continuing.\n", file, linenum);
3575 return 0;
3576 }
3577 if (*(args[1]) == 0) {
3578 Alert("parsing [%s:%d] : <chroot> expects a directory as an argument.\n", file, linenum);
3579 return -1;
3580 }
3581 global.chroot = strdup(args[1]);
3582 }
3583 else if (!strcmp(args[0], "log")) { /* syslog server address */
3584 struct sockaddr_in *sa;
3585 int facility;
3586
3587 if (*(args[1]) == 0 || *(args[2]) == 0) {
3588 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n", file, linenum);
3589 return -1;
3590 }
3591
3592 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3593 if (!strcmp(log_facilities[facility], args[2]))
3594 break;
3595
3596 if (facility >= NB_LOG_FACILITIES) {
3597 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3598 exit(1);
3599 }
3600
3601 sa = str2sa(args[1]);
3602 if (!sa->sin_port)
3603 sa->sin_port = htons(SYSLOG_PORT);
3604
3605 if (global.logfac1 == -1) {
3606 global.logsrv1 = *sa;
3607 global.logfac1 = facility;
3608 }
3609 else if (global.logfac2 == -1) {
3610 global.logsrv2 = *sa;
3611 global.logfac2 = facility;
3612 }
3613 else {
3614 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3615 return -1;
3616 }
3617
3618 }
3619 else {
3620 Alert("parsing [%s:%d] : unknown keyword <%s> in <global> section\n", file, linenum, args[0]);
3621 return -1;
3622 }
3623 return 0;
3624}
3625
3626
3627/*
3628 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
3629 */
3630int cfg_parse_listen(char *file, int linenum, char **args) {
3631 static struct proxy *curproxy = NULL;
3632 struct server *newsrv = NULL;
3633
3634 if (!strcmp(args[0], "listen")) { /* new proxy */
3635 if (strchr(args[2], ':') == NULL) {
3636 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3637 file, linenum);
3638 return -1;
3639 }
3640
3641 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
3642 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3643 return -1;
3644 }
3645 curproxy->next = proxy;
3646 proxy = curproxy;
3647 curproxy->id = strdup(args[1]);
3648 curproxy->listen_addr = *str2sa(args[2]);
3649 curproxy->state = PR_STNEW;
3650 /* set default values */
3651 curproxy->maxconn = cfg_maxpconn;
3652 curproxy->conn_retries = CONN_RETRIES;
3653 curproxy->options = 0;
3654 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3655 curproxy->mode = PR_MODE_TCP;
3656 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3657 curproxy->to_log = 0;
3658 return 0;
3659 }
3660 else if (curproxy == NULL) {
3661 Alert("parsing [%s:%d] : <listen> expected.\n", file, linenum);
3662 return -1;
3663 }
3664
3665 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3666 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3667 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3668 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3669 else {
3670 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3671 return -1;
3672 }
3673 }
3674 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3675 curproxy->state = PR_STDISABLED;
3676 }
3677 else if (!strcmp(args[0], "cookie")) { /* cookie name */
3678 int cur_arg;
3679 if (curproxy->cookie_name != NULL) {
3680 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3681 file, linenum);
3682 return 0;
3683 }
3684
3685 if (*(args[1]) == 0) {
3686 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3687 file, linenum);
3688 return -1;
3689 }
3690 curproxy->cookie_name = strdup(args[1]);
3691
3692 cur_arg = 2;
3693 while (*(args[cur_arg])) {
3694 if (!strcmp(args[cur_arg], "rewrite")) {
3695 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01003696 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003697 else if (!strcmp(args[cur_arg], "indirect")) {
3698 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01003699 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003700 else if (!strcmp(args[cur_arg], "insert")) {
3701 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01003702 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003703 else {
3704 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003705 file, linenum);
3706 return -1;
3707 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003708 cur_arg++;
3709 }
3710 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3711 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3712 file, linenum);
3713 return -1;
3714 }
3715 }
3716 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3717 if (curproxy->contimeout != 0) {
3718 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n", file, linenum);
3719 return 0;
3720 }
3721 if (*(args[1]) == 0) {
3722 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3723 file, linenum);
3724 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003725 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003726 curproxy->contimeout = atol(args[1]);
3727 }
3728 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3729 if (curproxy->clitimeout != 0) {
3730 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3731 file, linenum);
3732 return 0;
3733 }
3734 if (*(args[1]) == 0) {
3735 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3736 file, linenum);
3737 return -1;
3738 }
3739 curproxy->clitimeout = atol(args[1]);
3740 }
3741 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3742 if (curproxy->srvtimeout != 0) {
3743 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n", file, linenum);
3744 return 0;
3745 }
3746 if (*(args[1]) == 0) {
3747 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003748 file, linenum);
3749 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003750 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003751 curproxy->srvtimeout = atol(args[1]);
3752 }
3753 else if (!strcmp(args[0], "retries")) { /* connection retries */
3754 if (*(args[1]) == 0) {
3755 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3756 file, linenum);
3757 return -1;
3758 }
3759 curproxy->conn_retries = atol(args[1]);
3760 }
3761 else if (!strcmp(args[0], "option")) {
3762 if (*(args[1]) == 0) {
3763 Alert("parsing [%s:%d] : <option> expects an option name.\n", file, linenum);
3764 return -1;
3765 }
3766 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003767 /* enable reconnections to dispatch */
3768 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01003769#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003770 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003771 /* enable transparent proxy connections */
3772 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01003773#endif
3774 else if (!strcmp(args[1], "keepalive"))
3775 /* enable keep-alive */
3776 curproxy->options |= PR_O_KEEPALIVE;
3777 else if (!strcmp(args[1], "forwardfor"))
3778 /* insert x-forwarded-for field */
3779 curproxy->options |= PR_O_FWDFOR;
3780 else if (!strcmp(args[1], "httplog")) {
3781 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01003782 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
3783 }
3784 else if (!strcmp(args[1], "dontlognull")) {
3785 /* don't log empty requests */
3786 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003787 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003788 else {
3789 Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
3790 return -1;
3791 }
3792 return 0;
3793 }
3794 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3795 /* enable reconnections to dispatch */
3796 curproxy->options |= PR_O_REDISP;
3797 }
willy tarreaua1598082005-12-17 13:08:06 +01003798#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003799 else if (!strcmp(args[0], "transparent")) {
3800 /* enable transparent proxy connections */
3801 curproxy->options |= PR_O_TRANSP;
3802 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003803#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01003804 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3805 if (*(args[1]) == 0) {
3806 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3807 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003808 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003809 curproxy->maxconn = atol(args[1]);
3810 }
3811 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3812 if (*(args[1]) == 0) {
3813 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n", file, linenum);
3814 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003815 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003816 curproxy->grace = atol(args[1]);
3817 }
3818 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3819 if (strchr(args[1], ':') == NULL) {
3820 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n", file, linenum);
3821 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003822 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003823 curproxy->dispatch_addr = *str2sa(args[1]);
3824 }
3825 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
3826 if (*(args[1])) {
3827 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003828 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01003829 }
3830 else {
3831 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n", file, linenum);
3832 return -1;
3833 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003834 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003835 else /* if no option is set, use round-robin by default */
3836 curproxy->options |= PR_O_BALANCE_RR;
3837 }
3838 else if (!strcmp(args[0], "server")) { /* server address */
3839 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003840
willy tarreau9fe663a2005-12-17 13:02:59 +01003841 if (strchr(args[2], ':') == NULL) {
3842 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
3843 file, linenum);
3844 return -1;
3845 }
3846 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
3847 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3848 return -1;
3849 }
3850 newsrv->next = curproxy->srv;
3851 curproxy->srv = newsrv;
3852 newsrv->proxy = curproxy;
3853 newsrv->id = strdup(args[1]);
3854 newsrv->addr = *str2sa(args[2]);
3855 newsrv->state = SRV_RUNNING; /* early server setup */
3856 newsrv->curfd = -1; /* no health-check in progress */
3857 newsrv->inter = DEF_CHKINTR;
3858 newsrv->rise = DEF_RISETIME;
3859 newsrv->fall = DEF_FALLTIME;
3860 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
3861 cur_arg = 3;
3862 while (*args[cur_arg]) {
3863 if (!strcmp(args[cur_arg], "cookie")) {
3864 newsrv->cookie = strdup(args[cur_arg + 1]);
3865 newsrv->cklen = strlen(args[cur_arg + 1]);
3866 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01003867 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003868 else if (!strcmp(args[cur_arg], "rise")) {
3869 newsrv->rise = atol(args[cur_arg + 1]);
3870 newsrv->health = newsrv->rise;
3871 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01003872 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003873 else if (!strcmp(args[cur_arg], "fall")) {
3874 newsrv->fall = atol(args[cur_arg + 1]);
3875 cur_arg += 2;
3876 }
3877 else if (!strcmp(args[cur_arg], "inter")) {
3878 newsrv->inter = atol(args[cur_arg + 1]);
3879 cur_arg += 2;
3880 }
3881 else if (!strcmp(args[cur_arg], "check")) {
3882 struct task *t;
3883
3884 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3885 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003886 return -1;
3887 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003888
3889 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
3890 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
3891 t->state = TASK_IDLE;
3892 t->process = process_chk;
3893 t->context = newsrv;
3894
3895 if (curproxy->state != PR_STDISABLED) {
3896 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
3897 task_queue(t);
3898 task_wakeup(&rq, t);
3899 }
3900
3901 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003902 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003903 else {
3904 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
3905 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01003906 return -1;
3907 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003908 }
3909 curproxy->nbservers++;
3910 }
3911 else if (!strcmp(args[0], "log")) { /* syslog server address */
3912 struct sockaddr_in *sa;
3913 int facility;
3914
3915 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
3916 curproxy->logfac1 = global.logfac1;
3917 curproxy->logsrv1 = global.logsrv1;
3918 curproxy->logfac2 = global.logfac2;
3919 curproxy->logsrv2 = global.logsrv2;
3920 }
3921 else if (*(args[1]) && *(args[2])) {
willy tarreau0f7af912005-12-17 12:21:26 +01003922 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3923 if (!strcmp(log_facilities[facility], args[2]))
3924 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01003925
willy tarreau0f7af912005-12-17 12:21:26 +01003926 if (facility >= NB_LOG_FACILITIES) {
3927 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3928 exit(1);
3929 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003930
willy tarreau0f7af912005-12-17 12:21:26 +01003931 sa = str2sa(args[1]);
3932 if (!sa->sin_port)
3933 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01003934
willy tarreau0f7af912005-12-17 12:21:26 +01003935 if (curproxy->logfac1 == -1) {
3936 curproxy->logsrv1 = *sa;
3937 curproxy->logfac1 = facility;
3938 }
3939 else if (curproxy->logfac2 == -1) {
3940 curproxy->logsrv2 = *sa;
3941 curproxy->logfac2 = facility;
3942 }
3943 else {
3944 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01003945 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003946 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003947 }
3948 else {
3949 Alert("parsing [%s:%d] : <log> expects either <address[:port]> and <facility> or 'global' as arguments.\n",
3950 file, linenum);
3951 return -1;
3952 }
3953 }
willy tarreaua1598082005-12-17 13:08:06 +01003954 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3955 if (strchr(args[1], ':') == NULL) {
3956 Alert("parsing [%s:%d] : <source> expects <addr:port> as argument.\n",
3957 file, linenum);
3958 return -1;
3959 }
3960
3961 curproxy->source_addr = *str2sa(args[1]);
3962 curproxy->options |= PR_O_BIND_SRC;
3963 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003964 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
3965 regex_t *preg;
3966
3967 if (*(args[1]) == 0 || *(args[2]) == 0) {
3968 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
3969 file, linenum);
3970 return -1;
3971 }
3972
3973 preg = calloc(1, sizeof(regex_t));
3974 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3975 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3976 return -1;
3977 }
3978
3979 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
3980 }
3981 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
3982 regex_t *preg;
3983
3984 if (*(args[1]) == 0) {
3985 Alert("parsing [%s:%d] : <reqdel> expects <regex> as an argument.\n", file, linenum);
3986 return -1;
3987 }
3988
3989 preg = calloc(1, sizeof(regex_t));
3990 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3991 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3992 return -1;
3993 }
3994
3995 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
3996 }
3997 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
3998 regex_t *preg;
3999
4000 if (*(args[1]) == 0) {
4001 Alert("parsing [%s:%d] : <reqdeny> expects <regex> as an argument.\n", file, linenum);
4002 return -1;
4003 }
4004
4005 preg = calloc(1, sizeof(regex_t));
4006 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4007 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4008 return -1;
4009 }
4010
4011 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4012 }
4013 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4014 regex_t *preg;
4015
4016 if (*(args[1]) == 0) {
4017 Alert("parsing [%s:%d] : <reqallow> expects <regex> as an argument.\n", file, linenum);
4018 return -1;
4019 }
4020
4021 preg = calloc(1, sizeof(regex_t));
4022 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4023 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4024 return -1;
4025 }
4026
4027 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4028 }
4029 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4030 regex_t *preg;
4031
4032 if (*(args[1]) == 0 || *(args[2]) == 0) {
4033 Alert("parsing [%s:%d] : <reqirep> expects <search> and <replace> as arguments.\n",
4034 file, linenum);
4035 return -1;
4036 }
4037
4038 preg = calloc(1, sizeof(regex_t));
4039 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4040 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4041 return -1;
4042 }
4043
4044 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4045 }
4046 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4047 regex_t *preg;
4048
4049 if (*(args[1]) == 0) {
4050 Alert("parsing [%s:%d] : <reqidel> expects <regex> as an argument.\n", file, linenum);
4051 return -1;
4052 }
4053
4054 preg = calloc(1, sizeof(regex_t));
4055 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4056 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4057 return -1;
4058 }
4059
4060 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4061 }
4062 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4063 regex_t *preg;
4064
4065 if (*(args[1]) == 0) {
4066 Alert("parsing [%s:%d] : <reqideny> expects <regex> as an argument.\n", file, linenum);
4067 return -1;
4068 }
4069
4070 preg = calloc(1, sizeof(regex_t));
4071 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4072 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4073 return -1;
4074 }
4075
4076 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4077 }
4078 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4079 regex_t *preg;
4080
4081 if (*(args[1]) == 0) {
4082 Alert("parsing [%s:%d] : <reqiallow> expects <regex> as an argument.\n", file, linenum);
4083 return -1;
4084 }
4085
4086 preg = calloc(1, sizeof(regex_t));
4087 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4088 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4089 return -1;
4090 }
4091
4092 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4093 }
4094 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4095 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
4096 Alert("parsing [%s:%d] : too many `reqadd'. Continuing.\n", file, linenum);
4097 return 0;
4098 }
4099
4100 if (*(args[1]) == 0) {
4101 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n", file, linenum);
4102 return -1;
4103 }
4104
4105 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004107 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004108 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004109
4110 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004111 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004112 file, linenum);
4113 return -1;
4114 }
4115
4116 preg = calloc(1, sizeof(regex_t));
4117 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4118 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4119 return -1;
4120 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004121
4122 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4123 }
4124 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4125 regex_t *preg;
4126
4127 if (*(args[1]) == 0) {
4128 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n", file, linenum);
4129 return -1;
4130 }
willy tarreaue39cd132005-12-17 13:00:18 +01004131
willy tarreau9fe663a2005-12-17 13:02:59 +01004132 preg = calloc(1, sizeof(regex_t));
4133 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4134 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4135 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004136 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004137
4138 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4139 }
4140 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004141 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004142
willy tarreau9fe663a2005-12-17 13:02:59 +01004143 if (*(args[1]) == 0 || *(args[2]) == 0) {
4144 Alert("parsing [%s:%d] : <rspirep> expects <search> and <replace> as arguments.\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01004145 file, linenum);
willy tarreaue39cd132005-12-17 13:00:18 +01004146 return -1;
4147 }
4148
4149 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004150 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreaue39cd132005-12-17 13:00:18 +01004151 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4152 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004153 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004154
4155 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4156 }
4157 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4158 regex_t *preg;
4159
4160 if (*(args[1]) == 0) {
4161 Alert("parsing [%s:%d] : <rspidel> expects <search> as an argument.\n", file, linenum);
4162 return -1;
4163 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004164
willy tarreau9fe663a2005-12-17 13:02:59 +01004165 preg = calloc(1, sizeof(regex_t));
4166 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4167 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4168 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004169 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004170
4171 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4172 }
4173 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4174 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
4175 Alert("parsing [%s:%d] : too many `rspadd'. Continuing.\n", file, linenum);
4176 return 0;
4177 }
4178
4179 if (*(args[1]) == 0) {
4180 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n", file, linenum);
4181 return -1;
4182 }
4183
4184 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4185 }
4186 else {
4187 Alert("parsing [%s:%d] : unknown keyword <%s> in <listen> section\n", file, linenum, args[0]);
4188 return -1;
4189 }
4190 return 0;
4191}
willy tarreaue39cd132005-12-17 13:00:18 +01004192
willy tarreau5cbea6f2005-12-17 12:48:26 +01004193
willy tarreau9fe663a2005-12-17 13:02:59 +01004194/*
4195 * This function reads and parses the configuration file given in the argument.
4196 * returns 0 if OK, -1 if error.
4197 */
4198int readcfgfile(char *file) {
4199 char thisline[256];
4200 char *line;
4201 FILE *f;
4202 int linenum = 0;
4203 char *end;
4204 char *args[MAX_LINE_ARGS];
4205 int arg;
4206 int cfgerr = 0;
4207 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01004208
willy tarreau9fe663a2005-12-17 13:02:59 +01004209 struct proxy *curproxy = NULL;
4210 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01004211
willy tarreau9fe663a2005-12-17 13:02:59 +01004212 if ((f=fopen(file,"r")) == NULL)
4213 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004214
willy tarreau9fe663a2005-12-17 13:02:59 +01004215 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
4216 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004217
willy tarreau9fe663a2005-12-17 13:02:59 +01004218 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004219
willy tarreau9fe663a2005-12-17 13:02:59 +01004220 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01004221 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01004222 line++;
4223
4224 arg = 0;
4225 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01004226
willy tarreau9fe663a2005-12-17 13:02:59 +01004227 while (*line && arg < MAX_LINE_ARGS) {
4228 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
4229 * C equivalent value. Other combinations left unchanged (eg: \1).
4230 */
4231 if (*line == '\\') {
4232 int skip = 0;
4233 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
4234 *line = line[1];
4235 skip = 1;
4236 }
4237 else if (line[1] == 'r') {
4238 *line = '\r';
4239 skip = 1;
4240 }
4241 else if (line[1] == 'n') {
4242 *line = '\n';
4243 skip = 1;
4244 }
4245 else if (line[1] == 't') {
4246 *line = '\t';
4247 skip = 1;
4248 }
4249 else if (line[1] == 'x' && (line + 3 < end )) {
4250 unsigned char hex1, hex2;
4251 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
4252 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4253 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4254 *line = (hex1<<4) + hex2;
4255 skip = 3;
4256 }
4257 if (skip) {
4258 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
4259 end -= skip;
4260 }
4261 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004262 }
willy tarreaua1598082005-12-17 13:08:06 +01004263 else if (*line == '#' || *line == '\n' || *line == '\r') {
4264 /* end of string, end of loop */
4265 *line = 0;
4266 break;
4267 }
willy tarreauc29948c2005-12-17 13:10:27 +01004268 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004269 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01004270 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01004271 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01004272 line++;
4273 args[++arg] = line;
4274 }
4275 else {
4276 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004277 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004278 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004279
willy tarreau9fe663a2005-12-17 13:02:59 +01004280 /* empty line */
4281 if (!**args)
4282 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01004283
willy tarreau9fe663a2005-12-17 13:02:59 +01004284 /* zero out remaining args */
4285 while (++arg < MAX_LINE_ARGS) {
4286 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004287 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004288
willy tarreau9fe663a2005-12-17 13:02:59 +01004289 if (!strcmp(args[0], "listen")) /* new proxy */
4290 confsect = CFG_LISTEN;
4291 else if (!strcmp(args[0], "global")) /* global config */
4292 confsect = CFG_GLOBAL;
4293 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004294
willy tarreau9fe663a2005-12-17 13:02:59 +01004295 switch (confsect) {
4296 case CFG_LISTEN:
4297 if (cfg_parse_listen(file, linenum, args) < 0)
4298 return -1;
4299 break;
4300 case CFG_GLOBAL:
4301 if (cfg_parse_global(file, linenum, args) < 0)
4302 return -1;
4303 break;
4304 default:
4305 Alert("parsing [%s:%d] : unknown keyword <%s> out of section.\n", file, linenum, args[0]);
4306 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004307 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004308
4309
willy tarreau0f7af912005-12-17 12:21:26 +01004310 }
4311 fclose(f);
4312
4313 /*
4314 * Now, check for the integrity of all that we have collected.
4315 */
4316
4317 if ((curproxy = proxy) == NULL) {
4318 Alert("parsing %s : no <listen> line. Nothing to do !\n",
4319 file);
4320 return -1;
4321 }
4322
4323 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01004324 if (curproxy->state == PR_STDISABLED) {
4325 curproxy = curproxy->next;
4326 continue;
4327 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004328 if ((curproxy->mode != PR_MODE_HEALTH) &&
4329 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01004330 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004331 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
4332 file, curproxy->id);
4333 cfgerr++;
4334 }
4335 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
4336 if (curproxy->options & PR_O_TRANSP) {
4337 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
4338 file, curproxy->id);
4339 cfgerr++;
4340 }
4341 else if (curproxy->srv == NULL) {
4342 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
4343 file, curproxy->id);
4344 cfgerr++;
4345 }
willy tarreaua1598082005-12-17 13:08:06 +01004346 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004347 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
4348 file, curproxy->id);
4349 }
4350 }
4351 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01004352 if (curproxy->cookie_name != NULL) {
4353 Warning("parsing %s : cookie will be ignored for listener %s.\n",
4354 file, curproxy->id);
4355 }
4356 if ((newsrv = curproxy->srv) != NULL) {
4357 Warning("parsing %s : servers will be ignored for listener %s.\n",
4358 file, curproxy->id);
4359 }
willy tarreaue39cd132005-12-17 13:00:18 +01004360 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004361 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
4362 file, curproxy->id);
4363 }
willy tarreaue39cd132005-12-17 13:00:18 +01004364 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004365 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
4366 file, curproxy->id);
4367 }
4368 }
4369 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
4370 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
4371 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
4372 file, curproxy->id);
4373 cfgerr++;
4374 }
4375 else {
4376 while (newsrv != NULL) {
4377 /* nothing to check for now */
4378 newsrv = newsrv->next;
4379 }
4380 }
4381 }
4382 curproxy = curproxy->next;
4383 }
4384 if (cfgerr > 0) {
4385 Alert("Errors found in configuration file, aborting.\n");
4386 return -1;
4387 }
4388 else
4389 return 0;
4390}
4391
4392
4393/*
4394 * This function initializes all the necessary variables. It only returns
4395 * if everything is OK. If something fails, it exits.
4396 */
4397void init(int argc, char **argv) {
4398 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01004399 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004400 char *old_argv = *argv;
4401 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01004402 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01004403
4404 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004405 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004406 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
4407 sizeof(int)*8);
4408 exit(1);
4409 }
4410
4411 pid = getpid();
4412 progname = *argv;
4413 while ((tmp = strchr(progname, '/')) != NULL)
4414 progname = tmp + 1;
4415
4416 argc--; argv++;
4417 while (argc > 0) {
4418 char *flag;
4419
4420 if (**argv == '-') {
4421 flag = *argv+1;
4422
4423 /* 1 arg */
4424 if (*flag == 'v') {
4425 display_version();
4426 exit(0);
4427 }
4428 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01004429 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01004430 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01004431 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004432 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01004433 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01004434#if STATTIME > 0
4435 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01004436 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01004437 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01004438 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01004439#endif
4440 else { /* >=2 args */
4441 argv++; argc--;
4442 if (argc == 0)
4443 usage(old_argv);
4444
4445 switch (*flag) {
4446 case 'n' : cfg_maxconn = atol(*argv); break;
4447 case 'N' : cfg_maxpconn = atol(*argv); break;
4448 case 'f' : cfg_cfgfile = *argv; break;
4449 default: usage(old_argv);
4450 }
4451 }
4452 }
4453 else
4454 usage(old_argv);
4455 argv++; argc--;
4456 }
4457
willy tarreau0f7af912005-12-17 12:21:26 +01004458 if (!cfg_cfgfile)
4459 usage(old_argv);
4460
4461 gethostname(hostname, MAX_HOSTNAME_LEN);
4462
4463 if (readcfgfile(cfg_cfgfile) < 0) {
4464 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
4465 exit(1);
4466 }
4467
willy tarreau9fe663a2005-12-17 13:02:59 +01004468 if (cfg_maxconn > 0)
4469 global.maxconn = cfg_maxconn;
4470
4471 if (global.maxconn == 0)
4472 global.maxconn = DEFAULT_MAXCONN;
4473
4474 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
4475
4476 if (arg_mode & MODE_DEBUG) {
4477 /* command line debug mode inhibits configuration mode */
4478 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4479 }
4480 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG));
4481
4482 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
4483 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
4484 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4485 }
4486
4487 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
4488 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
4489 global.nbproc = 1;
4490 }
4491
4492 if (global.nbproc < 1)
4493 global.nbproc = 1;
4494
willy tarreau0f7af912005-12-17 12:21:26 +01004495 ReadEvent = (fd_set *)calloc(1,
4496 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004497 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004498 WriteEvent = (fd_set *)calloc(1,
4499 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004500 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004501 StaticReadEvent = (fd_set *)calloc(1,
4502 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004503 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004504 StaticWriteEvent = (fd_set *)calloc(1,
4505 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004506 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004507
4508 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01004509 sizeof(struct fdtab) * (global.maxsock));
4510 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004511 fdtab[i].state = FD_STCLOSE;
4512 }
4513}
4514
4515/*
4516 * this function starts all the proxies. It returns 0 if OK, -1 if not.
4517 */
4518int start_proxies() {
4519 struct proxy *curproxy;
4520 int one = 1;
4521 int fd;
4522
4523 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
4524
4525 if (curproxy->state == PR_STDISABLED)
4526 continue;
4527
4528 if ((fd = curproxy->listen_fd =
4529 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
4530 Alert("cannot create listening socket for proxy %s. Aborting.\n",
4531 curproxy->id);
4532 return -1;
4533 }
4534
willy tarreau9fe663a2005-12-17 13:02:59 +01004535 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004536 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
4537 curproxy->id);
4538 close(fd);
4539 return -1;
4540 }
4541
willy tarreau0f7af912005-12-17 12:21:26 +01004542 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
4543 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
4544 (char *) &one, sizeof(one)) == -1)) {
4545 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
4546 curproxy->id);
4547 close(fd);
4548 return -1;
4549 }
4550
4551 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
4552 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
4553 curproxy->id);
4554 }
4555
4556 if (bind(fd,
4557 (struct sockaddr *)&curproxy->listen_addr,
4558 sizeof(curproxy->listen_addr)) == -1) {
4559 Alert("cannot bind socket for proxy %s. Aborting.\n",
4560 curproxy->id);
4561 close(fd);
4562 return -1;
4563 }
4564
4565 if (listen(fd, curproxy->maxconn) == -1) {
4566 Alert("cannot listen to socket for proxy %s. Aborting.\n",
4567 curproxy->id);
4568 close(fd);
4569 return -1;
4570 }
4571
4572 /* the function for the accept() event */
4573 fdtab[fd].read = &event_accept;
4574 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004575 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01004576 curproxy->state = PR_STRUN;
4577 fdtab[fd].state = FD_STLISTEN;
4578 FD_SET(fd, StaticReadEvent);
4579 fd_insert(fd);
4580 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01004581
willy tarreaua1598082005-12-17 13:08:06 +01004582 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004583
willy tarreau0f7af912005-12-17 12:21:26 +01004584 }
4585 return 0;
4586}
4587
4588
4589int main(int argc, char **argv) {
4590 init(argc, argv);
4591
willy tarreau9fe663a2005-12-17 13:02:59 +01004592 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01004593 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004594 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01004595 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01004596 }
4597
4598 signal(SIGQUIT, dump);
4599 signal(SIGUSR1, sig_soft_stop);
4600
4601 /* on very high loads, a sigpipe sometimes happen just between the
4602 * getsockopt() which tells "it's OK to write", and the following write :-(
4603 */
willy tarreau3242e862005-12-17 12:27:53 +01004604#ifndef MSG_NOSIGNAL
4605 signal(SIGPIPE, SIG_IGN);
4606#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004607
4608 if (start_proxies() < 0)
4609 exit(1);
4610
willy tarreau9fe663a2005-12-17 13:02:59 +01004611 /* open log files */
4612
4613 /* chroot if needed */
4614 if (global.chroot != NULL) {
4615 if (chroot(global.chroot) == -1) {
4616 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
4617 exit(1);
4618 }
4619 chdir("/");
4620 }
4621
4622 /* setgid / setuid */
4623 if (global.gid && setregid(global.gid, global.gid) == -1) {
4624 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
4625 exit(1);
4626 }
4627
4628 if (global.uid && setreuid(global.uid, global.uid) == -1) {
4629 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
4630 exit(1);
4631 }
4632
4633 if (global.mode & MODE_DAEMON) {
4634 int ret = 0;
4635 int proc;
4636
4637 /* the father launches the required number of processes */
4638 for (proc = 0; proc < global.nbproc; proc++) {
4639 ret = fork();
4640 if (ret < 0) {
4641 Alert("[%s.main()] Cannot fork.\n", argv[0]);
4642 exit(1); /* there has been an error */
4643 }
4644 else if (ret == 0) /* child breaks here */
4645 break;
4646 }
4647 if (proc == global.nbproc)
4648 exit(0); /* parent must leave */
4649
willy tarreaua1598082005-12-17 13:08:06 +01004650 pid = getpid(); /* update child's pid */
willy tarreau9fe663a2005-12-17 13:02:59 +01004651 setpgid(1, 0);
4652 }
4653
willy tarreau0f7af912005-12-17 12:21:26 +01004654 select_loop();
4655
4656 exit(0);
4657}
willy tarreaua1598082005-12-17 13:08:06 +01004658