blob: 9ab37b1c544ae3c9f4808b43c19b53d08b590ad0 [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 tarreau96d40372005-12-17 13:11:56 +010020 * 2002/05/10 : 1.1.10
21 * - if a cookie is used in insert+indirect mode, it's desirable that the
22 * the servers don't see it. It was not possible to remove it correctly
23 * with regexps, so now it's removed automatically.
willy tarreauc29948c2005-12-17 13:10:27 +010024 * 2002/04/19 : 1.1.9
25 * - don't use snprintf()'s return value as an end of message since it may
26 * be larger. This caused bus errors and segfaults in internal libc's
27 * getenv() during localtime() in send_log().
28 * - removed dead insecure send_syslog() function and all references to it.
29 * - fixed warnings on Solaris due to buggy implementation of isXXXX().
willy tarreaua1598082005-12-17 13:08:06 +010030 * 2002/04/18 : 1.1.8
31 * - option "dontlognull"
32 * - fixed "double space" bug in config parser
33 * - fixed an uninitialized server field in case of dispatch
34 * with no existing server which could cause a segfault during
35 * logging.
36 * - the pid logged was always the father's, which was wrong for daemons.
37 * - fixed wrong level "LOG_INFO" for message "proxy started".
38 * 2002/04/13 :
39 * - http logging is now complete :
40 * - ip:port, date, proxy, server
41 * - req_time, conn_time, hdr_time, tot_time
42 * - status, size, request
43 * - source address
willy tarreau9fe663a2005-12-17 13:02:59 +010044 * 2002/04/12 : 1.1.7
45 * - added option forwardfor
46 * - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel
47 * - added "log global" in "listen" section.
48 * 2002/04/09 :
49 * - added a new "global" section :
50 * - logs
51 * - debug, quiet, daemon modes
52 * - uid, gid, chroot, nbproc, maxconn
willy tarreaue39cd132005-12-17 13:00:18 +010053 * 2002/04/08 : 1.1.6
54 * - regex are now chained and not limited anymore.
55 * - unavailable server now returns HTTP/502.
56 * - increased per-line args limit to 40
57 * - added reqallow/reqdeny to block some request on matches
58 * - added HTTP 400/403 responses
59 * 2002/04/03 : 1.1.5
willy tarreau535ae7a2005-12-17 12:58:00 +010060 * - connection logging displayed incorrect source address.
61 * - added proxy start/stop and server up/down log events.
62 * - replaced log message short buffers with larger trash.
63 * - enlarged buffer to 8 kB and replace buffer to 4 kB.
willy tarreaue39cd132005-12-17 13:00:18 +010064 * 2002/03/25 : 1.1.4
willy tarreaue47c8d72005-12-17 12:55:52 +010065 * - made rise/fall/interval time configurable
willy tarreaue39cd132005-12-17 13:00:18 +010066 * 2002/03/22 : 1.1.3
willy tarreaub719f002005-12-17 12:55:07 +010067 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
68 * which could lead to loops.
willy tarreaue39cd132005-12-17 13:00:18 +010069 * 2002/03/21 : 1.1.2
willy tarreauef900ab2005-12-17 12:52:52 +010070 * - fixed a bug in buffer management where we could have a loop
71 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
72 * => implemented an adjustable buffer limit.
73 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
74 * and running tasks are skipped.
75 * - added some debug lines for accept events.
76 * - send warnings for servers up/down.
willy tarreaue39cd132005-12-17 13:00:18 +010077 * 2002/03/12 : 1.1.1
willy tarreauefae1842005-12-17 12:51:03 +010078 * - fixed a bug in total failure handling
79 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreaue39cd132005-12-17 13:00:18 +010080 * 2002/03/10 : 1.1.0
willy tarreau5cbea6f2005-12-17 12:48:26 +010081 * - fixed a few timeout bugs
82 * - rearranged the task scheduler subsystem to improve performance,
83 * add new tasks, and make it easier to later port to librt ;
84 * - allow multiple accept() for one select() wake up ;
85 * - implemented internal load balancing with basic health-check ;
86 * - cookie insertion and header add/replace/delete, with better strings
87 * support.
88 * 2002/03/08
89 * - reworked buffer handling to fix a few rewrite bugs, and
90 * improve overall performance.
91 * - implement the "purge" option to delete server cookies in direct mode.
92 * 2002/03/07
93 * - fixed some error cases where the maxfd was not decreased.
94 * 2002/02/26
95 * - now supports transparent proxying, at least on linux 2.4.
96 * 2002/02/12
97 * - soft stop works again (fixed select timeout computation).
98 * - it seems that TCP proxies sometimes cannot timeout.
99 * - added a "quiet" mode.
100 * - enforce file descriptor limitation on socket() and accept().
101 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +0100102 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +0100103 * 2001/12/16 : release of version 1.0.0.
104 * 2001/12/16 : added syslog capability for each accepted connection.
105 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
106 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
107 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
108 * with or without cookies (use keyword http for this).
109 * 2001/09/01 : added client/server header replacing with regexps.
110 * eg:
111 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
112 * srvexp ^Server:\ .* Server:\ Apache
113 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
114 * 2000/11/28 : major rewrite
115 * 2000/11/26 : first write
116 *
willy tarreau5cbea6f2005-12-17 12:48:26 +0100117 * TODO:
118 * - handle properly intermediate incomplete server headers. Done ?
119 * - log proxies start/stop
120 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +0100121 *
122 */
123
124#include <stdio.h>
125#include <stdlib.h>
126#include <unistd.h>
127#include <string.h>
128#include <ctype.h>
129#include <sys/time.h>
130#include <sys/types.h>
131#include <sys/socket.h>
132#include <netinet/tcp.h>
133#include <netinet/in.h>
134#include <arpa/inet.h>
135#include <netdb.h>
136#include <fcntl.h>
137#include <errno.h>
138#include <signal.h>
139#include <stdarg.h>
140#include <sys/resource.h>
141#include <time.h>
142#include <regex.h>
143#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +0100144#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100145#include <linux/netfilter_ipv4.h>
146#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100147
willy tarreauc29948c2005-12-17 13:10:27 +0100148#define HAPROXY_VERSION "1.1.9"
149#define HAPROXY_DATE "2002/04/19"
willy tarreau0f7af912005-12-17 12:21:26 +0100150
151/* this is for libc5 for example */
152#ifndef TCP_NODELAY
153#define TCP_NODELAY 1
154#endif
155
156#ifndef SHUT_RD
157#define SHUT_RD 0
158#endif
159
160#ifndef SHUT_WR
161#define SHUT_WR 1
162#endif
163
willy tarreau535ae7a2005-12-17 12:58:00 +0100164#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +0100165
166// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +0100167#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +0100168#define REQURI_LEN 1024
willy tarreau0f7af912005-12-17 12:21:26 +0100169
willy tarreau5cbea6f2005-12-17 12:48:26 +0100170// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100171#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100172
willy tarreaue39cd132005-12-17 13:00:18 +0100173// max # of added headers per request
174#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100175
176// max # of matches per regexp
177#define MAX_MATCH 10
178
willy tarreau5cbea6f2005-12-17 12:48:26 +0100179/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100180#define COOKIENAME_LEN 16
181#define SERVERID_LEN 16
182#define CONN_RETRIES 3
183
willy tarreau5cbea6f2005-12-17 12:48:26 +0100184#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100185#define DEF_CHKINTR 2000
186#define DEF_FALLTIME 3
187#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100188
willy tarreau9fe663a2005-12-17 13:02:59 +0100189/* default connections limit */
190#define DEFAULT_MAXCONN 2000
191
willy tarreau0f7af912005-12-17 12:21:26 +0100192/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
193#define INTBITS 5
194
195/* show stats this every millisecond, 0 to disable */
196#ifndef STATTIME
197#define STATTIME 2000
198#endif
199
willy tarreau5cbea6f2005-12-17 12:48:26 +0100200/* this reduces the number of calls to select() by choosing appropriate
201 * sheduler precision in milliseconds. It should be near the minimum
202 * time that is needed by select() to collect all events. All timeouts
203 * are rounded up by adding this value prior to pass it to select().
204 */
205#define SCHEDULER_RESOLUTION 9
206
willy tarreau0f7af912005-12-17 12:21:26 +0100207#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
208#define SETNOW(a) (*a=now)
209
willy tarreau9da061b2005-12-17 12:29:56 +0100210/****** string-specific macros and functions ******/
211/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
212#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
213
214/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
215#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
216
217
218#ifndef HAVE_STRLCPY
219/*
220 * copies at most <size-1> chars from <src> to <dst>. Last char is always
221 * set to 0, unless <size> is 0. The number of chars copied is returned
222 * (excluding the terminating zero).
223 * This code has been optimized for size and speed : on x86, it's 45 bytes
224 * long, uses only registers, and consumes only 4 cycles per char.
225 */
226int strlcpy(char *dst, const char *src, int size) {
227 char *orig = dst;
228 if (size) {
229 while (--size && (*dst = *src)) {
230 src++; dst++;
231 }
232 *dst = 0;
233 }
234 return dst - orig;
235}
236#endif
237
238
willy tarreau0f7af912005-12-17 12:21:26 +0100239#define MEM_OPTIM
240#ifdef MEM_OPTIM
241/*
242 * Returns a pointer to type <type> taken from the
243 * pool <pool_type> or dynamically allocated. In the
244 * first case, <pool_type> is updated to point to the
245 * next element in the list.
246 */
247#define pool_alloc(type) ({ \
248 void *p; \
249 if ((p = pool_##type) == NULL) \
250 p = malloc(sizeof_##type); \
251 else { \
252 pool_##type = *(void **)pool_##type; \
253 } \
254 p; \
255})
256
257/*
258 * Puts a memory area back to the corresponding pool.
259 * Items are chained directly through a pointer that
260 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100261 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100262 * that each memory area is at least as big as one
263 * pointer.
264 */
265#define pool_free(type, ptr) ({ \
266 *(void **)ptr = (void *)pool_##type; \
267 pool_##type = (void *)ptr; \
268})
269
270#else
271#define pool_alloc(type) (calloc(1,sizeof_##type));
272#define pool_free(type, ptr) (free(ptr));
273#endif /* MEM_OPTIM */
274
willy tarreau5cbea6f2005-12-17 12:48:26 +0100275#define sizeof_task sizeof(struct task)
276#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100277#define sizeof_buffer sizeof(struct buffer)
278#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100279#define sizeof_requri REQURI_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100280
willy tarreau5cbea6f2005-12-17 12:48:26 +0100281/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100282#define FD_STCLOSE 0
283#define FD_STLISTEN 1
284#define FD_STCONN 2
285#define FD_STREADY 3
286#define FD_STERROR 4
287
willy tarreau5cbea6f2005-12-17 12:48:26 +0100288/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100289#define TASK_IDLE 0
290#define TASK_RUNNING 1
291
willy tarreau5cbea6f2005-12-17 12:48:26 +0100292/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100293#define PR_STNEW 0
294#define PR_STIDLE 1
295#define PR_STRUN 2
296#define PR_STDISABLED 3
297
willy tarreau5cbea6f2005-12-17 12:48:26 +0100298/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100299#define PR_MODE_TCP 0
300#define PR_MODE_HTTP 1
301#define PR_MODE_HEALTH 2
302
willy tarreau5cbea6f2005-12-17 12:48:26 +0100303/* bits for proxy->options */
304#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
305#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
306#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
307#define PR_O_COOK_IND 8 /* keep only indirect cookies */
308#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
309#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
310#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
311#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100312#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
313#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100314#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
315#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau9fe663a2005-12-17 13:02:59 +0100316
willy tarreau5cbea6f2005-12-17 12:48:26 +0100317
willy tarreaue39cd132005-12-17 13:00:18 +0100318/* various session flags */
319#define SN_DIRECT 1 /* connection made on the server matching the client cookie */
320#define SN_CLDENY 2 /* a client header matches a deny regex */
321#define SN_CLALLOW 4 /* a client header matches an allow regex */
322#define SN_SVDENY 8 /* a server header matches a deny regex */
323#define SN_SVALLOW 16 /* a server header matches an allow regex */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100324
325/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100326#define CL_STHEADERS 0
327#define CL_STDATA 1
328#define CL_STSHUTR 2
329#define CL_STSHUTW 3
330#define CL_STCLOSE 4
331
willy tarreau5cbea6f2005-12-17 12:48:26 +0100332/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100333#define SV_STIDLE 0
334#define SV_STCONN 1
335#define SV_STHEADERS 2
336#define SV_STDATA 3
337#define SV_STSHUTR 4
338#define SV_STSHUTW 5
339#define SV_STCLOSE 6
340
341/* result of an I/O event */
342#define RES_SILENT 0 /* didn't happen */
343#define RES_DATA 1 /* data were sent or received */
344#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
345#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
346
willy tarreau9fe663a2005-12-17 13:02:59 +0100347/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100348#define MODE_DEBUG 1
349#define MODE_STATS 2
350#define MODE_LOG 4
351#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100352#define MODE_QUIET 16
353
354/* server flags */
355#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100356
willy tarreaue39cd132005-12-17 13:00:18 +0100357/* what to do when a header matches a regex */
358#define ACT_ALLOW 0 /* allow the request */
359#define ACT_REPLACE 1 /* replace the matching header */
360#define ACT_REMOVE 2 /* remove the matching header */
361#define ACT_DENY 3 /* deny the request */
362
willy tarreau9fe663a2005-12-17 13:02:59 +0100363/* configuration sections */
364#define CFG_NONE 0
365#define CFG_GLOBAL 1
366#define CFG_LISTEN 2
367
willy tarreaua1598082005-12-17 13:08:06 +0100368/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100369#define LW_DATE 1 /* date */
370#define LW_CLIP 2 /* CLient IP */
371#define LW_SVIP 4 /* SerVer IP */
372#define LW_SVID 8 /* server ID */
373#define LW_REQ 16 /* http REQuest */
374#define LW_RESP 32 /* http RESPonse */
375#define LW_PXIP 64 /* proxy IP */
376#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100377#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100378
willy tarreau0f7af912005-12-17 12:21:26 +0100379/*********************************************************************/
380
381#define LIST_HEAD(a) ((void *)(&(a)))
382
383/*********************************************************************/
384
385struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100386 struct hdr_exp *next;
387 regex_t *preg; /* expression to look for */
388 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
389 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100390};
391
392struct buffer {
393 unsigned int l; /* data length */
394 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100395 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100396 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100397 char data[BUFSIZE];
398};
399
400struct server {
401 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100402 int state; /* server state (SRV_*) */
403 int cklen; /* the len of the cookie, to speed up checks */
404 char *cookie; /* the id set in the cookie */
405 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100406 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100407 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100408 int rise, fall; /* time in iterations */
409 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100410 int result; /* 0 = connect OK, -1 = connect KO */
411 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100412 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100413};
414
willy tarreau5cbea6f2005-12-17 12:48:26 +0100415/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100416struct task {
417 struct task *next, *prev; /* chaining ... */
418 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100419 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100420 int state; /* task state : IDLE or RUNNING */
421 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100422 int (*process)(struct task *t); /* the function which processes the task */
423 void *context; /* the task's context */
424};
425
426/* WARNING: if new fields are added, they must be initialized in event_accept() */
427struct session {
428 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100429 /* application specific below */
430 struct timeval crexpire; /* expiration date for a client read */
431 struct timeval cwexpire; /* expiration date for a client write */
432 struct timeval srexpire; /* expiration date for a server read */
433 struct timeval swexpire; /* expiration date for a server write */
434 struct timeval cnexpire; /* expiration date for a connect */
435 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
436 struct proxy *proxy; /* the proxy this socket belongs to */
437 int cli_fd; /* the client side fd */
438 int srv_fd; /* the server side fd */
439 int cli_state; /* state of the client side */
440 int srv_state; /* state of the server side */
441 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100442 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100443 struct buffer *req; /* request buffer */
444 struct buffer *rep; /* response buffer */
445 struct sockaddr_in cli_addr; /* the client address */
446 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100447 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100448 struct {
449 int logwait; /* log fields waiting to be collected : LW_* */
450 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
451 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
452 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
453 long t_data; /* delay before the first data byte from the server ... */
454 unsigned long t_close; /* total session duration */
455 char *uri; /* first line if log needed, NULL otherwise */
456 int status; /* HTTP status from the server, negative if from proxy */
457 long long bytes; /* number of bytes transferred from the server */
458 } logs;
willy tarreau0f7af912005-12-17 12:21:26 +0100459};
460
461struct proxy {
462 int listen_fd; /* the listen socket */
463 int state; /* proxy state */
464 struct sockaddr_in listen_addr; /* the address we listen to */
465 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100466 struct server *srv, *cursrv; /* known servers, current server */
467 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100468 char *cookie_name; /* name of the cookie to look for */
469 int clitimeout; /* client I/O timeout (in milliseconds) */
470 int srvtimeout; /* server I/O timeout (in milliseconds) */
471 int contimeout; /* connect timeout (in milliseconds) */
472 char *id; /* proxy id */
473 int nbconn; /* # of active sessions */
474 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100475 int conn_retries; /* maximum number of connect retries */
476 int options; /* PR_O_REDISP, PR_O_TRANSP */
477 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100478 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100479 struct proxy *next;
480 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
481 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau9fe663a2005-12-17 13:02:59 +0100482 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100483 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100484 int nb_reqadd, nb_rspadd;
485 struct hdr_exp *req_exp; /* regular expressions for request headers */
486 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
487 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100488 int grace; /* grace time after stop request */
489};
490
491/* info about one given fd */
492struct fdtab {
493 int (*read)(int fd); /* read function */
494 int (*write)(int fd); /* write function */
495 struct task *owner; /* the session (or proxy) associated with this fd */
496 int state; /* the state of this fd */
497};
498
499/*********************************************************************/
500
willy tarreau0f7af912005-12-17 12:21:26 +0100501int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100502char *cfg_cfgfile = NULL; /* configuration file */
503char *progname = NULL; /* program name */
504int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100505
506/* global options */
507static struct {
508 int uid;
509 int gid;
510 int nbproc;
511 int maxconn;
512 int maxsock; /* max # of sockets */
513 int mode;
514 char *chroot;
515 int logfac1, logfac2;
516 struct sockaddr_in logsrv1, logsrv2;
517} global = {
518 logfac1 : -1,
519 logfac2 : -1,
520 /* others NULL OK */
521};
522
willy tarreau0f7af912005-12-17 12:21:26 +0100523/*********************************************************************/
524
525fd_set *ReadEvent,
526 *WriteEvent,
527 *StaticReadEvent,
528 *StaticWriteEvent;
529
530void **pool_session = NULL,
531 **pool_buffer = NULL,
532 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100533 **pool_requri = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100534 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100535
536struct proxy *proxy = NULL; /* list of all existing proxies */
537struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100538struct task *rq = NULL; /* global run queue */
539struct task wait_queue = { /* global wait queue */
540 prev:LIST_HEAD(wait_queue),
541 next:LIST_HEAD(wait_queue)
542};
willy tarreau0f7af912005-12-17 12:21:26 +0100543
willy tarreau0f7af912005-12-17 12:21:26 +0100544static int totalconn = 0; /* total # of terminated sessions */
545static int actconn = 0; /* # of active sessions */
546static int maxfd = 0; /* # of the highest fd + 1 */
547static int listeners = 0; /* # of listeners */
548static int stopping = 0; /* non zero means stopping in progress */
549static struct timeval now = {0,0}; /* the current date at any moment */
550
551static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
552static char trash[BUFSIZE];
553
554/*
555 * Syslog facilities and levels
556 */
557
558#define MAX_SYSLOG_LEN 1024
559#define NB_LOG_FACILITIES 24
560const char *log_facilities[NB_LOG_FACILITIES] = {
561 "kern", "user", "mail", "daemon",
562 "auth", "syslog", "lpr", "news",
563 "uucp", "cron", "auth2", "ftp",
564 "ntp", "audit", "alert", "cron2",
565 "local0", "local1", "local2", "local3",
566 "local4", "local5", "local6", "local7"
567};
568
569
570#define NB_LOG_LEVELS 8
571const char *log_levels[NB_LOG_LEVELS] = {
572 "emerg", "alert", "crit", "err",
573 "warning", "notice", "info", "debug"
574};
575
576#define SYSLOG_PORT 514
577
578const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
579 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
580#define MAX_HOSTNAME_LEN 32
581static char hostname[MAX_HOSTNAME_LEN] = "";
582
willy tarreaua1598082005-12-17 13:08:06 +0100583const char *HTTP_400 =
584 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100585 "Cache-Control: no-cache\r\n"
586 "Connection: close\r\n"
587 "\r\n"
willy tarreaua1598082005-12-17 13:08:06 +0100588 "400 Bad request : Your browser sent an invalid request.\r\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100589
willy tarreaua1598082005-12-17 13:08:06 +0100590const char *HTTP_403 =
591 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100592 "Cache-Control: no-cache\r\n"
593 "Connection: close\r\n"
594 "\r\n"
willy tarreaua1598082005-12-17 13:08:06 +0100595 "403 Forbidden : Request forbidden by administrative rules.\r\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100596
597const char *HTTP_502 =
598 "HTTP/1.0 502 Proxy Error\r\n"
599 "Cache-Control: no-cache\r\n"
600 "Connection: close\r\n"
601 "\r\n"
602 "502 Proxy Error : No server is available to handle this request.\r\n";
603
willy tarreau0f7af912005-12-17 12:21:26 +0100604/*********************************************************************/
605/* statistics ******************************************************/
606/*********************************************************************/
607
608static int stats_tsk_lsrch, stats_tsk_rsrch,
609 stats_tsk_good, stats_tsk_right, stats_tsk_left,
610 stats_tsk_new, stats_tsk_nsrch;
611
612
613/*********************************************************************/
614/* function prototypes *********************************************/
615/*********************************************************************/
616
617int event_accept(int fd);
618int event_cli_read(int fd);
619int event_cli_write(int fd);
620int event_srv_read(int fd);
621int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100622int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100623
624/*********************************************************************/
625/* general purpose functions ***************************************/
626/*********************************************************************/
627
628void display_version() {
629 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100630 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100631}
632
633/*
634 * This function prints the command line usage and exits
635 */
636void usage(char *name) {
637 display_version();
638 fprintf(stderr,
639 "Usage : %s -f <cfgfile> [ -vd"
640#if STATTIME > 0
641 "sl"
642#endif
643 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
644 " -v displays version\n"
645 " -d enters debug mode\n"
646#if STATTIME > 0
647 " -s enables statistics output\n"
648 " -l enables long statistics format\n"
649#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100650 " -D goes daemon ; implies -q\n"
651 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100652 " -n sets the maximum total # of connections (%d)\n"
653 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100654 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100655 exit(1);
656}
657
658
659/*
660 * Displays the message on stderr with the date and pid.
661 */
662void Alert(char *fmt, ...) {
663 va_list argp;
664 struct timeval tv;
665 struct tm *tm;
666
willy tarreau9fe663a2005-12-17 13:02:59 +0100667 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100668 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100669
willy tarreau5cbea6f2005-12-17 12:48:26 +0100670 gettimeofday(&tv, NULL);
671 tm=localtime(&tv.tv_sec);
672 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100673 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100674 vfprintf(stderr, fmt, argp);
675 fflush(stderr);
676 va_end(argp);
677 }
willy tarreau0f7af912005-12-17 12:21:26 +0100678}
679
680
681/*
682 * Displays the message on stderr with the date and pid.
683 */
684void Warning(char *fmt, ...) {
685 va_list argp;
686 struct timeval tv;
687 struct tm *tm;
688
willy tarreau9fe663a2005-12-17 13:02:59 +0100689 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100690 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100691
willy tarreau5cbea6f2005-12-17 12:48:26 +0100692 gettimeofday(&tv, NULL);
693 tm=localtime(&tv.tv_sec);
694 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100695 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100696 vfprintf(stderr, fmt, argp);
697 fflush(stderr);
698 va_end(argp);
699 }
700}
701
702/*
703 * Displays the message on <out> only if quiet mode is not set.
704 */
705void qfprintf(FILE *out, char *fmt, ...) {
706 va_list argp;
707
willy tarreau9fe663a2005-12-17 13:02:59 +0100708 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100709 va_start(argp, fmt);
710 vfprintf(out, fmt, argp);
711 fflush(out);
712 va_end(argp);
713 }
willy tarreau0f7af912005-12-17 12:21:26 +0100714}
715
716
717/*
718 * converts <str> to a struct sockaddr_in* which is locally allocated.
719 * The format is "addr:port", where "addr" can be empty or "*" to indicate
720 * INADDR_ANY.
721 */
722struct sockaddr_in *str2sa(char *str) {
723 static struct sockaddr_in sa;
724 char *c;
725 int port;
726
willy tarreaua1598082005-12-17 13:08:06 +0100727 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100728 str=strdup(str);
729
730 if ((c=strrchr(str,':')) != NULL) {
731 *c++=0;
732 port=atol(c);
733 }
734 else
735 port=0;
736
737 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
738 sa.sin_addr.s_addr = INADDR_ANY;
739 }
740 else if (
741#ifndef SOLARIS
742 !inet_aton(str, &sa.sin_addr)
743#else
744 !inet_pton(AF_INET, str, &sa.sin_addr)
745#endif
746 ) {
747 struct hostent *he;
748
749 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100750 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100751 }
752 else
753 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
754 }
755 sa.sin_port=htons(port);
756 sa.sin_family=AF_INET;
757
758 free(str);
759 return &sa;
760}
761
willy tarreau9fe663a2005-12-17 13:02:59 +0100762
763/*
764 * This function sends a syslog message to both log servers of a proxy,
765 * or to global log servers if the proxy is NULL.
766 * It also tries not to waste too much time computing the message header.
767 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100768 */
769void send_log(struct proxy *p, int level, char *message, ...) {
770 static int logfd = -1; /* syslog UDP socket */
771 static long tvsec = -1; /* to force the string to be initialized */
772 struct timeval tv;
773 va_list argp;
774 static char logmsg[MAX_SYSLOG_LEN];
775 static char *dataptr = NULL;
776 int fac_level;
777 int hdr_len, data_len;
778 struct sockaddr_in *sa[2];
779 int facilities[2];
780 int nbloggers = 0;
781 char *log_ptr;
782
783 if (logfd < 0) {
784 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
785 return;
786 }
787
788 if (level < 0 || progname == NULL || message == NULL)
789 return;
790
791 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100792 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100793 /* this string is rebuild only once a second */
794 struct tm *tm = localtime(&tv.tv_sec);
795 tvsec = tv.tv_sec;
796
willy tarreauc29948c2005-12-17 13:10:27 +0100797 hdr_len = snprintf(logmsg, sizeof(logmsg),
798 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
799 monthname[tm->tm_mon],
800 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
801 progname, pid);
802 /* WARNING: depending upon implementations, snprintf may return
803 * either -1 or the number of bytes that would be needed to store
804 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100805 */
willy tarreauc29948c2005-12-17 13:10:27 +0100806 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
807 hdr_len = sizeof(logmsg);
808
809 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100810 }
811
812 va_start(argp, message);
813 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100814 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
815 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100816 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100817 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100818
819 if (p == NULL) {
820 if (global.logfac1 >= 0) {
821 sa[nbloggers] = &global.logsrv1;
822 facilities[nbloggers] = global.logfac1;
823 nbloggers++;
824 }
825 if (global.logfac2 >= 0) {
826 sa[nbloggers] = &global.logsrv2;
827 facilities[nbloggers] = global.logfac2;
828 nbloggers++;
829 }
830 } else {
831 if (p->logfac1 >= 0) {
832 sa[nbloggers] = &p->logsrv1;
833 facilities[nbloggers] = p->logfac1;
834 nbloggers++;
835 }
836 if (p->logfac2 >= 0) {
837 sa[nbloggers] = &p->logsrv2;
838 facilities[nbloggers] = p->logfac2;
839 nbloggers++;
840 }
841 }
842
843 while (nbloggers-- > 0) {
willy tarreauc29948c2005-12-17 13:10:27 +0100844 /* For each target, we may have a different facility.
845 * We can also have a different log level for each message.
846 * This induces variations in the message header length.
847 * Since we don't want to recompute it each time, nor copy it every
848 * time, we only change the facility in the pre-computed header,
849 * and we change the pointer to the header accordingly.
850 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100851 fac_level = (facilities[nbloggers] << 3) + level;
852 log_ptr = logmsg + 3; /* last digit of the log level */
853 do {
854 *log_ptr = '0' + fac_level % 10;
855 fac_level /= 10;
856 log_ptr--;
857 } while (fac_level && log_ptr > logmsg);
858 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100859
willy tarreauc29948c2005-12-17 13:10:27 +0100860 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100861
862#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100863 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100864 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
865#else
willy tarreauc29948c2005-12-17 13:10:27 +0100866 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100867 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
868#endif
869 }
willy tarreau0f7af912005-12-17 12:21:26 +0100870}
871
872
873/* sets <tv> to the current time */
874static inline struct timeval *tv_now(struct timeval *tv) {
875 if (tv)
876 gettimeofday(tv, NULL);
877 return tv;
878}
879
880/*
881 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
882 */
883static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
884 if (!tv || !from)
885 return NULL;
886 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
887 tv->tv_sec = from->tv_sec + (ms/1000);
888 while (tv->tv_usec >= 1000000) {
889 tv->tv_usec -= 1000000;
890 tv->tv_sec++;
891 }
892 return tv;
893}
894
895/*
896 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
897 */
898static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
899 if (tv1->tv_sec > tv2->tv_sec)
900 return 1;
901 else if (tv1->tv_sec < tv2->tv_sec)
902 return -1;
903 else if (tv1->tv_usec > tv2->tv_usec)
904 return 1;
905 else if (tv1->tv_usec < tv2->tv_usec)
906 return -1;
907 else
908 return 0;
909}
910
911/*
912 * returns the absolute difference, in ms, between tv1 and tv2
913 */
914unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
915 int cmp;
916 unsigned long ret;
917
918
willy tarreauef900ab2005-12-17 12:52:52 +0100919 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100920 if (!cmp)
921 return 0; /* same dates, null diff */
922 else if (cmp<0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100923 struct timeval *tmp = tv1;
924 tv1 = tv2;
925 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100926 }
willy tarreauef900ab2005-12-17 12:52:52 +0100927 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100928 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100929 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100930 else
willy tarreauef900ab2005-12-17 12:52:52 +0100931 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100932 return (unsigned long) ret;
933}
934
935/*
936 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
937 */
938static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100939 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100940 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100941 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100942 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100943 return -1;
944 else
945 return 0;
946 }
947 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100948 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100949 return 1;
950 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100951 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100952 return -1;
953 else
954 return 0;
955}
956
957/*
958 * returns the remaining time between tv1=now and event=tv2
959 * if tv2 is passed, 0 is returned.
960 */
961static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
962 unsigned long ret;
963
willy tarreau0f7af912005-12-17 12:21:26 +0100964 if (tv_cmp_ms(tv1, tv2) >= 0)
965 return 0; /* event elapsed */
966
willy tarreauef900ab2005-12-17 12:52:52 +0100967 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100968 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100969 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100970 else
willy tarreauef900ab2005-12-17 12:52:52 +0100971 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100972 return (unsigned long) ret;
973}
974
975
976/*
977 * zeroes a struct timeval
978 */
979
980static inline struct timeval *tv_eternity(struct timeval *tv) {
981 tv->tv_sec = tv->tv_usec = 0;
982 return tv;
983}
984
985/*
986 * returns 1 if tv is null, else 0
987 */
988static inline int tv_iseternity(struct timeval *tv) {
989 if (tv->tv_sec == 0 && tv->tv_usec == 0)
990 return 1;
991 else
992 return 0;
993}
994
995/*
996 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
997 * considering that 0 is the eternity.
998 */
999static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1000 if (tv_iseternity(tv1))
1001 if (tv_iseternity(tv2))
1002 return 0; /* same */
1003 else
1004 return 1; /* tv1 later than tv2 */
1005 else if (tv_iseternity(tv2))
1006 return -1; /* tv2 later than tv1 */
1007
1008 if (tv1->tv_sec > tv2->tv_sec)
1009 return 1;
1010 else if (tv1->tv_sec < tv2->tv_sec)
1011 return -1;
1012 else if (tv1->tv_usec > tv2->tv_usec)
1013 return 1;
1014 else if (tv1->tv_usec < tv2->tv_usec)
1015 return -1;
1016 else
1017 return 0;
1018}
1019
1020/*
1021 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1022 * considering that 0 is the eternity.
1023 */
1024static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1025 if (tv_iseternity(tv1))
1026 if (tv_iseternity(tv2))
1027 return 0; /* same */
1028 else
1029 return 1; /* tv1 later than tv2 */
1030 else if (tv_iseternity(tv2))
1031 return -1; /* tv2 later than tv1 */
1032
willy tarreauefae1842005-12-17 12:51:03 +01001033 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001034 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001035 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001036 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001037 return -1;
1038 else
1039 return 0;
1040 }
1041 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001042 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001043 return 1;
1044 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001045 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001046 return -1;
1047 else
1048 return 0;
1049}
1050
1051/*
1052 * returns the first event between tv1 and tv2 into tvmin.
1053 * a zero tv is ignored. tvmin is returned.
1054 */
1055static inline struct timeval *tv_min(struct timeval *tvmin,
1056 struct timeval *tv1, struct timeval *tv2) {
1057
1058 if (tv_cmp2(tv1, tv2) <= 0)
1059 *tvmin = *tv1;
1060 else
1061 *tvmin = *tv2;
1062
1063 return tvmin;
1064}
1065
1066
1067
1068/***********************************************************/
1069/* fd management ***************************************/
1070/***********************************************************/
1071
1072
1073
willy tarreau5cbea6f2005-12-17 12:48:26 +01001074/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1075 * The file descriptor is also closed.
1076 */
willy tarreau0f7af912005-12-17 12:21:26 +01001077static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001078 FD_CLR(fd, StaticReadEvent);
1079 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001080 close(fd);
1081 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001082
1083 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1084 maxfd--;
1085}
1086
1087/* recomputes the maxfd limit from the fd */
1088static inline void fd_insert(int fd) {
1089 if (fd+1 > maxfd)
1090 maxfd = fd+1;
1091}
1092
1093/*************************************************************/
1094/* task management ***************************************/
1095/*************************************************************/
1096
willy tarreau5cbea6f2005-12-17 12:48:26 +01001097/* puts the task <t> in run queue <q>, and returns <t> */
1098static inline struct task *task_wakeup(struct task **q, struct task *t) {
1099 if (t->state == TASK_RUNNING)
1100 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001101 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001102 t->rqnext = *q;
1103 t->state = TASK_RUNNING;
1104 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001105 }
1106}
1107
willy tarreau5cbea6f2005-12-17 12:48:26 +01001108/* removes the task <t> from the queue <q>
1109 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001110 * set the run queue to point to the next one, and return it
1111 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001112static inline struct task *task_sleep(struct task **q, struct task *t) {
1113 if (t->state == TASK_RUNNING) {
1114 *q = t->rqnext;
1115 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001116 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001117 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001118}
1119
1120/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001121 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001122 * from the run queue. A pointer to the task itself is returned.
1123 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001124static inline struct task *task_delete(struct task *t) {
1125 t->prev->next = t->next;
1126 t->next->prev = t->prev;
1127 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001128}
1129
1130/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001131 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001132 */
1133static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001134 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001135}
1136
willy tarreau5cbea6f2005-12-17 12:48:26 +01001137/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001138 * may be only moved or left where it was, depending on its timing requirements.
1139 * <task> is returned.
1140 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001141struct task *task_queue(struct task *task) {
1142 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001143 struct task *start_from;
1144
1145 /* first, test if the task was already in a list */
1146 if (task->prev == NULL) {
1147 // start_from = list;
1148 start_from = list->prev;
1149 stats_tsk_new++;
1150
1151 /* insert the unlinked <task> into the list, searching back from the last entry */
1152 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1153 start_from = start_from->prev;
1154 stats_tsk_nsrch++;
1155 }
1156
1157 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1158 // start_from = start_from->next;
1159 // stats_tsk_nsrch++;
1160 // }
1161 }
1162 else if (task->prev == list ||
1163 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1164 start_from = task->next;
1165 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
1166 stats_tsk_good++;
1167 return task; /* it's already in the right place */
1168 }
1169
1170 stats_tsk_right++;
1171 /* insert the unlinked <task> into the list, searching after position <start_from> */
1172 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1173 start_from = start_from->next;
1174 stats_tsk_rsrch++;
1175 }
1176 /* we need to unlink it now */
1177 task_delete(task);
1178 }
1179 else { /* walk left. */
1180 stats_tsk_left++;
1181#ifdef LEFT_TO_TOP /* not very good */
1182 start_from = list;
1183 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1184 start_from = start_from->next;
1185 stats_tsk_lsrch++;
1186 }
1187#else
1188 start_from = task->prev->prev; /* valid because of the previous test above */
1189 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1190 start_from = start_from->prev;
1191 stats_tsk_lsrch++;
1192 }
1193#endif
1194 /* we need to unlink it now */
1195 task_delete(task);
1196 }
1197 task->prev = start_from;
1198 task->next = start_from->next;
1199 task->next->prev = task;
1200 start_from->next = task;
1201 return task;
1202}
1203
1204
1205/*********************************************************************/
1206/* more specific functions ***************************************/
1207/*********************************************************************/
1208
1209/* some prototypes */
1210static int maintain_proxies(void);
1211
willy tarreau5cbea6f2005-12-17 12:48:26 +01001212/* this either returns the sockname or the original destination address. Code
1213 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1214 */
1215static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001216#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001217 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1218#else
willy tarreaua1598082005-12-17 13:08:06 +01001219#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001220 return getsockname(fd, (struct sockaddr *)sa, salen);
1221#else
1222 return -1;
1223#endif
1224#endif
1225}
1226
1227/*
1228 * frees the context associated to a session. It must have been removed first.
1229 */
1230static inline void session_free(struct session *s) {
1231 if (s->req)
1232 pool_free(buffer, s->req);
1233 if (s->rep)
1234 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001235 if (s->logs.uri)
1236 pool_free(requri, s->logs.uri);
willy tarreau9fe663a2005-12-17 13:02:59 +01001237
willy tarreau5cbea6f2005-12-17 12:48:26 +01001238 pool_free(session, s);
1239}
1240
willy tarreau0f7af912005-12-17 12:21:26 +01001241
1242/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001243 * This function initiates a connection to the current server (s->srv) if (s->direct)
1244 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001245 * it's OK, -1 if it's impossible.
1246 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001247int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001248 int one = 1;
1249 int fd;
1250
1251 // fprintf(stderr,"connect_server : s=%p\n",s);
1252
willy tarreaue39cd132005-12-17 13:00:18 +01001253 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001254 s->srv_addr = s->srv->addr;
1255 }
1256 else if (s->proxy->options & PR_O_BALANCE) {
1257 if (s->proxy->options & PR_O_BALANCE_RR) {
1258 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001259 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001260 if (s->proxy->cursrv == NULL)
1261 s->proxy->cursrv = s->proxy->srv;
1262 if (s->proxy->cursrv->state & SRV_RUNNING)
1263 break;
1264 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001265 retry--;
1266 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001267
1268 if (retry == 0) /* no server left */
1269 return -1;
1270
1271 s->srv = s->proxy->cursrv;
1272 s->srv_addr = s->srv->addr;
1273 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001274 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001275 else /* unknown balancing algorithm */
1276 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001277 }
willy tarreaua1598082005-12-17 13:08:06 +01001278 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001279 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001280 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001281 }
1282 else if (s->proxy->options & PR_O_TRANSP) {
1283 /* in transparent mode, use the original dest addr if no dispatch specified */
1284 int salen = sizeof(struct sockaddr_in);
1285 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1286 qfprintf(stderr, "Cannot get original server address.\n");
1287 return -1;
1288 }
1289 }
willy tarreau0f7af912005-12-17 12:21:26 +01001290
1291 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001292 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001293 return -1;
1294 }
1295
willy tarreau9fe663a2005-12-17 13:02:59 +01001296 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001297 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1298 close(fd);
1299 return -1;
1300 }
1301
willy tarreau0f7af912005-12-17 12:21:26 +01001302 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1303 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001304 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001305 close(fd);
1306 return -1;
1307 }
1308
willy tarreaua1598082005-12-17 13:08:06 +01001309 /* allow specific binding */
1310 if (s->proxy->options & PR_O_BIND_SRC &&
1311 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1312 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1313 close(fd);
1314 return -1;
1315 }
1316
willy tarreau0f7af912005-12-17 12:21:26 +01001317 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1318 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001319 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001320 close(fd);
1321 return -1;
1322 }
1323 else if (errno != EALREADY && errno != EISCONN) {
1324 close(fd);
1325 return -1;
1326 }
1327 }
1328
willy tarreau5cbea6f2005-12-17 12:48:26 +01001329 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001330 fdtab[fd].read = &event_srv_read;
1331 fdtab[fd].write = &event_srv_write;
1332 fdtab[fd].state = FD_STCONN; /* connection in progress */
1333
1334 FD_SET(fd, StaticWriteEvent); /* for connect status */
1335
1336 fd_insert(fd);
1337
1338 if (s->proxy->contimeout)
1339 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1340 else
1341 tv_eternity(&s->cnexpire);
1342 return 0;
1343}
1344
1345/*
1346 * this function is called on a read event from a client socket.
1347 * It returns 0.
1348 */
1349int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001350 struct task *t = fdtab[fd].owner;
1351 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001352 struct buffer *b = s->req;
1353 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001354
1355 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1356
willy tarreau0f7af912005-12-17 12:21:26 +01001357 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001358 while (1) {
1359 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1360 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001361 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001362 }
1363 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001364 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001365 }
1366 else {
1367 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001368 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1369 * since it means that the rewrite protection has been removed. This
1370 * implies that the if statement can be removed.
1371 */
1372 if (max > b->rlim - b->data)
1373 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001374 }
1375
1376 if (max == 0) { /* not anymore room to store data */
1377 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001378 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001379 }
1380
willy tarreau3242e862005-12-17 12:27:53 +01001381#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001382 {
1383 int skerr, lskerr;
1384
1385 lskerr = sizeof(skerr);
1386 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1387 if (skerr)
1388 ret = -1;
1389 else
1390 ret = recv(fd, b->r, max, 0);
1391 }
willy tarreau3242e862005-12-17 12:27:53 +01001392#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001393 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001394#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001395 if (ret > 0) {
1396 b->r += ret;
1397 b->l += ret;
1398 s->res_cr = RES_DATA;
1399
1400 if (b->r == b->data + BUFSIZE) {
1401 b->r = b->data; /* wrap around the buffer */
1402 }
willy tarreaua1598082005-12-17 13:08:06 +01001403
1404 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001405 /* we hope to read more data or to get a close on next round */
1406 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001407 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001408 else if (ret == 0) {
1409 s->res_cr = RES_NULL;
1410 break;
1411 }
1412 else if (errno == EAGAIN) {/* ignore EAGAIN */
1413 break;
1414 }
1415 else {
1416 s->res_cr = RES_ERROR;
1417 fdtab[fd].state = FD_STERROR;
1418 break;
1419 }
1420 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001421 }
1422 else {
1423 s->res_cr = RES_ERROR;
1424 fdtab[fd].state = FD_STERROR;
1425 }
1426
willy tarreau5cbea6f2005-12-17 12:48:26 +01001427 if (s->res_cr != RES_SILENT) {
1428 if (s->proxy->clitimeout)
1429 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1430 else
1431 tv_eternity(&s->crexpire);
1432
1433 task_wakeup(&rq, t);
1434 }
willy tarreau0f7af912005-12-17 12:21:26 +01001435
willy tarreau0f7af912005-12-17 12:21:26 +01001436 return 0;
1437}
1438
1439
1440/*
1441 * this function is called on a read event from a server socket.
1442 * It returns 0.
1443 */
1444int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001445 struct task *t = fdtab[fd].owner;
1446 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001447 struct buffer *b = s->rep;
1448 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001449
1450 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1451
willy tarreau0f7af912005-12-17 12:21:26 +01001452 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001453 while (1) {
1454 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1455 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001456 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001457 }
1458 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001459 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001460 }
1461 else {
1462 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001463 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1464 * since it means that the rewrite protection has been removed. This
1465 * implies that the if statement can be removed.
1466 */
1467 if (max > b->rlim - b->data)
1468 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001469 }
1470
1471 if (max == 0) { /* not anymore room to store data */
1472 FD_CLR(fd, StaticReadEvent);
1473 break;
1474 }
1475
willy tarreau3242e862005-12-17 12:27:53 +01001476#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001477 {
1478 int skerr, lskerr;
1479
1480 lskerr = sizeof(skerr);
1481 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1482 if (skerr)
1483 ret = -1;
1484 else
1485 ret = recv(fd, b->r, max, 0);
1486 }
willy tarreau3242e862005-12-17 12:27:53 +01001487#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001488 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001489#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001490 if (ret > 0) {
1491 b->r += ret;
1492 b->l += ret;
1493 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001494
willy tarreau5cbea6f2005-12-17 12:48:26 +01001495 if (b->r == b->data + BUFSIZE) {
1496 b->r = b->data; /* wrap around the buffer */
1497 }
willy tarreaua1598082005-12-17 13:08:06 +01001498
1499 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001500 /* we hope to read more data or to get a close on next round */
1501 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001502 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001503 else if (ret == 0) {
1504 s->res_sr = RES_NULL;
1505 break;
1506 }
1507 else if (errno == EAGAIN) {/* ignore EAGAIN */
1508 break;
1509 }
1510 else {
1511 s->res_sr = RES_ERROR;
1512 fdtab[fd].state = FD_STERROR;
1513 break;
1514 }
1515 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001516 }
1517 else {
1518 s->res_sr = RES_ERROR;
1519 fdtab[fd].state = FD_STERROR;
1520 }
1521
willy tarreau5cbea6f2005-12-17 12:48:26 +01001522 if (s->res_sr != RES_SILENT) {
1523 if (s->proxy->srvtimeout)
1524 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1525 else
1526 tv_eternity(&s->srexpire);
1527
1528 task_wakeup(&rq, t);
1529 }
willy tarreau0f7af912005-12-17 12:21:26 +01001530
willy tarreau0f7af912005-12-17 12:21:26 +01001531 return 0;
1532}
1533
1534/*
1535 * this function is called on a write event from a client socket.
1536 * It returns 0.
1537 */
1538int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001539 struct task *t = fdtab[fd].owner;
1540 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001541 struct buffer *b = s->rep;
1542 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001543
1544 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1545
1546 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001547 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001548 // max = BUFSIZE; BUG !!!!
1549 max = 0;
1550 }
1551 else if (b->r > b->w) {
1552 max = b->r - b->w;
1553 }
1554 else
1555 max = b->data + BUFSIZE - b->w;
1556
willy tarreau0f7af912005-12-17 12:21:26 +01001557 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001558#ifndef MSG_NOSIGNAL
1559 int skerr, lskerr;
1560#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001561
1562 if (max == 0) {
1563 s->res_cw = RES_NULL;
1564 task_wakeup(&rq, t);
1565 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001566 }
1567
willy tarreau3242e862005-12-17 12:27:53 +01001568#ifndef MSG_NOSIGNAL
1569 lskerr=sizeof(skerr);
1570 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1571 if (skerr)
1572 ret = -1;
1573 else
1574 ret = send(fd, b->w, max, MSG_DONTWAIT);
1575#else
willy tarreau0f7af912005-12-17 12:21:26 +01001576 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001577#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001578
1579 if (ret > 0) {
1580 b->l -= ret;
1581 b->w += ret;
1582
1583 s->res_cw = RES_DATA;
1584
1585 if (b->w == b->data + BUFSIZE) {
1586 b->w = b->data; /* wrap around the buffer */
1587 }
1588 }
1589 else if (ret == 0) {
1590 /* nothing written, just make as if we were never called */
1591// s->res_cw = RES_NULL;
1592 return 0;
1593 }
1594 else if (errno == EAGAIN) /* ignore EAGAIN */
1595 return 0;
1596 else {
1597 s->res_cw = RES_ERROR;
1598 fdtab[fd].state = FD_STERROR;
1599 }
1600 }
1601 else {
1602 s->res_cw = RES_ERROR;
1603 fdtab[fd].state = FD_STERROR;
1604 }
1605
1606 if (s->proxy->clitimeout)
1607 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1608 else
1609 tv_eternity(&s->cwexpire);
1610
willy tarreau5cbea6f2005-12-17 12:48:26 +01001611 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001612 return 0;
1613}
1614
1615
1616/*
1617 * this function is called on a write event from a server socket.
1618 * It returns 0.
1619 */
1620int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001621 struct task *t = fdtab[fd].owner;
1622 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001623 struct buffer *b = s->req;
1624 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001625
1626 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1627
1628 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001629 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001630 // max = BUFSIZE; BUG !!!!
1631 max = 0;
1632 }
1633 else if (b->r > b->w) {
1634 max = b->r - b->w;
1635 }
1636 else
1637 max = b->data + BUFSIZE - b->w;
1638
willy tarreau0f7af912005-12-17 12:21:26 +01001639 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001640#ifndef MSG_NOSIGNAL
1641 int skerr, lskerr;
1642#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001643 if (max == 0) {
1644 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001645 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001646 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001647 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001648 return 0;
1649 }
1650
willy tarreauef900ab2005-12-17 12:52:52 +01001651
willy tarreau3242e862005-12-17 12:27:53 +01001652#ifndef MSG_NOSIGNAL
1653 lskerr=sizeof(skerr);
1654 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1655 if (skerr)
1656 ret = -1;
1657 else
1658 ret = send(fd, b->w, max, MSG_DONTWAIT);
1659#else
willy tarreau0f7af912005-12-17 12:21:26 +01001660 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001661#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001662 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001663 if (ret > 0) {
1664 b->l -= ret;
1665 b->w += ret;
1666
1667 s->res_sw = RES_DATA;
1668
1669 if (b->w == b->data + BUFSIZE) {
1670 b->w = b->data; /* wrap around the buffer */
1671 }
1672 }
1673 else if (ret == 0) {
1674 /* nothing written, just make as if we were never called */
1675 // s->res_sw = RES_NULL;
1676 return 0;
1677 }
1678 else if (errno == EAGAIN) /* ignore EAGAIN */
1679 return 0;
1680 else {
1681 s->res_sw = RES_ERROR;
1682 fdtab[fd].state = FD_STERROR;
1683 }
1684 }
1685 else {
1686 s->res_sw = RES_ERROR;
1687 fdtab[fd].state = FD_STERROR;
1688 }
1689
1690 if (s->proxy->srvtimeout)
1691 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1692 else
1693 tv_eternity(&s->swexpire);
1694
willy tarreau5cbea6f2005-12-17 12:48:26 +01001695 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001696 return 0;
1697}
1698
1699
1700/*
willy tarreaue39cd132005-12-17 13:00:18 +01001701 * returns a message to the client ; the connection is shut down for read,
1702 * and the request is cleared so that no server connection can be initiated.
1703 * The client must be in a valid state for this (HEADER, DATA ...).
1704 * Nothing is performed on the server side.
1705 * The reply buffer must be empty before this.
1706 */
1707void client_retnclose(struct session *s, int len, const char *msg) {
1708 FD_CLR(s->cli_fd, StaticReadEvent);
1709 FD_SET(s->cli_fd, StaticWriteEvent);
1710 tv_eternity(&s->crexpire);
1711 shutdown(s->cli_fd, SHUT_RD);
1712 s->cli_state = CL_STSHUTR;
1713 strcpy(s->rep->data, msg);
1714 s->rep->l = len;
1715 s->rep->r += len;
1716 s->req->l = 0;
1717}
1718
1719
1720/*
1721 * returns a message into the rep buffer, and flushes the req buffer.
1722 * The reply buffer must be empty before this.
1723 */
1724void client_return(struct session *s, int len, const char *msg) {
1725 strcpy(s->rep->data, msg);
1726 s->rep->l = len;
1727 s->rep->r += len;
1728 s->req->l = 0;
1729}
1730
willy tarreau9fe663a2005-12-17 13:02:59 +01001731/*
1732 * send a log for the session when we have enough info about it
1733 */
1734void sess_log(struct session *s) {
1735 unsigned char *pn;
1736 struct proxy *p = s->proxy;
1737 int log;
1738 char *uri;
1739 char *pxid;
1740 char *srv;
1741
1742 /* This is a first attempt at a better logging system.
1743 * For now, we rely on send_log() to provide the date, although it obviously
1744 * is the date of the log and not of the request, and most fields are not
1745 * computed.
1746 */
1747
willy tarreaua1598082005-12-17 13:08:06 +01001748 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001749
1750 pn = (log & LW_CLIP) ?
1751 (unsigned char *)&s->cli_addr.sin_addr :
1752 (unsigned char *)"\0\0\0\0";
1753
willy tarreaua1598082005-12-17 13:08:06 +01001754 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001755 pxid = p->id;
1756 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001757 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1758
1759 if (p->to_log & LW_DATE) {
1760 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1761
1762 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",
1763 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1764 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1765 tm->tm_hour, tm->tm_min, tm->tm_sec,
1766 pxid, srv,
1767 s->logs.t_request,
1768 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1769 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1770 s->logs.t_close,
1771 s->logs.status, s->logs.bytes,
1772 uri);
1773 }
1774 else {
1775 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld \"%s\"\n",
1776 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1777 pxid, srv,
1778 s->logs.t_request,
1779 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1780 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1781 s->logs.t_close,
1782 s->logs.status, s->logs.bytes,
1783 uri);
1784 }
1785
1786 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001787}
1788
willy tarreaue39cd132005-12-17 13:00:18 +01001789
1790/*
willy tarreau0f7af912005-12-17 12:21:26 +01001791 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001792 * to an accept. It tries to accept as many connections as possible.
1793 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001794 */
1795int event_accept(int fd) {
1796 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001797 struct session *s;
1798 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001799 int cfd;
1800 int one = 1;
1801
willy tarreau5cbea6f2005-12-17 12:48:26 +01001802 while (p->nbconn < p->maxconn) {
1803 struct sockaddr_in addr;
1804 int laddr = sizeof(addr);
1805 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1806 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001807
willy tarreau5cbea6f2005-12-17 12:48:26 +01001808 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1809 Alert("out of memory in event_accept().\n");
1810 FD_CLR(fd, StaticReadEvent);
1811 p->state = PR_STIDLE;
1812 close(cfd);
1813 return 0;
1814 }
willy tarreau0f7af912005-12-17 12:21:26 +01001815
willy tarreau5cbea6f2005-12-17 12:48:26 +01001816 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1817 Alert("out of memory in event_accept().\n");
1818 FD_CLR(fd, StaticReadEvent);
1819 p->state = PR_STIDLE;
1820 close(cfd);
1821 pool_free(session, s);
1822 return 0;
1823 }
willy tarreau0f7af912005-12-17 12:21:26 +01001824
willy tarreau5cbea6f2005-12-17 12:48:26 +01001825 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001826 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001827 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1828 close(cfd);
1829 pool_free(task, t);
1830 pool_free(session, s);
1831 return 0;
1832 }
willy tarreau0f7af912005-12-17 12:21:26 +01001833
willy tarreau5cbea6f2005-12-17 12:48:26 +01001834 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1835 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1836 (char *) &one, sizeof(one)) == -1)) {
1837 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1838 close(cfd);
1839 pool_free(task, t);
1840 pool_free(session, s);
1841 return 0;
1842 }
willy tarreau0f7af912005-12-17 12:21:26 +01001843
willy tarreau9fe663a2005-12-17 13:02:59 +01001844 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1845 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1846 t->state = TASK_IDLE;
1847 t->process = process_session;
1848 t->context = s;
1849
1850 s->task = t;
1851 s->proxy = p;
1852 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1853 s->srv_state = SV_STIDLE;
1854 s->req = s->rep = NULL; /* will be allocated later */
1855 s->flags = 0;
1856 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1857 s->cli_fd = cfd;
1858 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01001859 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01001860 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01001861
1862 s->logs.logwait = p->to_log;
1863 s->logs.tv_accept = now;
1864 s->logs.t_request = -1;
1865 s->logs.t_connect = -1;
1866 s->logs.t_data = -1;
1867 s->logs.t_close = 0;
1868 s->logs.uri = NULL;
1869 s->logs.status = -1;
1870 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001871
willy tarreau5cbea6f2005-12-17 12:48:26 +01001872 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1873 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01001874 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001875 unsigned char *pn, *sn;
1876 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01001877
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 namelen = sizeof(sockname);
1879 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1880 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1881 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01001882 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001883
willy tarreau9fe663a2005-12-17 13:02:59 +01001884 if (p->to_log) {
1885 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01001886 if (s->logs.logwait & LW_CLIP)
1887 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01001888 sess_log(s);
1889 }
1890 else
1891 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1892 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1893 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1894 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01001895 }
willy tarreau0f7af912005-12-17 12:21:26 +01001896
willy tarreau9fe663a2005-12-17 13:02:59 +01001897 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreauef900ab2005-12-17 12:52:52 +01001898 int len;
1899 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1900 write(1, trash, len);
1901 }
willy tarreau0f7af912005-12-17 12:21:26 +01001902
willy tarreau5cbea6f2005-12-17 12:48:26 +01001903 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1904 close(cfd); /* nothing can be done for this fd without memory */
1905 pool_free(task, t);
1906 pool_free(session, s);
1907 return 0;
1908 }
1909 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01001910 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001911 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1912 s->req->rlim = s->req->data + BUFSIZE;
1913 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
1914 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01001915
willy tarreau5cbea6f2005-12-17 12:48:26 +01001916 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1917 pool_free(buffer, s->req);
1918 close(cfd); /* nothing can be done for this fd without memory */
1919 pool_free(task, t);
1920 pool_free(session, s);
1921 return 0;
1922 }
1923 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01001924 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001925 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 +01001926
willy tarreau5cbea6f2005-12-17 12:48:26 +01001927 fdtab[cfd].read = &event_cli_read;
1928 fdtab[cfd].write = &event_cli_write;
1929 fdtab[cfd].owner = t;
1930 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001931
willy tarreau5cbea6f2005-12-17 12:48:26 +01001932 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01001933 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001934 }
1935 else {
1936 FD_SET(cfd, StaticReadEvent);
1937 }
1938
1939 fd_insert(cfd);
1940
1941 tv_eternity(&s->cnexpire);
1942 tv_eternity(&s->srexpire);
1943 tv_eternity(&s->swexpire);
1944 tv_eternity(&s->cwexpire);
1945
1946 if (s->proxy->clitimeout)
1947 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1948 else
1949 tv_eternity(&s->crexpire);
1950
1951 t->expire = s->crexpire;
1952
1953 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01001954
1955 if (p->mode != PR_MODE_HEALTH)
1956 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001957
1958 p->nbconn++;
1959 actconn++;
1960 totalconn++;
1961
1962 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1963 } /* end of while (p->nbconn < p->maxconn) */
1964 return 0;
1965}
willy tarreau0f7af912005-12-17 12:21:26 +01001966
willy tarreau0f7af912005-12-17 12:21:26 +01001967
willy tarreau5cbea6f2005-12-17 12:48:26 +01001968/*
1969 * This function is used only for server health-checks. It handles
1970 * the connection acknowledgement and returns 1 if the socket is OK,
1971 * or -1 if an error occured.
1972 */
1973int event_srv_hck(int fd) {
1974 struct task *t = fdtab[fd].owner;
1975 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001976
willy tarreau5cbea6f2005-12-17 12:48:26 +01001977 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01001978 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1980 if (skerr)
1981 s->result = -1;
1982 else
1983 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001984
willy tarreau5cbea6f2005-12-17 12:48:26 +01001985 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001986 return 0;
1987}
1988
1989
1990/*
1991 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1992 * and moves <end> just after the end of <str>.
1993 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1994 * the shift value (positive or negative) is returned.
1995 * If there's no space left, the move is not done.
1996 *
1997 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001998int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01001999 int delta;
2000 int len;
2001
2002 len = strlen(str);
2003 delta = len - (end - pos);
2004
2005 if (delta + b->r >= b->data + BUFSIZE)
2006 return 0; /* no space left */
2007
2008 /* first, protect the end of the buffer */
2009 memmove(end + delta, end, b->data + b->l - end);
2010
2011 /* now, copy str over pos */
2012 memcpy(pos, str,len);
2013
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 /* we only move data after the displaced zone */
2015 if (b->r > pos) b->r += delta;
2016 if (b->w > pos) b->w += delta;
2017 if (b->h > pos) b->h += delta;
2018 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002019 b->l += delta;
2020
2021 return delta;
2022}
2023
2024/* same except that the string len is given */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002025int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002026 int delta;
2027
2028 delta = len - (end - pos);
2029
2030 if (delta + b->r >= b->data + BUFSIZE)
2031 return 0; /* no space left */
2032
2033 /* first, protect the end of the buffer */
2034 memmove(end + delta, end, b->data + b->l - end);
2035
2036 /* now, copy str over pos */
2037 memcpy(pos, str,len);
2038
willy tarreau5cbea6f2005-12-17 12:48:26 +01002039 /* we only move data after the displaced zone */
2040 if (b->r > pos) b->r += delta;
2041 if (b->w > pos) b->w += delta;
2042 if (b->h > pos) b->h += delta;
2043 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002044 b->l += delta;
2045
2046 return delta;
2047}
2048
2049
2050int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2051 char *old_dst = dst;
2052
2053 while (*str) {
2054 if (*str == '\\') {
2055 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002056 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002057 int len, num;
2058
2059 num = *str - '0';
2060 str++;
2061
2062 if (matches[num].rm_so > -1) {
2063 len = matches[num].rm_eo - matches[num].rm_so;
2064 memcpy(dst, src + matches[num].rm_so, len);
2065 dst += len;
2066 }
2067
2068 }
2069 else if (*str == 'x') {
2070 unsigned char hex1, hex2;
2071 str++;
2072
2073 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2074
2075 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2076 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2077 *dst++ = (hex1<<4) + hex2;
2078 }
2079 else
2080 *dst++ = *str++;
2081 }
2082 else
2083 *dst++ = *str++;
2084 }
2085 *dst = 0;
2086 return dst - old_dst;
2087}
2088
willy tarreau9fe663a2005-12-17 13:02:59 +01002089
willy tarreau0f7af912005-12-17 12:21:26 +01002090/*
2091 * manages the client FSM and its socket. BTW, it also tries to handle the
2092 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2093 * 0 else.
2094 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002095int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002096 int s = t->srv_state;
2097 int c = t->cli_state;
2098 struct buffer *req = t->req;
2099 struct buffer *rep = t->rep;
2100
2101 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2102 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2103 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2104 //);
2105 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002106 /* now parse the partial (or complete) headers */
2107 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2108 char *ptr;
2109 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002110
willy tarreau5cbea6f2005-12-17 12:48:26 +01002111 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002112
willy tarreau0f7af912005-12-17 12:21:26 +01002113 /* look for the end of the current header */
2114 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2115 ptr++;
2116
willy tarreau5cbea6f2005-12-17 12:48:26 +01002117 if (ptr == req->h) { /* empty line, end of headers */
2118 char newhdr[MAXREWRITE + 1];
2119 int line, len;
2120 /* we can only get here after an end of headers */
2121 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002122
willy tarreaue39cd132005-12-17 13:00:18 +01002123 if (t->flags & SN_CLDENY) {
2124 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002125 t->logs.status = 403;
willy tarreaue39cd132005-12-17 13:00:18 +01002126 client_retnclose(t, strlen(HTTP_403), HTTP_403);
2127 return 1;
2128 }
2129
willy tarreau5cbea6f2005-12-17 12:48:26 +01002130 for (line = 0; line < t->proxy->nb_reqadd; line++) {
2131 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
2132 buffer_replace2(req, req->h, req->h, newhdr, len);
2133 }
willy tarreau0f7af912005-12-17 12:21:26 +01002134
willy tarreau9fe663a2005-12-17 13:02:59 +01002135 if (t->proxy->options & PR_O_FWDFOR) {
2136 /* insert an X-Forwarded-For header */
2137 unsigned char *pn;
2138 pn = (unsigned char *)&t->cli_addr.sin_addr;
2139 len = sprintf(newhdr, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2140 pn[0], pn[1], pn[2], pn[3]);
2141 buffer_replace2(req, req->h, req->h, newhdr, len);
2142 }
2143
willy tarreau5cbea6f2005-12-17 12:48:26 +01002144 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002145 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002146
willy tarreaua1598082005-12-17 13:08:06 +01002147 t->logs.t_request = tv_delta(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002148 /* FIXME: we'll set the client in a wait state while we try to
2149 * connect to the server. Is this really needed ? wouldn't it be
2150 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002151 //FD_CLR(t->cli_fd, StaticReadEvent);
2152 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002153 break;
2154 }
willy tarreau0f7af912005-12-17 12:21:26 +01002155
willy tarreau5cbea6f2005-12-17 12:48:26 +01002156 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2157 if (ptr > req->r - 2) {
2158 /* this is a partial header, let's wait for more to come */
2159 req->lr = ptr;
2160 break;
2161 }
willy tarreau0f7af912005-12-17 12:21:26 +01002162
willy tarreau5cbea6f2005-12-17 12:48:26 +01002163 /* now we know that *ptr is either \r or \n,
2164 * and that there are at least 1 char after it.
2165 */
2166 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2167 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2168 else
2169 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002170
willy tarreau5cbea6f2005-12-17 12:48:26 +01002171 /*
2172 * now we know that we have a full header ; we can do whatever
2173 * we want with these pointers :
2174 * req->h = beginning of header
2175 * ptr = end of header (first \r or \n)
2176 * req->lr = beginning of next line (next rep->h)
2177 * req->r = end of data (not used at this stage)
2178 */
willy tarreau0f7af912005-12-17 12:21:26 +01002179
willy tarreaua1598082005-12-17 13:08:06 +01002180 if (t->logs.logwait & LW_REQ &&
2181 t->proxy->mode & PR_MODE_HTTP) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002182 /* we have a complete HTTP request that we must log */
2183 int urilen;
2184
willy tarreaua1598082005-12-17 13:08:06 +01002185 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002186 Alert("HTTP logging : out of memory.\n");
willy tarreaua1598082005-12-17 13:08:06 +01002187 t->logs.status = 502;
2188 client_retnclose(t, strlen(HTTP_502), HTTP_502);
willy tarreau9fe663a2005-12-17 13:02:59 +01002189 return 1;
2190 }
2191
2192 urilen = ptr - req->h;
2193 if (urilen >= REQURI_LEN)
2194 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002195 memcpy(t->logs.uri, req->h, urilen);
2196 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002197
willy tarreaua1598082005-12-17 13:08:06 +01002198 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002199 sess_log(t);
2200 }
2201
willy tarreau5cbea6f2005-12-17 12:48:26 +01002202 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002203
willy tarreau9fe663a2005-12-17 13:02:59 +01002204 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002205 int len, max;
2206 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2207 max = ptr - req->h;
2208 UBOUND(max, sizeof(trash) - len - 1);
2209 len += strlcpy(trash + len, req->h, max + 1);
2210 trash[len++] = '\n';
2211 write(1, trash, len);
2212 }
willy tarreau0f7af912005-12-17 12:21:26 +01002213
willy tarreau5cbea6f2005-12-17 12:48:26 +01002214 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002215 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2216 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002217 char term;
2218
2219 term = *ptr;
2220 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002221 exp = t->proxy->req_exp;
2222 do {
2223 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2224 switch (exp->action) {
2225 case ACT_ALLOW:
2226 if (!(t->flags & SN_CLDENY))
2227 t->flags |= SN_CLALLOW;
2228 break;
2229 case ACT_REPLACE:
2230 if (!(t->flags & SN_CLDENY)) {
2231 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2232 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2233 }
2234 break;
2235 case ACT_REMOVE:
2236 if (!(t->flags & SN_CLDENY))
2237 delete_header = 1;
2238 break;
2239 case ACT_DENY:
2240 if (!(t->flags & SN_CLALLOW))
2241 t->flags |= SN_CLDENY;
2242 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002243 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002244 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002245 }
willy tarreaue39cd132005-12-17 13:00:18 +01002246 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002247 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002248 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002249
2250 /* now look for cookies */
2251 if (!delete_header && (req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
2252 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
2253 char *p1, *p2, *p3, *p4;
2254
2255 p1 = req->h + 8; /* first char after 'Cookie: ' */
2256
2257 while (p1 < ptr) {
willy tarreauc29948c2005-12-17 13:10:27 +01002258 while (p1 < ptr && (isspace((int)*p1) || *p1 == ';'))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002259 p1++;
2260
2261 if (p1 == ptr)
2262 break;
2263 else if (*p1 == ';') { /* next cookie */
2264 ++p1;
2265 continue;
2266 }
2267
2268 /* p1 is at the beginning of the cookie name */
2269 p2 = p1;
2270
2271 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2272 p2++;
2273
2274 if (p2 == ptr)
2275 break;
2276 else if (*p2 == ';') { /* next cookie */
2277 p1=++p2;
2278 continue;
2279 }
2280
2281 p3 = p2 + 1; /* skips the '=' sign */
2282 if (p3 == ptr)
2283 break;
2284
2285 p4=p3;
willy tarreauc29948c2005-12-17 13:10:27 +01002286 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002287 p4++;
2288
2289 /* here, we have the cookie name between p1 and p2,
2290 * and its value between p3 and p4.
2291 * we can process it.
2292 */
2293
2294 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2295 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2296 /* Cool... it's the right one */
2297 struct server *srv = t->proxy->srv;
2298
2299 while (srv &&
2300 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2301 srv = srv->next;
2302 }
2303
2304 if (srv) { /* we found the server */
willy tarreaue39cd132005-12-17 13:00:18 +01002305 t->flags |= SN_DIRECT;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002306 t->srv = srv;
willy tarreau96d40372005-12-17 13:11:56 +01002307 /* if this cookie was set in insert+indirect mode, then it's better that the
2308 * server never sees it.
2309 */
2310 if ((t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND))
2311 delete_header = 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002312 }
2313
2314 break;
2315 }
2316 else {
2317 // fprintf(stderr,"Ignoring unknown cookie : ");
2318 // write(2, p1, p2-p1);
2319 // fprintf(stderr," = ");
2320 // write(2, p3, p4-p3);
2321 // fprintf(stderr,"\n");
2322 }
2323 /* we'll have to look for another cookie ... */
2324 p1 = p4;
2325 } /* while (p1 < ptr) */
2326 } /* end of cookie processing */
2327
2328 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002329 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002330 buffer_replace2(req, req->h, req->lr, "", 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002331 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002332 req->h = req->lr;
2333 } /* while (req->lr < req->r) */
2334
2335 /* end of header processing (even if incomplete) */
2336
willy tarreauef900ab2005-12-17 12:52:52 +01002337 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2338 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2339 * full. We cannot loop here since event_cli_read will disable it only if
2340 * req->l == rlim-data
2341 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002342 FD_SET(t->cli_fd, StaticReadEvent);
2343 if (t->proxy->clitimeout)
2344 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2345 else
2346 tv_eternity(&t->crexpire);
2347 }
2348
willy tarreaue39cd132005-12-17 13:00:18 +01002349 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002350 * won't be able to free more later, so the session will never terminate.
2351 */
willy tarreaue39cd132005-12-17 13:00:18 +01002352 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002353 t->logs.status = 400;
willy tarreaue39cd132005-12-17 13:00:18 +01002354 client_retnclose(t, strlen(HTTP_400), HTTP_400);
2355 return 1;
2356 }
2357 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2358 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2359
2360 /* read timeout, read error, or last read : give up.
2361 * since we are in header mode, if there's no space left for headers, we
2362 * won't be able to free more later, so the session will never terminate.
2363 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002364 tv_eternity(&t->crexpire);
2365 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002366 t->cli_state = CL_STCLOSE;
2367 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002368 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002369
2370 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002371 }
2372 else if (c == CL_STDATA) {
2373 /* read or write error */
2374 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002375 tv_eternity(&t->crexpire);
2376 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002377 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002378 t->cli_state = CL_STCLOSE;
2379 return 1;
2380 }
2381 /* read timeout, last read, or end of server write */
2382 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2383 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002384 FD_CLR(t->cli_fd, StaticReadEvent);
2385 // if (req->l == 0) /* nothing to write on the server side */
2386 // FD_CLR(t->srv_fd, StaticWriteEvent);
2387 tv_eternity(&t->crexpire);
2388 shutdown(t->cli_fd, SHUT_RD);
2389 t->cli_state = CL_STSHUTR;
2390 return 1;
2391 }
2392 /* write timeout, or last server read and buffer empty */
2393 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2394 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002395 FD_CLR(t->cli_fd, StaticWriteEvent);
2396 tv_eternity(&t->cwexpire);
2397 shutdown(t->cli_fd, SHUT_WR);
2398 t->cli_state = CL_STSHUTW;
2399 return 1;
2400 }
2401
willy tarreauef900ab2005-12-17 12:52:52 +01002402 if (req->l >= req->rlim - req->data) {
2403 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002404 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002405 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002406 FD_CLR(t->cli_fd, StaticReadEvent);
2407 tv_eternity(&t->crexpire);
2408 }
2409 }
2410 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002411 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002412 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2413 FD_SET(t->cli_fd, StaticReadEvent);
2414 if (t->proxy->clitimeout)
2415 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2416 else
2417 tv_eternity(&t->crexpire);
2418 }
2419 }
2420
2421 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002422 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002423 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2424 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2425 tv_eternity(&t->cwexpire);
2426 }
2427 }
2428 else { /* buffer not empty */
2429 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2430 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2431 if (t->proxy->clitimeout)
2432 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2433 else
2434 tv_eternity(&t->cwexpire);
2435 }
2436 }
2437 return 0; /* other cases change nothing */
2438 }
2439 else if (c == CL_STSHUTR) {
2440 if ((t->res_cw == RES_ERROR) ||
2441 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002442 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002443 tv_eternity(&t->cwexpire);
2444 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002445 t->cli_state = CL_STCLOSE;
2446 return 1;
2447 }
2448 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002449 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002450 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2451 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2452 tv_eternity(&t->cwexpire);
2453 }
2454 }
2455 else { /* buffer not empty */
2456 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2457 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2458 if (t->proxy->clitimeout)
2459 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2460 else
2461 tv_eternity(&t->cwexpire);
2462 }
2463 }
2464 return 0;
2465 }
2466 else if (c == CL_STSHUTW) {
2467 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002468 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002469 tv_eternity(&t->crexpire);
2470 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002471 t->cli_state = CL_STCLOSE;
2472 return 1;
2473 }
willy tarreauef900ab2005-12-17 12:52:52 +01002474 else if (req->l >= req->rlim - req->data) {
2475 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002476 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002477 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002478 FD_CLR(t->cli_fd, StaticReadEvent);
2479 tv_eternity(&t->crexpire);
2480 }
2481 }
2482 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002483 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002484 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2485 FD_SET(t->cli_fd, StaticReadEvent);
2486 if (t->proxy->clitimeout)
2487 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2488 else
2489 tv_eternity(&t->crexpire);
2490 }
2491 }
2492 return 0;
2493 }
2494 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002495 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002496 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002497 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002498 write(1, trash, len);
2499 }
2500 return 0;
2501 }
2502 return 0;
2503}
2504
2505
2506/*
2507 * manages the server FSM and its socket. It returns 1 if a state has changed
2508 * (and a resync may be needed), 0 else.
2509 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002510int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002511 int s = t->srv_state;
2512 int c = t->cli_state;
2513 struct buffer *req = t->req;
2514 struct buffer *rep = t->rep;
2515
willy tarreau5cbea6f2005-12-17 12:48:26 +01002516 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2517 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2518 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2519 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2520 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002521 if (s == SV_STIDLE) {
2522 if (c == CL_STHEADERS)
2523 return 0; /* stay in idle, waiting for data to reach the client side */
2524 else if (c == CL_STCLOSE ||
2525 c == CL_STSHUTW ||
2526 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2527 tv_eternity(&t->cnexpire);
2528 t->srv_state = SV_STCLOSE;
2529 return 1;
2530 }
2531 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002532 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002533 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2534 t->srv_state = SV_STCONN;
2535 }
2536 else { /* try again */
2537 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002538 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002539 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002540 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2541 }
2542
2543 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002544 t->srv_state = SV_STCONN;
2545 break;
2546 }
2547 }
2548 if (t->conn_retries < 0) {
2549 /* if conn_retries < 0 or other error, let's abort */
2550 tv_eternity(&t->cnexpire);
2551 t->srv_state = SV_STCLOSE;
willy tarreaua1598082005-12-17 13:08:06 +01002552 t->logs.status = 502;
willy tarreaue39cd132005-12-17 13:00:18 +01002553 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002554 }
2555 }
2556 return 1;
2557 }
2558 }
2559 else if (s == SV_STCONN) { /* connection in progress */
2560 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2561 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2562 return 0; /* nothing changed */
2563 }
2564 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2565 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2566 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002567 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002568 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002569 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002570 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002571 if (t->conn_retries >= 0) {
2572 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002573 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002574 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2575 }
2576 if (connect_server(t) == 0)
2577 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002578 }
2579 /* if conn_retries < 0 or other error, let's abort */
2580 tv_eternity(&t->cnexpire);
2581 t->srv_state = SV_STCLOSE;
2582 return 1;
2583 }
2584 else { /* no error or write 0 */
willy tarreaua1598082005-12-17 13:08:06 +01002585 t->logs.t_connect = tv_delta(&t->logs.tv_accept, &now);
2586
willy tarreau0f7af912005-12-17 12:21:26 +01002587 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2588 if (req->l == 0) /* nothing to write */
2589 FD_CLR(t->srv_fd, StaticWriteEvent);
2590 else /* need the right to write */
2591 FD_SET(t->srv_fd, StaticWriteEvent);
2592
2593 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2594 FD_SET(t->srv_fd, StaticReadEvent);
2595 if (t->proxy->srvtimeout)
2596 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2597 else
2598 tv_eternity(&t->srexpire);
2599
2600 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002601 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002602 }
willy tarreauef900ab2005-12-17 12:52:52 +01002603 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002604 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002605 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2606 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002607 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002608 return 1;
2609 }
2610 }
2611 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002612
2613 /* now parse the partial (or complete) headers */
2614 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2615 char *ptr;
2616 int delete_header;
2617
2618 ptr = rep->lr;
2619
2620 /* look for the end of the current header */
2621 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2622 ptr++;
2623
2624 if (ptr == rep->h) {
2625 char newhdr[MAXREWRITE + 1];
2626 int line, len;
2627
2628 /* we can only get here after an end of headers */
2629 /* we'll have something else to do here : add new headers ... */
2630
willy tarreaue39cd132005-12-17 13:00:18 +01002631 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002632 /* the server is known, it's not the one the client requested, we have to
2633 * insert a set-cookie here.
2634 */
2635 len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
2636 t->proxy->cookie_name, t->srv->cookie);
2637 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2638 }
2639
2640 /* headers to be added */
2641 for (line = 0; line < t->proxy->nb_rspadd; line++) {
2642 len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
2643 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2644 }
2645
2646 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002647 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreaua1598082005-12-17 13:08:06 +01002648 t->logs.t_data = tv_delta(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002649 break;
2650 }
2651
2652 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2653 if (ptr > rep->r - 2) {
2654 /* this is a partial header, let's wait for more to come */
2655 rep->lr = ptr;
2656 break;
2657 }
2658
2659 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2660 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2661
2662 /* now we know that *ptr is either \r or \n,
2663 * and that there are at least 1 char after it.
2664 */
2665 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2666 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2667 else
2668 rep->lr = ptr + 2; /* \r\n or \n\r */
2669
2670 /*
2671 * now we know that we have a full header ; we can do whatever
2672 * we want with these pointers :
2673 * rep->h = beginning of header
2674 * ptr = end of header (first \r or \n)
2675 * rep->lr = beginning of next line (next rep->h)
2676 * rep->r = end of data (not used at this stage)
2677 */
2678
willy tarreaua1598082005-12-17 13:08:06 +01002679
2680 if (t->logs.logwait & LW_RESP) {
2681 t->logs.logwait &= ~LW_RESP;
2682 t->logs.status = atoi(rep->h + 9);
2683 }
2684
willy tarreau5cbea6f2005-12-17 12:48:26 +01002685 delete_header = 0;
2686
willy tarreau9fe663a2005-12-17 13:02:59 +01002687 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002688 int len, max;
2689 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2690 max = ptr - rep->h;
2691 UBOUND(max, sizeof(trash) - len - 1);
2692 len += strlcpy(trash + len, rep->h, max + 1);
2693 trash[len++] = '\n';
2694 write(1, trash, len);
2695 }
2696
2697 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002698 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
2699 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002700 char term;
2701
2702 term = *ptr;
2703 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002704 exp = t->proxy->rsp_exp;
2705 do {
2706 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2707 switch (exp->action) {
2708 case ACT_ALLOW:
2709 if (!(t->flags & SN_SVDENY))
2710 t->flags |= SN_SVALLOW;
2711 break;
2712 case ACT_REPLACE:
2713 if (!(t->flags & SN_SVDENY)) {
2714 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2715 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2716 }
2717 break;
2718 case ACT_REMOVE:
2719 if (!(t->flags & SN_SVDENY))
2720 delete_header = 1;
2721 break;
2722 case ACT_DENY:
2723 if (!(t->flags & SN_SVALLOW))
2724 t->flags |= SN_SVDENY;
2725 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002726 }
2727 break;
2728 }
willy tarreaue39cd132005-12-17 13:00:18 +01002729 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002730 *ptr = term; /* restore the string terminator */
2731 }
2732
2733 /* check for server cookies */
2734 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY) && (rep->r >= rep->h + 12) &&
2735 (t->proxy->cookie_name != NULL) && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2736 char *p1, *p2, *p3, *p4;
2737
2738 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2739
2740 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01002741 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002742 p1++;
2743
2744 if (p1 == ptr || *p1 == ';') /* end of cookie */
2745 break;
2746
2747 /* p1 is at the beginning of the cookie name */
2748 p2 = p1;
2749
2750 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2751 p2++;
2752
2753 if (p2 == ptr || *p2 == ';') /* next cookie */
2754 break;
2755
2756 p3 = p2 + 1; /* skips the '=' sign */
2757 if (p3 == ptr)
2758 break;
2759
2760 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01002761 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002762 p4++;
2763
2764 /* here, we have the cookie name between p1 and p2,
2765 * and its value between p3 and p4.
2766 * we can process it.
2767 */
2768
2769 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2770 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2771 /* Cool... it's the right one */
2772
2773 /* If the cookie is in insert mode on a known server, we'll delete
2774 * this occurrence because we'll insert another one later.
2775 * We'll delete it too if the "indirect" option is set and we're in
2776 * a direct access. */
2777 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01002778 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002779 /* this header must be deleted */
2780 delete_header = 1;
2781 }
2782 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2783 /* replace bytes p3->p4 with the cookie name associated
2784 * with this server since we know it.
2785 */
2786 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2787 }
2788 break;
2789 }
2790 else {
2791 // fprintf(stderr,"Ignoring unknown cookie : ");
2792 // write(2, p1, p2-p1);
2793 // fprintf(stderr," = ");
2794 // write(2, p3, p4-p3);
2795 // fprintf(stderr,"\n");
2796 }
2797 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2798 } /* we're now at the end of the cookie value */
2799 } /* end of cookie processing */
2800
2801 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002802 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002803 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01002804
willy tarreau5cbea6f2005-12-17 12:48:26 +01002805 rep->h = rep->lr;
2806 } /* while (rep->lr < rep->r) */
2807
2808 /* end of header processing (even if incomplete) */
2809
willy tarreauef900ab2005-12-17 12:52:52 +01002810 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2811 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2812 * full. We cannot loop here since event_srv_read will disable it only if
2813 * rep->l == rlim-data
2814 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002815 FD_SET(t->srv_fd, StaticReadEvent);
2816 if (t->proxy->srvtimeout)
2817 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2818 else
2819 tv_eternity(&t->srexpire);
2820 }
willy tarreau0f7af912005-12-17 12:21:26 +01002821
2822 /* read or write error */
2823 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002824 tv_eternity(&t->srexpire);
2825 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002826 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002827 t->srv_state = SV_STCLOSE;
2828 return 1;
2829 }
willy tarreauef900ab2005-12-17 12:52:52 +01002830 /* read timeout, last read, or end of client write
2831 * since we are in header mode, if there's no space left for headers, we
2832 * won't be able to free more later, so the session will never terminate.
2833 */
2834 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2835 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002836 FD_CLR(t->srv_fd, StaticReadEvent);
2837 tv_eternity(&t->srexpire);
2838 shutdown(t->srv_fd, SHUT_RD);
2839 t->srv_state = SV_STSHUTR;
2840 return 1;
2841
2842 }
2843 /* write timeout, or last client read and buffer empty */
2844 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2845 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2846 FD_CLR(t->srv_fd, StaticWriteEvent);
2847 tv_eternity(&t->swexpire);
2848 shutdown(t->srv_fd, SHUT_WR);
2849 t->srv_state = SV_STSHUTW;
2850 return 1;
2851 }
2852
2853 if (req->l == 0) {
2854 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2855 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2856 tv_eternity(&t->swexpire);
2857 }
2858 }
2859 else { /* client buffer not empty */
2860 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2861 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2862 if (t->proxy->srvtimeout)
2863 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2864 else
2865 tv_eternity(&t->swexpire);
2866 }
2867 }
2868
willy tarreau5cbea6f2005-12-17 12:48:26 +01002869 /* be nice with the client side which would like to send a complete header
2870 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2871 * would read all remaining data at once ! The client should not write past rep->lr
2872 * when the server is in header state.
2873 */
2874 //return header_processed;
2875 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002876 }
2877 else if (s == SV_STDATA) {
2878 /* read or write error */
2879 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002880 tv_eternity(&t->srexpire);
2881 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002882 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002883 t->srv_state = SV_STCLOSE;
2884 return 1;
2885 }
2886 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01002887 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2888 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002889 FD_CLR(t->srv_fd, StaticReadEvent);
2890 tv_eternity(&t->srexpire);
2891 shutdown(t->srv_fd, SHUT_RD);
2892 t->srv_state = SV_STSHUTR;
2893 return 1;
2894
2895 }
2896 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01002897 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
2898 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002899 FD_CLR(t->srv_fd, StaticWriteEvent);
2900 tv_eternity(&t->swexpire);
2901 shutdown(t->srv_fd, SHUT_WR);
2902 t->srv_state = SV_STSHUTW;
2903 return 1;
2904 }
2905 else if (req->l == 0) {
2906 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2907 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2908 tv_eternity(&t->swexpire);
2909 }
2910 }
2911 else { /* buffer not empty */
2912 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2913 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2914 if (t->proxy->srvtimeout)
2915 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2916 else
2917 tv_eternity(&t->swexpire);
2918 }
2919 }
2920
2921 if (rep->l == BUFSIZE) { /* no room to read more data */
2922 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2923 FD_CLR(t->srv_fd, StaticReadEvent);
2924 tv_eternity(&t->srexpire);
2925 }
2926 }
2927 else {
2928 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2929 FD_SET(t->srv_fd, StaticReadEvent);
2930 if (t->proxy->srvtimeout)
2931 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2932 else
2933 tv_eternity(&t->srexpire);
2934 }
2935 }
2936
2937 return 0; /* other cases change nothing */
2938 }
2939 else if (s == SV_STSHUTR) {
2940 if ((t->res_sw == RES_ERROR) ||
2941 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2942 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002943 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002944 tv_eternity(&t->swexpire);
2945 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002946 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002947 t->srv_state = SV_STCLOSE;
2948 return 1;
2949 }
2950 else if (req->l == 0) {
2951 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2952 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2953 tv_eternity(&t->swexpire);
2954 }
2955 }
2956 else { /* buffer not empty */
2957 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2958 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2959 if (t->proxy->srvtimeout)
2960 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2961 else
2962 tv_eternity(&t->swexpire);
2963 }
2964 }
2965 return 0;
2966 }
2967 else if (s == SV_STSHUTW) {
2968 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
2969 c == CL_STSHUTW || c == CL_STCLOSE ||
2970 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002971 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002972 tv_eternity(&t->srexpire);
2973 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002974 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002975 t->srv_state = SV_STCLOSE;
2976 return 1;
2977 }
2978 else if (rep->l == BUFSIZE) { /* no room to read more data */
2979 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2980 FD_CLR(t->srv_fd, StaticReadEvent);
2981 tv_eternity(&t->srexpire);
2982 }
2983 }
2984 else {
2985 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2986 FD_SET(t->srv_fd, StaticReadEvent);
2987 if (t->proxy->srvtimeout)
2988 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2989 else
2990 tv_eternity(&t->srexpire);
2991 }
2992 }
2993 return 0;
2994 }
2995 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002996 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002997 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002998 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002999 write(1, trash, len);
3000 }
3001 return 0;
3002 }
3003 return 0;
3004}
3005
3006
willy tarreau5cbea6f2005-12-17 12:48:26 +01003007/* Processes the client and server jobs of a session task, then
3008 * puts it back to the wait queue in a clean state, or
3009 * cleans up its resources if it must be deleted. Returns
3010 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003011 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003012int process_session(struct task *t) {
3013 struct session *s = t->context;
3014 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003015
willy tarreau5cbea6f2005-12-17 12:48:26 +01003016 do {
3017 fsm_resync = 0;
3018 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3019 fsm_resync |= process_cli(s);
3020 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3021 fsm_resync |= process_srv(s);
3022 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3023 } while (fsm_resync);
3024
3025 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003026 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003027 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003028
willy tarreau5cbea6f2005-12-17 12:48:26 +01003029 tv_min(&min1, &s->crexpire, &s->cwexpire);
3030 tv_min(&min2, &s->srexpire, &s->swexpire);
3031 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003032 tv_min(&t->expire, &min1, &min2);
3033
3034 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003035 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003036
willy tarreau5cbea6f2005-12-17 12:48:26 +01003037 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003038 }
3039
willy tarreau5cbea6f2005-12-17 12:48:26 +01003040 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003041 actconn--;
3042
willy tarreau9fe663a2005-12-17 13:02:59 +01003043 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003044 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003045 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003046 write(1, trash, len);
3047 }
3048
willy tarreaua1598082005-12-17 13:08:06 +01003049 s->logs.t_close = tv_delta(&s->logs.tv_accept, &now);
3050 if (s->rep != NULL)
3051 s->logs.bytes = s->rep->total;
3052
willy tarreau9fe663a2005-12-17 13:02:59 +01003053 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003054 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003055 sess_log(s);
3056
willy tarreau0f7af912005-12-17 12:21:26 +01003057 /* the task MUST not be in the run queue anymore */
3058 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003059 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003060 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003061 return -1; /* rest in peace for eternity */
3062}
3063
3064
3065
3066/*
3067 * manages a server health-check. Returns
3068 * the time the task accepts to wait, or -1 for infinity.
3069 */
3070int process_chk(struct task *t) {
3071 struct server *s = t->context;
3072 int fd = s->curfd;
3073 int one = 1;
3074
willy tarreauef900ab2005-12-17 12:52:52 +01003075 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003076
3077 if (fd < 0) { /* no check currently running */
3078 //fprintf(stderr, "process_chk: 2\n");
3079 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3080 task_queue(t); /* restore t to its place in the task list */
3081 return tv_remain(&now, &t->expire);
3082 }
3083
3084 /* we'll initiate a new check */
3085 s->result = 0; /* no result yet */
3086 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003087 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003088 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3089 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3090 //fprintf(stderr, "process_chk: 3\n");
3091
3092 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
3093 /* OK, connection in progress or established */
3094
3095 //fprintf(stderr, "process_chk: 4\n");
3096
3097 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3098 fdtab[fd].owner = t;
3099 fdtab[fd].read = NULL;
3100 fdtab[fd].write = &event_srv_hck;
3101 fdtab[fd].state = FD_STCONN; /* connection in progress */
3102 FD_SET(fd, StaticWriteEvent); /* for connect status */
3103 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003104 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3105 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003106 task_queue(t); /* restore t to its place in the task list */
3107 return tv_remain(&now, &t->expire);
3108 }
3109 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3110 s->result = -1; /* a real error */
3111 }
3112 }
3113 //fprintf(stderr, "process_chk: 5\n");
3114 close(fd);
3115 }
3116
3117 if (!s->result) { /* nothing done */
3118 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003119 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003120 task_queue(t); /* restore t to its place in the task list */
3121 return tv_remain(&now, &t->expire);
3122 }
3123
3124 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003125 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003126 s->health--; /* still good */
3127 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003128 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003129 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003130 Warning("server %s DOWN.\n", s->id);
3131
willy tarreau9fe663a2005-12-17 13:02:59 +01003132 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003133 }
willy tarreauef900ab2005-12-17 12:52:52 +01003134
willy tarreau5cbea6f2005-12-17 12:48:26 +01003135 s->health = 0; /* failure */
3136 s->state &= ~SRV_RUNNING;
3137 }
3138
3139 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003140 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3141 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003142 }
3143 else {
3144 //fprintf(stderr, "process_chk: 8\n");
3145 /* there was a test running */
3146 if (s->result > 0) { /* good server detected */
3147 //fprintf(stderr, "process_chk: 9\n");
3148 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003149 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003150 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003151 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003152 Warning("server %s UP.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003153 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003154 }
willy tarreauef900ab2005-12-17 12:52:52 +01003155
willy tarreaue47c8d72005-12-17 12:55:52 +01003156 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003157 s->state |= SRV_RUNNING;
3158 }
willy tarreauef900ab2005-12-17 12:52:52 +01003159 s->curfd = -1; /* no check running anymore */
3160 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003161 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003162 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003163 }
3164 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3165 //fprintf(stderr, "process_chk: 10\n");
3166 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003167 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003168 s->health--; /* still good */
3169 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003170 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003171 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003172 Warning("server %s DOWN.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003173
3174 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003175 }
willy tarreauef900ab2005-12-17 12:52:52 +01003176
willy tarreau5cbea6f2005-12-17 12:48:26 +01003177 s->health = 0; /* failure */
3178 s->state &= ~SRV_RUNNING;
3179 }
3180 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003181 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003182 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003183 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003184 }
3185 /* if result is 0 and there's no timeout, we have to wait again */
3186 }
3187 //fprintf(stderr, "process_chk: 11\n");
3188 s->result = 0;
3189 task_queue(t); /* restore t to its place in the task list */
3190 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003191}
3192
3193
willy tarreau5cbea6f2005-12-17 12:48:26 +01003194
willy tarreau0f7af912005-12-17 12:21:26 +01003195#if STATTIME > 0
3196int stats(void);
3197#endif
3198
3199/*
3200 * Main select() loop.
3201 */
3202
3203void select_loop() {
3204 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003205 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003206 int status;
3207 int fd,i;
3208 struct timeval delta;
3209 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003210 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003211
willy tarreau5cbea6f2005-12-17 12:48:26 +01003212 tv_now(&now);
3213
3214 while (1) {
3215 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003216
willy tarreau5cbea6f2005-12-17 12:48:26 +01003217 /* look for expired tasks and add them to the run queue.
3218 */
3219 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3220 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3221 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003222 if (t->state & TASK_RUNNING)
3223 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003224
3225 /* wakeup expired entries. It doesn't matter if they are
3226 * already running because of a previous event
3227 */
3228 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003229 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003230 task_wakeup(&rq, t);
3231 }
3232 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003233 /* first non-runnable task. Use its expiration date as an upper bound */
3234 int temp_time = tv_remain(&now, &t->expire);
3235 if (temp_time)
3236 next_time = temp_time;
3237 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003238 break;
3239 }
3240 }
3241
3242 /* process each task in the run queue now. Each task may be deleted
3243 * since we only use tnext.
3244 */
3245 tnext = rq;
3246 while ((t = tnext) != NULL) {
3247 int temp_time;
3248
3249 tnext = t->rqnext;
3250 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003251 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003252 temp_time = t->process(t);
3253 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003254 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003255 }
3256
willy tarreauef900ab2005-12-17 12:52:52 +01003257 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003258
3259 /* maintain all proxies in a consistent state. This should quickly become a task */
3260 time2 = maintain_proxies();
3261 next_time = MINTIME(time2, next_time);
3262
3263 /* stop when there's no connection left and we don't allow them anymore */
3264 if (!actconn && listeners == 0)
3265 break;
3266
willy tarreau0f7af912005-12-17 12:21:26 +01003267
3268#if STATTIME > 0
3269 time2 = stats();
3270 // fprintf(stderr," stats = %d\n", time2);
3271 next_time = MINTIME(time2, next_time);
3272#endif
3273
willy tarreau5cbea6f2005-12-17 12:48:26 +01003274 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003275 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003276 /* to avoid eventual select loops due to timer precision */
3277 next_time += SCHEDULER_RESOLUTION;
3278 delta.tv_sec = next_time / 1000;
3279 delta.tv_usec = (next_time % 1000) * 1000;
3280 }
3281 else if (next_time == 0) { /* allow select to return immediately when needed */
3282 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003283 }
3284
3285
3286 /* let's restore fdset state */
3287
3288 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003289 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003290 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3291 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3292 }
3293
3294// /* just a verification code, needs to be removed for performance */
3295// for (i=0; i<maxfd; i++) {
3296// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3297// abort();
3298// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3299// abort();
3300//
3301// }
3302
3303 status=select(maxfd,
3304 readnotnull ? ReadEvent : NULL,
3305 writenotnull ? WriteEvent : NULL,
3306 NULL,
3307 (next_time >= 0) ? &delta : NULL);
3308
willy tarreau5cbea6f2005-12-17 12:48:26 +01003309 /* this is an experiment on the separation of the select work */
3310 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3311 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3312
willy tarreau0f7af912005-12-17 12:21:26 +01003313 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003314
willy tarreau0f7af912005-12-17 12:21:26 +01003315 if (status > 0) { /* must proceed with events */
3316
3317 int fds;
3318 char count;
3319
3320 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3321 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3322 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3323
willy tarreau5cbea6f2005-12-17 12:48:26 +01003324 /* if we specify read first, the accepts and zero reads will be
3325 * seen first. Moreover, system buffers will be flushed faster.
3326 */
willy tarreau0f7af912005-12-17 12:21:26 +01003327 if (fdtab[fd].state == FD_STCLOSE)
3328 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003329
3330 if (FD_ISSET(fd, ReadEvent))
3331 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003332
willy tarreau5cbea6f2005-12-17 12:48:26 +01003333 if (FD_ISSET(fd, WriteEvent))
3334 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003335 }
3336 }
3337 else {
3338 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3339 }
willy tarreau0f7af912005-12-17 12:21:26 +01003340 }
3341}
3342
3343
3344#if STATTIME > 0
3345/*
3346 * Display proxy statistics regularly. It is designed to be called from the
3347 * select_loop().
3348 */
3349int stats(void) {
3350 static int lines;
3351 static struct timeval nextevt;
3352 static struct timeval lastevt;
3353 static struct timeval starttime = {0,0};
3354 unsigned long totaltime, deltatime;
3355 int ret;
3356
3357 if (tv_remain(&now, &nextevt) == 0) {
3358 deltatime = (tv_delta(&now, &lastevt)?:1);
3359 totaltime = (tv_delta(&now, &starttime)?:1);
3360
willy tarreau9fe663a2005-12-17 13:02:59 +01003361 if (global.mode & MODE_STATS) {
3362 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003363 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003364 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3365 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003366 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003367 actconn, totalconn,
3368 stats_tsk_new, stats_tsk_good,
3369 stats_tsk_left, stats_tsk_right,
3370 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3371 }
3372 }
3373
3374 tv_delayfrom(&nextevt, &now, STATTIME);
3375
3376 lastevt=now;
3377 }
3378 ret = tv_remain(&now, &nextevt);
3379 return ret;
3380}
3381#endif
3382
3383
3384/*
3385 * this function enables proxies when there are enough free sessions,
3386 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003387 * select_loop(). It returns the time left before next expiration event
3388 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003389 */
3390static int maintain_proxies(void) {
3391 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003392 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003393
3394 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003395 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003396
3397 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003398 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003399 while (p) {
3400 if (p->nbconn < p->maxconn) {
3401 if (p->state == PR_STIDLE) {
3402 FD_SET(p->listen_fd, StaticReadEvent);
3403 p->state = PR_STRUN;
3404 }
3405 }
3406 else {
3407 if (p->state == PR_STRUN) {
3408 FD_CLR(p->listen_fd, StaticReadEvent);
3409 p->state = PR_STIDLE;
3410 }
3411 }
3412 p = p->next;
3413 }
3414 }
3415 else { /* block all proxies */
3416 while (p) {
3417 if (p->state == PR_STRUN) {
3418 FD_CLR(p->listen_fd, StaticReadEvent);
3419 p->state = PR_STIDLE;
3420 }
3421 p = p->next;
3422 }
3423 }
3424
willy tarreau5cbea6f2005-12-17 12:48:26 +01003425 if (stopping) {
3426 p = proxy;
3427 while (p) {
3428 if (p->state != PR_STDISABLED) {
3429 int t;
3430 t = tv_remain(&now, &p->stop_time);
3431 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003432 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003433 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003434
willy tarreau5cbea6f2005-12-17 12:48:26 +01003435 fd_delete(p->listen_fd);
3436 p->state = PR_STDISABLED;
3437 listeners--;
3438 }
3439 else {
3440 tleft = MINTIME(t, tleft);
3441 }
3442 }
3443 p = p->next;
3444 }
3445 }
3446 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003447}
3448
3449/*
3450 * this function disables health-check servers so that the process will quickly be ignored
3451 * by load balancers.
3452 */
3453static void soft_stop(void) {
3454 struct proxy *p;
3455
3456 stopping = 1;
3457 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003458 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003459 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003460 if (p->state != PR_STDISABLED) {
3461 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01003462 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01003463 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01003464 }
willy tarreau0f7af912005-12-17 12:21:26 +01003465 p = p->next;
3466 }
3467}
3468
3469/*
3470 * upon SIGUSR1, let's have a soft stop.
3471 */
3472void sig_soft_stop(int sig) {
3473 soft_stop();
3474 signal(sig, SIG_IGN);
3475}
3476
3477
3478void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003479 struct task *t, *tnext;
3480 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003481
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3483 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3484 tnext = t->next;
3485 s = t->context;
3486 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3487 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3488 "req=%d, rep=%d, clifd=%d\n",
3489 s, tv_remain(&now, &t->expire),
3490 s->cli_state,
3491 s->srv_state,
3492 FD_ISSET(s->cli_fd, StaticReadEvent),
3493 FD_ISSET(s->cli_fd, StaticWriteEvent),
3494 FD_ISSET(s->srv_fd, StaticReadEvent),
3495 FD_ISSET(s->srv_fd, StaticWriteEvent),
3496 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3497 );
willy tarreau0f7af912005-12-17 12:21:26 +01003498 }
3499}
3500
willy tarreaue39cd132005-12-17 13:00:18 +01003501void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
3502 struct hdr_exp *exp;
3503
3504 while (*head != NULL)
3505 head = &(*head)->next;
3506
3507 exp = calloc(1, sizeof(struct hdr_exp));
3508
3509 exp->preg = preg;
3510 exp->replace = replace;
3511 exp->action = action;
3512 *head = exp;
3513}
3514
willy tarreau9fe663a2005-12-17 13:02:59 +01003515
willy tarreau0f7af912005-12-17 12:21:26 +01003516/*
willy tarreau9fe663a2005-12-17 13:02:59 +01003517 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01003518 */
willy tarreau9fe663a2005-12-17 13:02:59 +01003519int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01003520
willy tarreau9fe663a2005-12-17 13:02:59 +01003521 if (!strcmp(args[0], "global")) { /* new section */
3522 /* no option, nothing special to do */
3523 return 0;
3524 }
3525 else if (!strcmp(args[0], "daemon")) {
3526 global.mode |= MODE_DAEMON;
3527 }
3528 else if (!strcmp(args[0], "debug")) {
3529 global.mode |= MODE_DEBUG;
3530 }
3531 else if (!strcmp(args[0], "quiet")) {
3532 global.mode |= MODE_QUIET;
3533 }
3534 else if (!strcmp(args[0], "stats")) {
3535 global.mode |= MODE_STATS;
3536 }
3537 else if (!strcmp(args[0], "uid")) {
3538 if (global.uid != 0) {
3539 Alert("parsing [%s:%d] : <uid> already specified. Continuing.\n", file, linenum);
3540 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003541 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003542 if (*(args[1]) == 0) {
3543 Alert("parsing [%s:%d] : <uid> expects an integer argument.\n", file, linenum);
3544 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003545 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003546 global.uid = atol(args[1]);
3547 }
3548 else if (!strcmp(args[0], "gid")) {
3549 if (global.gid != 0) {
3550 Alert("parsing [%s:%d] : <gid> already specified. Continuing.\n", file, linenum);
3551 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003552 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003553 if (*(args[1]) == 0) {
3554 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003555 return -1;
3556 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003557 global.gid = atol(args[1]);
3558 }
3559 else if (!strcmp(args[0], "nbproc")) {
3560 if (global.nbproc != 0) {
3561 Alert("parsing [%s:%d] : <nbproc> already specified. Continuing.\n", file, linenum);
3562 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003563 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003564 if (*(args[1]) == 0) {
3565 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
3566 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003567 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003568 global.nbproc = atol(args[1]);
3569 }
3570 else if (!strcmp(args[0], "maxconn")) {
3571 if (global.maxconn != 0) {
3572 Alert("parsing [%s:%d] : <maxconn> already specified. Continuing.\n", file, linenum);
3573 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003574 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003575 if (*(args[1]) == 0) {
3576 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3577 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003578 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003579 global.maxconn = atol(args[1]);
3580 }
3581 else if (!strcmp(args[0], "chroot")) {
3582 if (global.chroot != NULL) {
3583 Alert("parsing [%s:%d] : <chroot> already specified. Continuing.\n", file, linenum);
3584 return 0;
3585 }
3586 if (*(args[1]) == 0) {
3587 Alert("parsing [%s:%d] : <chroot> expects a directory as an argument.\n", file, linenum);
3588 return -1;
3589 }
3590 global.chroot = strdup(args[1]);
3591 }
3592 else if (!strcmp(args[0], "log")) { /* syslog server address */
3593 struct sockaddr_in *sa;
3594 int facility;
3595
3596 if (*(args[1]) == 0 || *(args[2]) == 0) {
3597 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n", file, linenum);
3598 return -1;
3599 }
3600
3601 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3602 if (!strcmp(log_facilities[facility], args[2]))
3603 break;
3604
3605 if (facility >= NB_LOG_FACILITIES) {
3606 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3607 exit(1);
3608 }
3609
3610 sa = str2sa(args[1]);
3611 if (!sa->sin_port)
3612 sa->sin_port = htons(SYSLOG_PORT);
3613
3614 if (global.logfac1 == -1) {
3615 global.logsrv1 = *sa;
3616 global.logfac1 = facility;
3617 }
3618 else if (global.logfac2 == -1) {
3619 global.logsrv2 = *sa;
3620 global.logfac2 = facility;
3621 }
3622 else {
3623 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3624 return -1;
3625 }
3626
3627 }
3628 else {
3629 Alert("parsing [%s:%d] : unknown keyword <%s> in <global> section\n", file, linenum, args[0]);
3630 return -1;
3631 }
3632 return 0;
3633}
3634
3635
3636/*
3637 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
3638 */
3639int cfg_parse_listen(char *file, int linenum, char **args) {
3640 static struct proxy *curproxy = NULL;
3641 struct server *newsrv = NULL;
3642
3643 if (!strcmp(args[0], "listen")) { /* new proxy */
3644 if (strchr(args[2], ':') == NULL) {
3645 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3646 file, linenum);
3647 return -1;
3648 }
3649
3650 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
3651 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3652 return -1;
3653 }
3654 curproxy->next = proxy;
3655 proxy = curproxy;
3656 curproxy->id = strdup(args[1]);
3657 curproxy->listen_addr = *str2sa(args[2]);
3658 curproxy->state = PR_STNEW;
3659 /* set default values */
3660 curproxy->maxconn = cfg_maxpconn;
3661 curproxy->conn_retries = CONN_RETRIES;
3662 curproxy->options = 0;
3663 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3664 curproxy->mode = PR_MODE_TCP;
3665 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3666 curproxy->to_log = 0;
3667 return 0;
3668 }
3669 else if (curproxy == NULL) {
3670 Alert("parsing [%s:%d] : <listen> expected.\n", file, linenum);
3671 return -1;
3672 }
3673
3674 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3675 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3676 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3677 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3678 else {
3679 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3680 return -1;
3681 }
3682 }
3683 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3684 curproxy->state = PR_STDISABLED;
3685 }
3686 else if (!strcmp(args[0], "cookie")) { /* cookie name */
3687 int cur_arg;
3688 if (curproxy->cookie_name != NULL) {
3689 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3690 file, linenum);
3691 return 0;
3692 }
3693
3694 if (*(args[1]) == 0) {
3695 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3696 file, linenum);
3697 return -1;
3698 }
3699 curproxy->cookie_name = strdup(args[1]);
3700
3701 cur_arg = 2;
3702 while (*(args[cur_arg])) {
3703 if (!strcmp(args[cur_arg], "rewrite")) {
3704 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01003705 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003706 else if (!strcmp(args[cur_arg], "indirect")) {
3707 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01003708 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003709 else if (!strcmp(args[cur_arg], "insert")) {
3710 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01003711 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003712 else {
3713 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003714 file, linenum);
3715 return -1;
3716 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003717 cur_arg++;
3718 }
3719 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3720 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3721 file, linenum);
3722 return -1;
3723 }
3724 }
3725 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3726 if (curproxy->contimeout != 0) {
3727 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n", file, linenum);
3728 return 0;
3729 }
3730 if (*(args[1]) == 0) {
3731 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3732 file, linenum);
3733 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003734 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003735 curproxy->contimeout = atol(args[1]);
3736 }
3737 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3738 if (curproxy->clitimeout != 0) {
3739 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3740 file, linenum);
3741 return 0;
3742 }
3743 if (*(args[1]) == 0) {
3744 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3745 file, linenum);
3746 return -1;
3747 }
3748 curproxy->clitimeout = atol(args[1]);
3749 }
3750 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3751 if (curproxy->srvtimeout != 0) {
3752 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n", file, linenum);
3753 return 0;
3754 }
3755 if (*(args[1]) == 0) {
3756 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003757 file, linenum);
3758 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003759 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003760 curproxy->srvtimeout = atol(args[1]);
3761 }
3762 else if (!strcmp(args[0], "retries")) { /* connection retries */
3763 if (*(args[1]) == 0) {
3764 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3765 file, linenum);
3766 return -1;
3767 }
3768 curproxy->conn_retries = atol(args[1]);
3769 }
3770 else if (!strcmp(args[0], "option")) {
3771 if (*(args[1]) == 0) {
3772 Alert("parsing [%s:%d] : <option> expects an option name.\n", file, linenum);
3773 return -1;
3774 }
3775 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003776 /* enable reconnections to dispatch */
3777 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01003778#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003779 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003780 /* enable transparent proxy connections */
3781 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01003782#endif
3783 else if (!strcmp(args[1], "keepalive"))
3784 /* enable keep-alive */
3785 curproxy->options |= PR_O_KEEPALIVE;
3786 else if (!strcmp(args[1], "forwardfor"))
3787 /* insert x-forwarded-for field */
3788 curproxy->options |= PR_O_FWDFOR;
3789 else if (!strcmp(args[1], "httplog")) {
3790 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01003791 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
3792 }
3793 else if (!strcmp(args[1], "dontlognull")) {
3794 /* don't log empty requests */
3795 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003796 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003797 else {
3798 Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
3799 return -1;
3800 }
3801 return 0;
3802 }
3803 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3804 /* enable reconnections to dispatch */
3805 curproxy->options |= PR_O_REDISP;
3806 }
willy tarreaua1598082005-12-17 13:08:06 +01003807#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003808 else if (!strcmp(args[0], "transparent")) {
3809 /* enable transparent proxy connections */
3810 curproxy->options |= PR_O_TRANSP;
3811 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003812#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01003813 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3814 if (*(args[1]) == 0) {
3815 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3816 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003817 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003818 curproxy->maxconn = atol(args[1]);
3819 }
3820 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3821 if (*(args[1]) == 0) {
3822 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n", file, linenum);
3823 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003824 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003825 curproxy->grace = atol(args[1]);
3826 }
3827 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3828 if (strchr(args[1], ':') == NULL) {
3829 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n", file, linenum);
3830 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003831 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003832 curproxy->dispatch_addr = *str2sa(args[1]);
3833 }
3834 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
3835 if (*(args[1])) {
3836 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003837 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01003838 }
3839 else {
3840 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n", file, linenum);
3841 return -1;
3842 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003843 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003844 else /* if no option is set, use round-robin by default */
3845 curproxy->options |= PR_O_BALANCE_RR;
3846 }
3847 else if (!strcmp(args[0], "server")) { /* server address */
3848 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003849
willy tarreau9fe663a2005-12-17 13:02:59 +01003850 if (strchr(args[2], ':') == NULL) {
3851 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
3852 file, linenum);
3853 return -1;
3854 }
3855 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
3856 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3857 return -1;
3858 }
3859 newsrv->next = curproxy->srv;
3860 curproxy->srv = newsrv;
3861 newsrv->proxy = curproxy;
3862 newsrv->id = strdup(args[1]);
3863 newsrv->addr = *str2sa(args[2]);
3864 newsrv->state = SRV_RUNNING; /* early server setup */
3865 newsrv->curfd = -1; /* no health-check in progress */
3866 newsrv->inter = DEF_CHKINTR;
3867 newsrv->rise = DEF_RISETIME;
3868 newsrv->fall = DEF_FALLTIME;
3869 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
3870 cur_arg = 3;
3871 while (*args[cur_arg]) {
3872 if (!strcmp(args[cur_arg], "cookie")) {
3873 newsrv->cookie = strdup(args[cur_arg + 1]);
3874 newsrv->cklen = strlen(args[cur_arg + 1]);
3875 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01003876 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003877 else if (!strcmp(args[cur_arg], "rise")) {
3878 newsrv->rise = atol(args[cur_arg + 1]);
3879 newsrv->health = newsrv->rise;
3880 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01003881 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003882 else if (!strcmp(args[cur_arg], "fall")) {
3883 newsrv->fall = atol(args[cur_arg + 1]);
3884 cur_arg += 2;
3885 }
3886 else if (!strcmp(args[cur_arg], "inter")) {
3887 newsrv->inter = atol(args[cur_arg + 1]);
3888 cur_arg += 2;
3889 }
3890 else if (!strcmp(args[cur_arg], "check")) {
3891 struct task *t;
3892
3893 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3894 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003895 return -1;
3896 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003897
3898 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
3899 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
3900 t->state = TASK_IDLE;
3901 t->process = process_chk;
3902 t->context = newsrv;
3903
3904 if (curproxy->state != PR_STDISABLED) {
3905 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
3906 task_queue(t);
3907 task_wakeup(&rq, t);
3908 }
3909
3910 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003911 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003912 else {
3913 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
3914 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01003915 return -1;
3916 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003917 }
3918 curproxy->nbservers++;
3919 }
3920 else if (!strcmp(args[0], "log")) { /* syslog server address */
3921 struct sockaddr_in *sa;
3922 int facility;
3923
3924 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
3925 curproxy->logfac1 = global.logfac1;
3926 curproxy->logsrv1 = global.logsrv1;
3927 curproxy->logfac2 = global.logfac2;
3928 curproxy->logsrv2 = global.logsrv2;
3929 }
3930 else if (*(args[1]) && *(args[2])) {
willy tarreau0f7af912005-12-17 12:21:26 +01003931 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3932 if (!strcmp(log_facilities[facility], args[2]))
3933 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01003934
willy tarreau0f7af912005-12-17 12:21:26 +01003935 if (facility >= NB_LOG_FACILITIES) {
3936 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3937 exit(1);
3938 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003939
willy tarreau0f7af912005-12-17 12:21:26 +01003940 sa = str2sa(args[1]);
3941 if (!sa->sin_port)
3942 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01003943
willy tarreau0f7af912005-12-17 12:21:26 +01003944 if (curproxy->logfac1 == -1) {
3945 curproxy->logsrv1 = *sa;
3946 curproxy->logfac1 = facility;
3947 }
3948 else if (curproxy->logfac2 == -1) {
3949 curproxy->logsrv2 = *sa;
3950 curproxy->logfac2 = facility;
3951 }
3952 else {
3953 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01003954 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003955 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003956 }
3957 else {
3958 Alert("parsing [%s:%d] : <log> expects either <address[:port]> and <facility> or 'global' as arguments.\n",
3959 file, linenum);
3960 return -1;
3961 }
3962 }
willy tarreaua1598082005-12-17 13:08:06 +01003963 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
3964 if (strchr(args[1], ':') == NULL) {
3965 Alert("parsing [%s:%d] : <source> expects <addr:port> as argument.\n",
3966 file, linenum);
3967 return -1;
3968 }
3969
3970 curproxy->source_addr = *str2sa(args[1]);
3971 curproxy->options |= PR_O_BIND_SRC;
3972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003973 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
3974 regex_t *preg;
3975
3976 if (*(args[1]) == 0 || *(args[2]) == 0) {
3977 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
3978 file, linenum);
3979 return -1;
3980 }
3981
3982 preg = calloc(1, sizeof(regex_t));
3983 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3984 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3985 return -1;
3986 }
3987
3988 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
3989 }
3990 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
3991 regex_t *preg;
3992
3993 if (*(args[1]) == 0) {
3994 Alert("parsing [%s:%d] : <reqdel> expects <regex> as an argument.\n", file, linenum);
3995 return -1;
3996 }
3997
3998 preg = calloc(1, sizeof(regex_t));
3999 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4000 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4001 return -1;
4002 }
4003
4004 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4005 }
4006 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
4007 regex_t *preg;
4008
4009 if (*(args[1]) == 0) {
4010 Alert("parsing [%s:%d] : <reqdeny> expects <regex> as an argument.\n", file, linenum);
4011 return -1;
4012 }
4013
4014 preg = calloc(1, sizeof(regex_t));
4015 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4016 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4017 return -1;
4018 }
4019
4020 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4021 }
4022 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4023 regex_t *preg;
4024
4025 if (*(args[1]) == 0) {
4026 Alert("parsing [%s:%d] : <reqallow> expects <regex> as an argument.\n", file, linenum);
4027 return -1;
4028 }
4029
4030 preg = calloc(1, sizeof(regex_t));
4031 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4032 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4033 return -1;
4034 }
4035
4036 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4037 }
4038 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4039 regex_t *preg;
4040
4041 if (*(args[1]) == 0 || *(args[2]) == 0) {
4042 Alert("parsing [%s:%d] : <reqirep> expects <search> and <replace> as arguments.\n",
4043 file, linenum);
4044 return -1;
4045 }
4046
4047 preg = calloc(1, sizeof(regex_t));
4048 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4049 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4050 return -1;
4051 }
4052
4053 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4054 }
4055 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4056 regex_t *preg;
4057
4058 if (*(args[1]) == 0) {
4059 Alert("parsing [%s:%d] : <reqidel> expects <regex> as an argument.\n", file, linenum);
4060 return -1;
4061 }
4062
4063 preg = calloc(1, sizeof(regex_t));
4064 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4065 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4066 return -1;
4067 }
4068
4069 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4070 }
4071 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4072 regex_t *preg;
4073
4074 if (*(args[1]) == 0) {
4075 Alert("parsing [%s:%d] : <reqideny> expects <regex> as an argument.\n", file, linenum);
4076 return -1;
4077 }
4078
4079 preg = calloc(1, sizeof(regex_t));
4080 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4081 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4082 return -1;
4083 }
4084
4085 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4086 }
4087 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4088 regex_t *preg;
4089
4090 if (*(args[1]) == 0) {
4091 Alert("parsing [%s:%d] : <reqiallow> expects <regex> as an argument.\n", file, linenum);
4092 return -1;
4093 }
4094
4095 preg = calloc(1, sizeof(regex_t));
4096 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4097 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4098 return -1;
4099 }
4100
4101 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4102 }
4103 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4104 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
4105 Alert("parsing [%s:%d] : too many `reqadd'. Continuing.\n", file, linenum);
4106 return 0;
4107 }
4108
4109 if (*(args[1]) == 0) {
4110 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n", file, linenum);
4111 return -1;
4112 }
4113
4114 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004115 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004116 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004117 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004118
4119 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004120 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004121 file, linenum);
4122 return -1;
4123 }
4124
4125 preg = calloc(1, sizeof(regex_t));
4126 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4127 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4128 return -1;
4129 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004130
4131 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4132 }
4133 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4134 regex_t *preg;
4135
4136 if (*(args[1]) == 0) {
4137 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n", file, linenum);
4138 return -1;
4139 }
willy tarreaue39cd132005-12-17 13:00:18 +01004140
willy tarreau9fe663a2005-12-17 13:02:59 +01004141 preg = calloc(1, sizeof(regex_t));
4142 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4143 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4144 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004145 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004146
4147 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4148 }
4149 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004150 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004151
willy tarreau9fe663a2005-12-17 13:02:59 +01004152 if (*(args[1]) == 0 || *(args[2]) == 0) {
4153 Alert("parsing [%s:%d] : <rspirep> expects <search> and <replace> as arguments.\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01004154 file, linenum);
willy tarreaue39cd132005-12-17 13:00:18 +01004155 return -1;
4156 }
4157
4158 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004159 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreaue39cd132005-12-17 13:00:18 +01004160 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4161 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004162 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004163
4164 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4165 }
4166 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4167 regex_t *preg;
4168
4169 if (*(args[1]) == 0) {
4170 Alert("parsing [%s:%d] : <rspidel> expects <search> as an argument.\n", file, linenum);
4171 return -1;
4172 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004173
willy tarreau9fe663a2005-12-17 13:02:59 +01004174 preg = calloc(1, sizeof(regex_t));
4175 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4176 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4177 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004178 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004179
4180 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4181 }
4182 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4183 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
4184 Alert("parsing [%s:%d] : too many `rspadd'. Continuing.\n", file, linenum);
4185 return 0;
4186 }
4187
4188 if (*(args[1]) == 0) {
4189 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n", file, linenum);
4190 return -1;
4191 }
4192
4193 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4194 }
4195 else {
4196 Alert("parsing [%s:%d] : unknown keyword <%s> in <listen> section\n", file, linenum, args[0]);
4197 return -1;
4198 }
4199 return 0;
4200}
willy tarreaue39cd132005-12-17 13:00:18 +01004201
willy tarreau5cbea6f2005-12-17 12:48:26 +01004202
willy tarreau9fe663a2005-12-17 13:02:59 +01004203/*
4204 * This function reads and parses the configuration file given in the argument.
4205 * returns 0 if OK, -1 if error.
4206 */
4207int readcfgfile(char *file) {
4208 char thisline[256];
4209 char *line;
4210 FILE *f;
4211 int linenum = 0;
4212 char *end;
4213 char *args[MAX_LINE_ARGS];
4214 int arg;
4215 int cfgerr = 0;
4216 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01004217
willy tarreau9fe663a2005-12-17 13:02:59 +01004218 struct proxy *curproxy = NULL;
4219 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01004220
willy tarreau9fe663a2005-12-17 13:02:59 +01004221 if ((f=fopen(file,"r")) == NULL)
4222 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004223
willy tarreau9fe663a2005-12-17 13:02:59 +01004224 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
4225 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004226
willy tarreau9fe663a2005-12-17 13:02:59 +01004227 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004228
willy tarreau9fe663a2005-12-17 13:02:59 +01004229 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01004230 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01004231 line++;
4232
4233 arg = 0;
4234 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01004235
willy tarreau9fe663a2005-12-17 13:02:59 +01004236 while (*line && arg < MAX_LINE_ARGS) {
4237 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
4238 * C equivalent value. Other combinations left unchanged (eg: \1).
4239 */
4240 if (*line == '\\') {
4241 int skip = 0;
4242 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
4243 *line = line[1];
4244 skip = 1;
4245 }
4246 else if (line[1] == 'r') {
4247 *line = '\r';
4248 skip = 1;
4249 }
4250 else if (line[1] == 'n') {
4251 *line = '\n';
4252 skip = 1;
4253 }
4254 else if (line[1] == 't') {
4255 *line = '\t';
4256 skip = 1;
4257 }
4258 else if (line[1] == 'x' && (line + 3 < end )) {
4259 unsigned char hex1, hex2;
4260 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
4261 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4262 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4263 *line = (hex1<<4) + hex2;
4264 skip = 3;
4265 }
4266 if (skip) {
4267 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
4268 end -= skip;
4269 }
4270 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004271 }
willy tarreaua1598082005-12-17 13:08:06 +01004272 else if (*line == '#' || *line == '\n' || *line == '\r') {
4273 /* end of string, end of loop */
4274 *line = 0;
4275 break;
4276 }
willy tarreauc29948c2005-12-17 13:10:27 +01004277 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004278 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01004279 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01004280 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01004281 line++;
4282 args[++arg] = line;
4283 }
4284 else {
4285 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004286 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004287 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004288
willy tarreau9fe663a2005-12-17 13:02:59 +01004289 /* empty line */
4290 if (!**args)
4291 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01004292
willy tarreau9fe663a2005-12-17 13:02:59 +01004293 /* zero out remaining args */
4294 while (++arg < MAX_LINE_ARGS) {
4295 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004296 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004297
willy tarreau9fe663a2005-12-17 13:02:59 +01004298 if (!strcmp(args[0], "listen")) /* new proxy */
4299 confsect = CFG_LISTEN;
4300 else if (!strcmp(args[0], "global")) /* global config */
4301 confsect = CFG_GLOBAL;
4302 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004303
willy tarreau9fe663a2005-12-17 13:02:59 +01004304 switch (confsect) {
4305 case CFG_LISTEN:
4306 if (cfg_parse_listen(file, linenum, args) < 0)
4307 return -1;
4308 break;
4309 case CFG_GLOBAL:
4310 if (cfg_parse_global(file, linenum, args) < 0)
4311 return -1;
4312 break;
4313 default:
4314 Alert("parsing [%s:%d] : unknown keyword <%s> out of section.\n", file, linenum, args[0]);
4315 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004316 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004317
4318
willy tarreau0f7af912005-12-17 12:21:26 +01004319 }
4320 fclose(f);
4321
4322 /*
4323 * Now, check for the integrity of all that we have collected.
4324 */
4325
4326 if ((curproxy = proxy) == NULL) {
4327 Alert("parsing %s : no <listen> line. Nothing to do !\n",
4328 file);
4329 return -1;
4330 }
4331
4332 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01004333 if (curproxy->state == PR_STDISABLED) {
4334 curproxy = curproxy->next;
4335 continue;
4336 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004337 if ((curproxy->mode != PR_MODE_HEALTH) &&
4338 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01004339 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004340 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
4341 file, curproxy->id);
4342 cfgerr++;
4343 }
4344 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
4345 if (curproxy->options & PR_O_TRANSP) {
4346 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
4347 file, curproxy->id);
4348 cfgerr++;
4349 }
4350 else if (curproxy->srv == NULL) {
4351 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
4352 file, curproxy->id);
4353 cfgerr++;
4354 }
willy tarreaua1598082005-12-17 13:08:06 +01004355 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004356 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
4357 file, curproxy->id);
4358 }
4359 }
4360 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01004361 if (curproxy->cookie_name != NULL) {
4362 Warning("parsing %s : cookie will be ignored for listener %s.\n",
4363 file, curproxy->id);
4364 }
4365 if ((newsrv = curproxy->srv) != NULL) {
4366 Warning("parsing %s : servers will be ignored for listener %s.\n",
4367 file, curproxy->id);
4368 }
willy tarreaue39cd132005-12-17 13:00:18 +01004369 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004370 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
4371 file, curproxy->id);
4372 }
willy tarreaue39cd132005-12-17 13:00:18 +01004373 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004374 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
4375 file, curproxy->id);
4376 }
4377 }
4378 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
4379 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
4380 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
4381 file, curproxy->id);
4382 cfgerr++;
4383 }
4384 else {
4385 while (newsrv != NULL) {
4386 /* nothing to check for now */
4387 newsrv = newsrv->next;
4388 }
4389 }
4390 }
4391 curproxy = curproxy->next;
4392 }
4393 if (cfgerr > 0) {
4394 Alert("Errors found in configuration file, aborting.\n");
4395 return -1;
4396 }
4397 else
4398 return 0;
4399}
4400
4401
4402/*
4403 * This function initializes all the necessary variables. It only returns
4404 * if everything is OK. If something fails, it exits.
4405 */
4406void init(int argc, char **argv) {
4407 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01004408 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004409 char *old_argv = *argv;
4410 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01004411 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01004412
4413 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004414 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004415 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
4416 sizeof(int)*8);
4417 exit(1);
4418 }
4419
4420 pid = getpid();
4421 progname = *argv;
4422 while ((tmp = strchr(progname, '/')) != NULL)
4423 progname = tmp + 1;
4424
4425 argc--; argv++;
4426 while (argc > 0) {
4427 char *flag;
4428
4429 if (**argv == '-') {
4430 flag = *argv+1;
4431
4432 /* 1 arg */
4433 if (*flag == 'v') {
4434 display_version();
4435 exit(0);
4436 }
4437 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01004438 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01004439 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01004440 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004441 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01004442 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01004443#if STATTIME > 0
4444 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01004445 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01004446 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01004447 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01004448#endif
4449 else { /* >=2 args */
4450 argv++; argc--;
4451 if (argc == 0)
4452 usage(old_argv);
4453
4454 switch (*flag) {
4455 case 'n' : cfg_maxconn = atol(*argv); break;
4456 case 'N' : cfg_maxpconn = atol(*argv); break;
4457 case 'f' : cfg_cfgfile = *argv; break;
4458 default: usage(old_argv);
4459 }
4460 }
4461 }
4462 else
4463 usage(old_argv);
4464 argv++; argc--;
4465 }
4466
willy tarreau0f7af912005-12-17 12:21:26 +01004467 if (!cfg_cfgfile)
4468 usage(old_argv);
4469
4470 gethostname(hostname, MAX_HOSTNAME_LEN);
4471
4472 if (readcfgfile(cfg_cfgfile) < 0) {
4473 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
4474 exit(1);
4475 }
4476
willy tarreau9fe663a2005-12-17 13:02:59 +01004477 if (cfg_maxconn > 0)
4478 global.maxconn = cfg_maxconn;
4479
4480 if (global.maxconn == 0)
4481 global.maxconn = DEFAULT_MAXCONN;
4482
4483 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
4484
4485 if (arg_mode & MODE_DEBUG) {
4486 /* command line debug mode inhibits configuration mode */
4487 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4488 }
4489 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG));
4490
4491 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
4492 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
4493 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4494 }
4495
4496 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
4497 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
4498 global.nbproc = 1;
4499 }
4500
4501 if (global.nbproc < 1)
4502 global.nbproc = 1;
4503
willy tarreau0f7af912005-12-17 12:21:26 +01004504 ReadEvent = (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 WriteEvent = (fd_set *)calloc(1,
4508 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004509 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004510 StaticReadEvent = (fd_set *)calloc(1,
4511 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004512 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004513 StaticWriteEvent = (fd_set *)calloc(1,
4514 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004515 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004516
4517 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01004518 sizeof(struct fdtab) * (global.maxsock));
4519 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004520 fdtab[i].state = FD_STCLOSE;
4521 }
4522}
4523
4524/*
4525 * this function starts all the proxies. It returns 0 if OK, -1 if not.
4526 */
4527int start_proxies() {
4528 struct proxy *curproxy;
4529 int one = 1;
4530 int fd;
4531
4532 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
4533
4534 if (curproxy->state == PR_STDISABLED)
4535 continue;
4536
4537 if ((fd = curproxy->listen_fd =
4538 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
4539 Alert("cannot create listening socket for proxy %s. Aborting.\n",
4540 curproxy->id);
4541 return -1;
4542 }
4543
willy tarreau9fe663a2005-12-17 13:02:59 +01004544 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004545 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
4546 curproxy->id);
4547 close(fd);
4548 return -1;
4549 }
4550
willy tarreau0f7af912005-12-17 12:21:26 +01004551 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
4552 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
4553 (char *) &one, sizeof(one)) == -1)) {
4554 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
4555 curproxy->id);
4556 close(fd);
4557 return -1;
4558 }
4559
4560 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
4561 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
4562 curproxy->id);
4563 }
4564
4565 if (bind(fd,
4566 (struct sockaddr *)&curproxy->listen_addr,
4567 sizeof(curproxy->listen_addr)) == -1) {
4568 Alert("cannot bind socket for proxy %s. Aborting.\n",
4569 curproxy->id);
4570 close(fd);
4571 return -1;
4572 }
4573
4574 if (listen(fd, curproxy->maxconn) == -1) {
4575 Alert("cannot listen to socket for proxy %s. Aborting.\n",
4576 curproxy->id);
4577 close(fd);
4578 return -1;
4579 }
4580
4581 /* the function for the accept() event */
4582 fdtab[fd].read = &event_accept;
4583 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004584 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01004585 curproxy->state = PR_STRUN;
4586 fdtab[fd].state = FD_STLISTEN;
4587 FD_SET(fd, StaticReadEvent);
4588 fd_insert(fd);
4589 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01004590
willy tarreaua1598082005-12-17 13:08:06 +01004591 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004592
willy tarreau0f7af912005-12-17 12:21:26 +01004593 }
4594 return 0;
4595}
4596
4597
4598int main(int argc, char **argv) {
4599 init(argc, argv);
4600
willy tarreau9fe663a2005-12-17 13:02:59 +01004601 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01004602 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004603 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01004604 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01004605 }
4606
4607 signal(SIGQUIT, dump);
4608 signal(SIGUSR1, sig_soft_stop);
4609
4610 /* on very high loads, a sigpipe sometimes happen just between the
4611 * getsockopt() which tells "it's OK to write", and the following write :-(
4612 */
willy tarreau3242e862005-12-17 12:27:53 +01004613#ifndef MSG_NOSIGNAL
4614 signal(SIGPIPE, SIG_IGN);
4615#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004616
4617 if (start_proxies() < 0)
4618 exit(1);
4619
willy tarreau9fe663a2005-12-17 13:02:59 +01004620 /* open log files */
4621
4622 /* chroot if needed */
4623 if (global.chroot != NULL) {
4624 if (chroot(global.chroot) == -1) {
4625 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
4626 exit(1);
4627 }
4628 chdir("/");
4629 }
4630
4631 /* setgid / setuid */
4632 if (global.gid && setregid(global.gid, global.gid) == -1) {
4633 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
4634 exit(1);
4635 }
4636
4637 if (global.uid && setreuid(global.uid, global.uid) == -1) {
4638 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
4639 exit(1);
4640 }
4641
4642 if (global.mode & MODE_DAEMON) {
4643 int ret = 0;
4644 int proc;
4645
4646 /* the father launches the required number of processes */
4647 for (proc = 0; proc < global.nbproc; proc++) {
4648 ret = fork();
4649 if (ret < 0) {
4650 Alert("[%s.main()] Cannot fork.\n", argv[0]);
4651 exit(1); /* there has been an error */
4652 }
4653 else if (ret == 0) /* child breaks here */
4654 break;
4655 }
4656 if (proc == global.nbproc)
4657 exit(0); /* parent must leave */
4658
willy tarreaua1598082005-12-17 13:08:06 +01004659 pid = getpid(); /* update child's pid */
willy tarreau9fe663a2005-12-17 13:02:59 +01004660 setpgid(1, 0);
4661 }
4662
willy tarreau0f7af912005-12-17 12:21:26 +01004663 select_loop();
4664
4665 exit(0);
4666}
willy tarreaua1598082005-12-17 13:08:06 +01004667