blob: e34346098975845762a7acabf9947dde2caa4db8 [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 tarreau750a4722005-12-17 13:21:24 +010010 * Pending bugs (may be not fixed because not reproduced) :
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
willy tarreau8337c6b2005-12-17 13:41:01 +010014 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
15 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010016 * - 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 tarreau8337c6b2005-12-17 13:41:01 +010020 * 2002/10/18 : 1.1.17
21 * - add the notion of "backup" servers, which are used only when all other
22 * servers are down.
23 * - make Set-Cookie return "" instead of "(null)" when the server has no
24 * cookie assigned (useful for backup servers).
25 * - "log" now supports an optionnal level name (info, notice, err ...) above
26 * which nothing is sent.
27 * - replaced some strncmp() with memcmp() for better efficiency.
28 * - added "capture cookie" option which logs client and/or server cookies
29 * - cleaned up/down messages and dump servers states upon SIGHUP
30 * - added a redirection feature for errors : "errorloc <errnum> <url>"
31 * - now we won't insist on connecting to a dead server, even with a cookie,
32 * unless option "persist" is specified.
33 * - added HTTP/408 response for client request time-out and HTTP/50[234] for
34 * server reply time-out or errors.
willy tarreaubc4e1fb2005-12-17 13:32:07 +010035 * 2002/09/01 : 1.1.16
36 * - implement HTTP health checks when option "httpchk" is specified.
willy tarreaue867b482005-12-17 13:28:43 +010037 * 2002/08/07 : 1.1.15
38 * - replaced setpgid()/setpgrp() with setsid() for better portability, because
39 * setpgrp() doesn't have the same meaning under Solaris, Linux, and OpenBSD.
willy tarreaucd878942005-12-17 13:27:43 +010040 * 2002/07/20 : 1.1.14
41 * - added "postonly" cookie mode
willy tarreau6e682ce2005-12-17 13:26:49 +010042 * 2002/07/15 : 1.1.13
43 * - tv_diff used inverted parameters which led to negative times !
willy tarreaucd878942005-12-17 13:27:43 +010044 * 2002/07/13 : 1.1.12
willy tarreau750a4722005-12-17 13:21:24 +010045 * - fixed stats monitoring, and optimized some tv_* for most common cases.
46 * - replaced temporary 'newhdr' with 'trash' to reduce stack size
47 * - made HTTP errors more HTML-fiendly.
48 * - renamed strlcpy() to strlcpy2() because of a slightly difference between
49 * their behaviour (return value), to avoid confusion.
50 * - restricted HTTP messages to HTTP proxies only
51 * - added a 502 message when the connection has been refused by the server,
52 * to prevent clients from believing this is a zero-byte HTTP 0.9 reply.
53 * - changed 'Cache-control:' from 'no-cache="set-cookie"' to 'private' when
54 * inserting a cookie, because some caches (apache) don't understand it.
55 * - fixed processing of server headers when client is in SHUTR state
56 * 2002/07/04 :
57 * - automatically close fd's 0,1 and 2 when going daemon ; setpgrp() after
58 * setpgid()
willy tarreau240afa62005-12-17 13:14:35 +010059 * 2002/06/04 : 1.1.11
60 * - fixed multi-cookie handling in client request to allow clean deletion
61 * in insert+indirect mode. Now, only the server cookie is deleted and not
62 * all the header. Should now be compliant to RFC2109.
63 * - added a "nocache" option to "cookie" to specify that we explicitly want
64 * to add a "cache-control" header when we add a cookie.
65 * It is also possible to add an "Expires: <old-date>" to keep compatibility
66 * with old/broken caches.
willy tarreau96d40372005-12-17 13:11:56 +010067 * 2002/05/10 : 1.1.10
68 * - if a cookie is used in insert+indirect mode, it's desirable that the
69 * the servers don't see it. It was not possible to remove it correctly
70 * with regexps, so now it's removed automatically.
willy tarreauc29948c2005-12-17 13:10:27 +010071 * 2002/04/19 : 1.1.9
72 * - don't use snprintf()'s return value as an end of message since it may
73 * be larger. This caused bus errors and segfaults in internal libc's
74 * getenv() during localtime() in send_log().
75 * - removed dead insecure send_syslog() function and all references to it.
76 * - fixed warnings on Solaris due to buggy implementation of isXXXX().
willy tarreaua1598082005-12-17 13:08:06 +010077 * 2002/04/18 : 1.1.8
78 * - option "dontlognull"
79 * - fixed "double space" bug in config parser
80 * - fixed an uninitialized server field in case of dispatch
81 * with no existing server which could cause a segfault during
82 * logging.
83 * - the pid logged was always the father's, which was wrong for daemons.
84 * - fixed wrong level "LOG_INFO" for message "proxy started".
85 * 2002/04/13 :
86 * - http logging is now complete :
87 * - ip:port, date, proxy, server
88 * - req_time, conn_time, hdr_time, tot_time
89 * - status, size, request
90 * - source address
willy tarreau9fe663a2005-12-17 13:02:59 +010091 * 2002/04/12 : 1.1.7
92 * - added option forwardfor
93 * - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel
94 * - added "log global" in "listen" section.
95 * 2002/04/09 :
96 * - added a new "global" section :
97 * - logs
98 * - debug, quiet, daemon modes
99 * - uid, gid, chroot, nbproc, maxconn
willy tarreaue39cd132005-12-17 13:00:18 +0100100 * 2002/04/08 : 1.1.6
101 * - regex are now chained and not limited anymore.
102 * - unavailable server now returns HTTP/502.
103 * - increased per-line args limit to 40
104 * - added reqallow/reqdeny to block some request on matches
105 * - added HTTP 400/403 responses
106 * 2002/04/03 : 1.1.5
willy tarreau535ae7a2005-12-17 12:58:00 +0100107 * - connection logging displayed incorrect source address.
108 * - added proxy start/stop and server up/down log events.
109 * - replaced log message short buffers with larger trash.
110 * - enlarged buffer to 8 kB and replace buffer to 4 kB.
willy tarreaue39cd132005-12-17 13:00:18 +0100111 * 2002/03/25 : 1.1.4
willy tarreaue47c8d72005-12-17 12:55:52 +0100112 * - made rise/fall/interval time configurable
willy tarreaue39cd132005-12-17 13:00:18 +0100113 * 2002/03/22 : 1.1.3
willy tarreaub719f002005-12-17 12:55:07 +0100114 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
115 * which could lead to loops.
willy tarreaue39cd132005-12-17 13:00:18 +0100116 * 2002/03/21 : 1.1.2
willy tarreauef900ab2005-12-17 12:52:52 +0100117 * - fixed a bug in buffer management where we could have a loop
118 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
119 * => implemented an adjustable buffer limit.
120 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
121 * and running tasks are skipped.
122 * - added some debug lines for accept events.
123 * - send warnings for servers up/down.
willy tarreaue39cd132005-12-17 13:00:18 +0100124 * 2002/03/12 : 1.1.1
willy tarreauefae1842005-12-17 12:51:03 +0100125 * - fixed a bug in total failure handling
126 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreaue39cd132005-12-17 13:00:18 +0100127 * 2002/03/10 : 1.1.0
willy tarreau5cbea6f2005-12-17 12:48:26 +0100128 * - fixed a few timeout bugs
129 * - rearranged the task scheduler subsystem to improve performance,
130 * add new tasks, and make it easier to later port to librt ;
131 * - allow multiple accept() for one select() wake up ;
132 * - implemented internal load balancing with basic health-check ;
133 * - cookie insertion and header add/replace/delete, with better strings
134 * support.
135 * 2002/03/08
136 * - reworked buffer handling to fix a few rewrite bugs, and
137 * improve overall performance.
138 * - implement the "purge" option to delete server cookies in direct mode.
139 * 2002/03/07
140 * - fixed some error cases where the maxfd was not decreased.
141 * 2002/02/26
142 * - now supports transparent proxying, at least on linux 2.4.
143 * 2002/02/12
144 * - soft stop works again (fixed select timeout computation).
145 * - it seems that TCP proxies sometimes cannot timeout.
146 * - added a "quiet" mode.
147 * - enforce file descriptor limitation on socket() and accept().
148 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +0100149 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +0100150 * 2001/12/16 : release of version 1.0.0.
151 * 2001/12/16 : added syslog capability for each accepted connection.
152 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
153 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
154 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
155 * with or without cookies (use keyword http for this).
156 * 2001/09/01 : added client/server header replacing with regexps.
157 * eg:
158 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
159 * srvexp ^Server:\ .* Server:\ Apache
160 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
161 * 2000/11/28 : major rewrite
162 * 2000/11/26 : first write
163 *
willy tarreau5cbea6f2005-12-17 12:48:26 +0100164 * TODO:
165 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +0100166 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +0100167 *
168 */
169
170#include <stdio.h>
171#include <stdlib.h>
172#include <unistd.h>
173#include <string.h>
174#include <ctype.h>
175#include <sys/time.h>
176#include <sys/types.h>
177#include <sys/socket.h>
178#include <netinet/tcp.h>
179#include <netinet/in.h>
180#include <arpa/inet.h>
181#include <netdb.h>
182#include <fcntl.h>
183#include <errno.h>
184#include <signal.h>
185#include <stdarg.h>
186#include <sys/resource.h>
187#include <time.h>
188#include <regex.h>
189#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +0100190#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100191#include <linux/netfilter_ipv4.h>
192#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100193
willy tarreau8337c6b2005-12-17 13:41:01 +0100194#define HAPROXY_VERSION "1.1.17"
195#define HAPROXY_DATE "2002/10/18"
willy tarreau0f7af912005-12-17 12:21:26 +0100196
197/* this is for libc5 for example */
198#ifndef TCP_NODELAY
199#define TCP_NODELAY 1
200#endif
201
202#ifndef SHUT_RD
203#define SHUT_RD 0
204#endif
205
206#ifndef SHUT_WR
207#define SHUT_WR 1
208#endif
209
willy tarreau535ae7a2005-12-17 12:58:00 +0100210#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +0100211
212// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +0100213#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +0100214#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100215#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100216
willy tarreau5cbea6f2005-12-17 12:48:26 +0100217// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100218#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100219
willy tarreaue39cd132005-12-17 13:00:18 +0100220// max # of added headers per request
221#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100222
223// max # of matches per regexp
224#define MAX_MATCH 10
225
willy tarreau5cbea6f2005-12-17 12:48:26 +0100226/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100227#define COOKIENAME_LEN 16
228#define SERVERID_LEN 16
229#define CONN_RETRIES 3
230
willy tarreau5cbea6f2005-12-17 12:48:26 +0100231#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100232#define DEF_CHKINTR 2000
233#define DEF_FALLTIME 3
234#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100235
willy tarreau9fe663a2005-12-17 13:02:59 +0100236/* default connections limit */
237#define DEFAULT_MAXCONN 2000
238
willy tarreau0f7af912005-12-17 12:21:26 +0100239/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
240#define INTBITS 5
241
242/* show stats this every millisecond, 0 to disable */
243#ifndef STATTIME
244#define STATTIME 2000
245#endif
246
willy tarreau5cbea6f2005-12-17 12:48:26 +0100247/* this reduces the number of calls to select() by choosing appropriate
248 * sheduler precision in milliseconds. It should be near the minimum
249 * time that is needed by select() to collect all events. All timeouts
250 * are rounded up by adding this value prior to pass it to select().
251 */
252#define SCHEDULER_RESOLUTION 9
253
willy tarreau0f7af912005-12-17 12:21:26 +0100254#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
255#define SETNOW(a) (*a=now)
256
willy tarreau9da061b2005-12-17 12:29:56 +0100257/****** string-specific macros and functions ******/
258/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
259#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
260
261/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
262#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
263
willy tarreau9da061b2005-12-17 12:29:56 +0100264/*
265 * copies at most <size-1> chars from <src> to <dst>. Last char is always
266 * set to 0, unless <size> is 0. The number of chars copied is returned
267 * (excluding the terminating zero).
268 * This code has been optimized for size and speed : on x86, it's 45 bytes
269 * long, uses only registers, and consumes only 4 cycles per char.
270 */
willy tarreau750a4722005-12-17 13:21:24 +0100271int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100272 char *orig = dst;
273 if (size) {
274 while (--size && (*dst = *src)) {
275 src++; dst++;
276 }
277 *dst = 0;
278 }
279 return dst - orig;
280}
willy tarreau9da061b2005-12-17 12:29:56 +0100281
willy tarreau0f7af912005-12-17 12:21:26 +0100282#define MEM_OPTIM
283#ifdef MEM_OPTIM
284/*
285 * Returns a pointer to type <type> taken from the
286 * pool <pool_type> or dynamically allocated. In the
287 * first case, <pool_type> is updated to point to the
288 * next element in the list.
289 */
290#define pool_alloc(type) ({ \
291 void *p; \
292 if ((p = pool_##type) == NULL) \
293 p = malloc(sizeof_##type); \
294 else { \
295 pool_##type = *(void **)pool_##type; \
296 } \
297 p; \
298})
299
300/*
301 * Puts a memory area back to the corresponding pool.
302 * Items are chained directly through a pointer that
303 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100304 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100305 * that each memory area is at least as big as one
306 * pointer.
307 */
308#define pool_free(type, ptr) ({ \
309 *(void **)ptr = (void *)pool_##type; \
310 pool_##type = (void *)ptr; \
311})
312
313#else
314#define pool_alloc(type) (calloc(1,sizeof_##type));
315#define pool_free(type, ptr) (free(ptr));
316#endif /* MEM_OPTIM */
317
willy tarreau5cbea6f2005-12-17 12:48:26 +0100318#define sizeof_task sizeof(struct task)
319#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100320#define sizeof_buffer sizeof(struct buffer)
321#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100322#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100323#define sizeof_capture CAPTURE_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100324
willy tarreau5cbea6f2005-12-17 12:48:26 +0100325/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100326#define FD_STCLOSE 0
327#define FD_STLISTEN 1
328#define FD_STCONN 2
329#define FD_STREADY 3
330#define FD_STERROR 4
331
willy tarreau5cbea6f2005-12-17 12:48:26 +0100332/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100333#define TASK_IDLE 0
334#define TASK_RUNNING 1
335
willy tarreau5cbea6f2005-12-17 12:48:26 +0100336/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100337#define PR_STNEW 0
338#define PR_STIDLE 1
339#define PR_STRUN 2
340#define PR_STDISABLED 3
341
willy tarreau5cbea6f2005-12-17 12:48:26 +0100342/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100343#define PR_MODE_TCP 0
344#define PR_MODE_HTTP 1
345#define PR_MODE_HEALTH 2
346
willy tarreau5cbea6f2005-12-17 12:48:26 +0100347/* bits for proxy->options */
348#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
349#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
350#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
351#define PR_O_COOK_IND 8 /* keep only indirect cookies */
352#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
353#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
354#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
355#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100356#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
357#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100358#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
359#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100360#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100361#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100362#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
willy tarreau8337c6b2005-12-17 13:41:01 +0100363#define PR_O_PERSIST 8192 /* server persistence stays effective even when server is down */
willy tarreau9fe663a2005-12-17 13:02:59 +0100364
willy tarreau5cbea6f2005-12-17 12:48:26 +0100365
willy tarreaue39cd132005-12-17 13:00:18 +0100366/* various session flags */
367#define SN_DIRECT 1 /* connection made on the server matching the client cookie */
368#define SN_CLDENY 2 /* a client header matches a deny regex */
369#define SN_CLALLOW 4 /* a client header matches an allow regex */
370#define SN_SVDENY 8 /* a server header matches a deny regex */
371#define SN_SVALLOW 16 /* a server header matches an allow regex */
willy tarreaucd878942005-12-17 13:27:43 +0100372#define SN_POST 32 /* the request was an HTTP POST */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100373
374/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100375#define CL_STHEADERS 0
376#define CL_STDATA 1
377#define CL_STSHUTR 2
378#define CL_STSHUTW 3
379#define CL_STCLOSE 4
380
willy tarreau5cbea6f2005-12-17 12:48:26 +0100381/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100382#define SV_STIDLE 0
383#define SV_STCONN 1
384#define SV_STHEADERS 2
385#define SV_STDATA 3
386#define SV_STSHUTR 4
387#define SV_STSHUTW 5
388#define SV_STCLOSE 6
389
390/* result of an I/O event */
391#define RES_SILENT 0 /* didn't happen */
392#define RES_DATA 1 /* data were sent or received */
393#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
394#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
395
willy tarreau9fe663a2005-12-17 13:02:59 +0100396/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100397#define MODE_DEBUG 1
398#define MODE_STATS 2
399#define MODE_LOG 4
400#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100401#define MODE_QUIET 16
402
403/* server flags */
404#define SRV_RUNNING 1
willy tarreau8337c6b2005-12-17 13:41:01 +0100405#define SRV_BACKUP 2
willy tarreau0f7af912005-12-17 12:21:26 +0100406
willy tarreaue39cd132005-12-17 13:00:18 +0100407/* what to do when a header matches a regex */
408#define ACT_ALLOW 0 /* allow the request */
409#define ACT_REPLACE 1 /* replace the matching header */
410#define ACT_REMOVE 2 /* remove the matching header */
411#define ACT_DENY 3 /* deny the request */
412
willy tarreau9fe663a2005-12-17 13:02:59 +0100413/* configuration sections */
414#define CFG_NONE 0
415#define CFG_GLOBAL 1
416#define CFG_LISTEN 2
417
willy tarreaua1598082005-12-17 13:08:06 +0100418/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100419#define LW_DATE 1 /* date */
420#define LW_CLIP 2 /* CLient IP */
421#define LW_SVIP 4 /* SerVer IP */
422#define LW_SVID 8 /* server ID */
423#define LW_REQ 16 /* http REQuest */
424#define LW_RESP 32 /* http RESPonse */
425#define LW_PXIP 64 /* proxy IP */
426#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100427#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100428
willy tarreau0f7af912005-12-17 12:21:26 +0100429/*********************************************************************/
430
431#define LIST_HEAD(a) ((void *)(&(a)))
432
433/*********************************************************************/
434
435struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100436 struct hdr_exp *next;
437 regex_t *preg; /* expression to look for */
438 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
439 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100440};
441
442struct buffer {
443 unsigned int l; /* data length */
444 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100445 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100446 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100447 char data[BUFSIZE];
448};
449
450struct server {
451 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100452 int state; /* server state (SRV_*) */
453 int cklen; /* the len of the cookie, to speed up checks */
454 char *cookie; /* the id set in the cookie */
455 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100456 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100457 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100458 int rise, fall; /* time in iterations */
459 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100460 int result; /* 0 = connect OK, -1 = connect KO */
461 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100462 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100463};
464
willy tarreau5cbea6f2005-12-17 12:48:26 +0100465/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100466struct task {
467 struct task *next, *prev; /* chaining ... */
468 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100469 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100470 int state; /* task state : IDLE or RUNNING */
471 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100472 int (*process)(struct task *t); /* the function which processes the task */
473 void *context; /* the task's context */
474};
475
476/* WARNING: if new fields are added, they must be initialized in event_accept() */
477struct session {
478 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100479 /* application specific below */
480 struct timeval crexpire; /* expiration date for a client read */
481 struct timeval cwexpire; /* expiration date for a client write */
482 struct timeval srexpire; /* expiration date for a server read */
483 struct timeval swexpire; /* expiration date for a server write */
484 struct timeval cnexpire; /* expiration date for a connect */
485 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
486 struct proxy *proxy; /* the proxy this socket belongs to */
487 int cli_fd; /* the client side fd */
488 int srv_fd; /* the server side fd */
489 int cli_state; /* state of the client side */
490 int srv_state; /* state of the server side */
491 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100492 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100493 struct buffer *req; /* request buffer */
494 struct buffer *rep; /* response buffer */
495 struct sockaddr_in cli_addr; /* the client address */
496 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100497 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100498 struct {
499 int logwait; /* log fields waiting to be collected : LW_* */
500 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
501 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
502 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
503 long t_data; /* delay before the first data byte from the server ... */
504 unsigned long t_close; /* total session duration */
505 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100506 char *cli_cookie; /* cookie presented by the client, in capture mode */
507 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100508 int status; /* HTTP status from the server, negative if from proxy */
509 long long bytes; /* number of bytes transferred from the server */
510 } logs;
willy tarreau0f7af912005-12-17 12:21:26 +0100511};
512
513struct proxy {
514 int listen_fd; /* the listen socket */
515 int state; /* proxy state */
516 struct sockaddr_in listen_addr; /* the address we listen to */
517 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100518 struct server *srv, *cursrv; /* known servers, current server */
519 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100520 char *cookie_name; /* name of the cookie to look for */
willy tarreau8337c6b2005-12-17 13:41:01 +0100521 int cookie_len; /* strlen(cookie_len), computed only once */
522 char *capture_name; /* beginning of the name of the cookie to capture */
523 int capture_namelen; /* length of the cookie name to match */
524 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100525 int clitimeout; /* client I/O timeout (in milliseconds) */
526 int srvtimeout; /* server I/O timeout (in milliseconds) */
527 int contimeout; /* connect timeout (in milliseconds) */
528 char *id; /* proxy id */
529 int nbconn; /* # of active sessions */
530 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100531 int conn_retries; /* maximum number of connect retries */
532 int options; /* PR_O_REDISP, PR_O_TRANSP */
533 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100534 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100535 struct proxy *next;
536 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
537 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100538 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100539 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100540 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100541 int nb_reqadd, nb_rspadd;
542 struct hdr_exp *req_exp; /* regular expressions for request headers */
543 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
544 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100545 int grace; /* grace time after stop request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100546 struct {
547 char *msg400; /* message for error 400 */
548 int len400; /* message length for error 400 */
549 char *msg403; /* message for error 403 */
550 int len403; /* message length for error 403 */
551 char *msg408; /* message for error 408 */
552 int len408; /* message length for error 408 */
553 char *msg500; /* message for error 500 */
554 int len500; /* message length for error 500 */
555 char *msg502; /* message for error 502 */
556 int len502; /* message length for error 502 */
557 char *msg503; /* message for error 503 */
558 int len503; /* message length for error 503 */
559 char *msg504; /* message for error 504 */
560 int len504; /* message length for error 504 */
561 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100562};
563
564/* info about one given fd */
565struct fdtab {
566 int (*read)(int fd); /* read function */
567 int (*write)(int fd); /* write function */
568 struct task *owner; /* the session (or proxy) associated with this fd */
569 int state; /* the state of this fd */
570};
571
572/*********************************************************************/
573
willy tarreau0f7af912005-12-17 12:21:26 +0100574int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100575char *cfg_cfgfile = NULL; /* configuration file */
576char *progname = NULL; /* program name */
577int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100578
579/* global options */
580static struct {
581 int uid;
582 int gid;
583 int nbproc;
584 int maxconn;
585 int maxsock; /* max # of sockets */
586 int mode;
587 char *chroot;
588 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100589 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100590 struct sockaddr_in logsrv1, logsrv2;
591} global = {
592 logfac1 : -1,
593 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100594 loglev1 : 7, /* max syslog level : debug */
595 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100596 /* others NULL OK */
597};
598
willy tarreau0f7af912005-12-17 12:21:26 +0100599/*********************************************************************/
600
601fd_set *ReadEvent,
602 *WriteEvent,
603 *StaticReadEvent,
604 *StaticWriteEvent;
605
606void **pool_session = NULL,
607 **pool_buffer = NULL,
608 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100609 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100610 **pool_task = NULL,
611 **pool_capture = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100612
613struct proxy *proxy = NULL; /* list of all existing proxies */
614struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100615struct task *rq = NULL; /* global run queue */
616struct task wait_queue = { /* global wait queue */
617 prev:LIST_HEAD(wait_queue),
618 next:LIST_HEAD(wait_queue)
619};
willy tarreau0f7af912005-12-17 12:21:26 +0100620
willy tarreau0f7af912005-12-17 12:21:26 +0100621static int totalconn = 0; /* total # of terminated sessions */
622static int actconn = 0; /* # of active sessions */
623static int maxfd = 0; /* # of the highest fd + 1 */
624static int listeners = 0; /* # of listeners */
625static int stopping = 0; /* non zero means stopping in progress */
626static struct timeval now = {0,0}; /* the current date at any moment */
627
628static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100629/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100630static char trash[BUFSIZE];
631
632/*
633 * Syslog facilities and levels
634 */
635
636#define MAX_SYSLOG_LEN 1024
637#define NB_LOG_FACILITIES 24
638const char *log_facilities[NB_LOG_FACILITIES] = {
639 "kern", "user", "mail", "daemon",
640 "auth", "syslog", "lpr", "news",
641 "uucp", "cron", "auth2", "ftp",
642 "ntp", "audit", "alert", "cron2",
643 "local0", "local1", "local2", "local3",
644 "local4", "local5", "local6", "local7"
645};
646
647
648#define NB_LOG_LEVELS 8
649const char *log_levels[NB_LOG_LEVELS] = {
650 "emerg", "alert", "crit", "err",
651 "warning", "notice", "info", "debug"
652};
653
654#define SYSLOG_PORT 514
655
656const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
657 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
658#define MAX_HOSTNAME_LEN 32
659static char hostname[MAX_HOSTNAME_LEN] = "";
660
willy tarreau8337c6b2005-12-17 13:41:01 +0100661const char *HTTP_302 =
662 "HTTP/1.0 302 Found\r\n"
663 "Cache-Control: no-cache\r\n"
664 "Connection: close\r\n"
665 "Location: "; /* not terminated since it will be concatenated with the URL */
666
willy tarreaua1598082005-12-17 13:08:06 +0100667const char *HTTP_400 =
668 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100669 "Cache-Control: no-cache\r\n"
670 "Connection: close\r\n"
671 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100672 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100673
willy tarreaua1598082005-12-17 13:08:06 +0100674const char *HTTP_403 =
675 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100676 "Cache-Control: no-cache\r\n"
677 "Connection: close\r\n"
678 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100679 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
680
willy tarreau8337c6b2005-12-17 13:41:01 +0100681const char *HTTP_408 =
682 "HTTP/1.0 408 Request Time-out\r\n"
683 "Cache-Control: no-cache\r\n"
684 "Connection: close\r\n"
685 "\r\n"
686 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
687
willy tarreau750a4722005-12-17 13:21:24 +0100688const char *HTTP_500 =
689 "HTTP/1.0 500 Server Error\r\n"
690 "Cache-Control: no-cache\r\n"
691 "Connection: close\r\n"
692 "\r\n"
693 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100694
695const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100696 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100697 "Cache-Control: no-cache\r\n"
698 "Connection: close\r\n"
699 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100700 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
701
702const char *HTTP_503 =
703 "HTTP/1.0 503 Service Unavailable\r\n"
704 "Cache-Control: no-cache\r\n"
705 "Connection: close\r\n"
706 "\r\n"
707 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
708
709const char *HTTP_504 =
710 "HTTP/1.0 504 Gateway Time-out\r\n"
711 "Cache-Control: no-cache\r\n"
712 "Connection: close\r\n"
713 "\r\n"
714 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100715
willy tarreau0f7af912005-12-17 12:21:26 +0100716/*********************************************************************/
717/* statistics ******************************************************/
718/*********************************************************************/
719
willy tarreau750a4722005-12-17 13:21:24 +0100720#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100721static int stats_tsk_lsrch, stats_tsk_rsrch,
722 stats_tsk_good, stats_tsk_right, stats_tsk_left,
723 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100724#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100725
726
727/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100728/* debugging *******************************************************/
729/*********************************************************************/
730#ifdef DEBUG_FULL
731static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
732static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
733#endif
734
735/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100736/* function prototypes *********************************************/
737/*********************************************************************/
738
739int event_accept(int fd);
740int event_cli_read(int fd);
741int event_cli_write(int fd);
742int event_srv_read(int fd);
743int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100744int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100745
746/*********************************************************************/
747/* general purpose functions ***************************************/
748/*********************************************************************/
749
750void display_version() {
751 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100752 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100753}
754
755/*
756 * This function prints the command line usage and exits
757 */
758void usage(char *name) {
759 display_version();
760 fprintf(stderr,
761 "Usage : %s -f <cfgfile> [ -vd"
762#if STATTIME > 0
763 "sl"
764#endif
765 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
766 " -v displays version\n"
767 " -d enters debug mode\n"
768#if STATTIME > 0
769 " -s enables statistics output\n"
770 " -l enables long statistics format\n"
771#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100772 " -D goes daemon ; implies -q\n"
773 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100774 " -n sets the maximum total # of connections (%d)\n"
775 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100776 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100777 exit(1);
778}
779
780
781/*
782 * Displays the message on stderr with the date and pid.
783 */
784void Alert(char *fmt, ...) {
785 va_list argp;
786 struct timeval tv;
787 struct tm *tm;
788
willy tarreau9fe663a2005-12-17 13:02:59 +0100789 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100790 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100791
willy tarreau5cbea6f2005-12-17 12:48:26 +0100792 gettimeofday(&tv, NULL);
793 tm=localtime(&tv.tv_sec);
794 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100795 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100796 vfprintf(stderr, fmt, argp);
797 fflush(stderr);
798 va_end(argp);
799 }
willy tarreau0f7af912005-12-17 12:21:26 +0100800}
801
802
803/*
804 * Displays the message on stderr with the date and pid.
805 */
806void Warning(char *fmt, ...) {
807 va_list argp;
808 struct timeval tv;
809 struct tm *tm;
810
willy tarreau9fe663a2005-12-17 13:02:59 +0100811 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100812 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100813
willy tarreau5cbea6f2005-12-17 12:48:26 +0100814 gettimeofday(&tv, NULL);
815 tm=localtime(&tv.tv_sec);
816 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100817 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100818 vfprintf(stderr, fmt, argp);
819 fflush(stderr);
820 va_end(argp);
821 }
822}
823
824/*
825 * Displays the message on <out> only if quiet mode is not set.
826 */
827void qfprintf(FILE *out, char *fmt, ...) {
828 va_list argp;
829
willy tarreau9fe663a2005-12-17 13:02:59 +0100830 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100831 va_start(argp, fmt);
832 vfprintf(out, fmt, argp);
833 fflush(out);
834 va_end(argp);
835 }
willy tarreau0f7af912005-12-17 12:21:26 +0100836}
837
838
839/*
840 * converts <str> to a struct sockaddr_in* which is locally allocated.
841 * The format is "addr:port", where "addr" can be empty or "*" to indicate
842 * INADDR_ANY.
843 */
844struct sockaddr_in *str2sa(char *str) {
845 static struct sockaddr_in sa;
846 char *c;
847 int port;
848
willy tarreaua1598082005-12-17 13:08:06 +0100849 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100850 str=strdup(str);
851
852 if ((c=strrchr(str,':')) != NULL) {
853 *c++=0;
854 port=atol(c);
855 }
856 else
857 port=0;
858
859 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
860 sa.sin_addr.s_addr = INADDR_ANY;
861 }
862 else if (
863#ifndef SOLARIS
864 !inet_aton(str, &sa.sin_addr)
865#else
866 !inet_pton(AF_INET, str, &sa.sin_addr)
867#endif
868 ) {
869 struct hostent *he;
870
871 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100872 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100873 }
874 else
875 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
876 }
877 sa.sin_port=htons(port);
878 sa.sin_family=AF_INET;
879
880 free(str);
881 return &sa;
882}
883
willy tarreau9fe663a2005-12-17 13:02:59 +0100884
885/*
886 * This function sends a syslog message to both log servers of a proxy,
887 * or to global log servers if the proxy is NULL.
888 * It also tries not to waste too much time computing the message header.
889 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100890 */
891void send_log(struct proxy *p, int level, char *message, ...) {
892 static int logfd = -1; /* syslog UDP socket */
893 static long tvsec = -1; /* to force the string to be initialized */
894 struct timeval tv;
895 va_list argp;
896 static char logmsg[MAX_SYSLOG_LEN];
897 static char *dataptr = NULL;
898 int fac_level;
899 int hdr_len, data_len;
900 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +0100901 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +0100902 int nbloggers = 0;
903 char *log_ptr;
904
905 if (logfd < 0) {
906 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
907 return;
908 }
909
910 if (level < 0 || progname == NULL || message == NULL)
911 return;
912
913 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100914 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100915 /* this string is rebuild only once a second */
916 struct tm *tm = localtime(&tv.tv_sec);
917 tvsec = tv.tv_sec;
918
willy tarreauc29948c2005-12-17 13:10:27 +0100919 hdr_len = snprintf(logmsg, sizeof(logmsg),
920 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
921 monthname[tm->tm_mon],
922 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
923 progname, pid);
924 /* WARNING: depending upon implementations, snprintf may return
925 * either -1 or the number of bytes that would be needed to store
926 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100927 */
willy tarreauc29948c2005-12-17 13:10:27 +0100928 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
929 hdr_len = sizeof(logmsg);
930
931 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100932 }
933
934 va_start(argp, message);
935 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100936 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
937 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100938 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100939 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100940
941 if (p == NULL) {
942 if (global.logfac1 >= 0) {
943 sa[nbloggers] = &global.logsrv1;
944 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100945 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100946 nbloggers++;
947 }
948 if (global.logfac2 >= 0) {
949 sa[nbloggers] = &global.logsrv2;
950 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100951 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100952 nbloggers++;
953 }
954 } else {
955 if (p->logfac1 >= 0) {
956 sa[nbloggers] = &p->logsrv1;
957 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +0100958 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +0100959 nbloggers++;
960 }
961 if (p->logfac2 >= 0) {
962 sa[nbloggers] = &p->logsrv2;
963 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100964 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100965 nbloggers++;
966 }
967 }
968
969 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +0100970 /* we can filter the level of the messages that are sent to each logger */
971 if (level > loglevel[nbloggers])
972 continue;
973
willy tarreauc29948c2005-12-17 13:10:27 +0100974 /* For each target, we may have a different facility.
975 * We can also have a different log level for each message.
976 * This induces variations in the message header length.
977 * Since we don't want to recompute it each time, nor copy it every
978 * time, we only change the facility in the pre-computed header,
979 * and we change the pointer to the header accordingly.
980 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100981 fac_level = (facilities[nbloggers] << 3) + level;
982 log_ptr = logmsg + 3; /* last digit of the log level */
983 do {
984 *log_ptr = '0' + fac_level % 10;
985 fac_level /= 10;
986 log_ptr--;
987 } while (fac_level && log_ptr > logmsg);
988 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100989
willy tarreauc29948c2005-12-17 13:10:27 +0100990 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100991
992#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100993 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100994 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
995#else
willy tarreauc29948c2005-12-17 13:10:27 +0100996 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100997 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
998#endif
999 }
willy tarreau0f7af912005-12-17 12:21:26 +01001000}
1001
1002
1003/* sets <tv> to the current time */
1004static inline struct timeval *tv_now(struct timeval *tv) {
1005 if (tv)
1006 gettimeofday(tv, NULL);
1007 return tv;
1008}
1009
1010/*
1011 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1012 */
1013static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1014 if (!tv || !from)
1015 return NULL;
1016 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1017 tv->tv_sec = from->tv_sec + (ms/1000);
1018 while (tv->tv_usec >= 1000000) {
1019 tv->tv_usec -= 1000000;
1020 tv->tv_sec++;
1021 }
1022 return tv;
1023}
1024
1025/*
1026 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1027 */
1028static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001029 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001030 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001031 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001032 return 1;
1033 else if (tv1->tv_usec < tv2->tv_usec)
1034 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001035 else if (tv1->tv_usec > tv2->tv_usec)
1036 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001037 else
1038 return 0;
1039}
1040
1041/*
1042 * returns the absolute difference, in ms, between tv1 and tv2
1043 */
1044unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1045 int cmp;
1046 unsigned long ret;
1047
1048
willy tarreauef900ab2005-12-17 12:52:52 +01001049 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001050 if (!cmp)
1051 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001052 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001053 struct timeval *tmp = tv1;
1054 tv1 = tv2;
1055 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001056 }
willy tarreauef900ab2005-12-17 12:52:52 +01001057 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001058 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001059 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001060 else
willy tarreauef900ab2005-12-17 12:52:52 +01001061 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001062 return (unsigned long) ret;
1063}
1064
1065/*
willy tarreau750a4722005-12-17 13:21:24 +01001066 * returns the difference, in ms, between tv1 and tv2
1067 */
1068static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1069 unsigned long ret;
1070
willy tarreau6e682ce2005-12-17 13:26:49 +01001071 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1072 if (tv2->tv_usec > tv1->tv_usec)
1073 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001074 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001075 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001076 return (unsigned long) ret;
1077}
1078
1079/*
willy tarreau0f7af912005-12-17 12:21:26 +01001080 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1081 */
1082static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001083 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001084 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001085 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001086 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1087 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001088 else
1089 return 0;
1090 }
willy tarreau0f7af912005-12-17 12:21:26 +01001091 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001092 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001093 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001094 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1095 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1096 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001097 else
1098 return 0;
1099}
1100
1101/*
1102 * returns the remaining time between tv1=now and event=tv2
1103 * if tv2 is passed, 0 is returned.
1104 */
1105static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1106 unsigned long ret;
1107
willy tarreau0f7af912005-12-17 12:21:26 +01001108 if (tv_cmp_ms(tv1, tv2) >= 0)
1109 return 0; /* event elapsed */
1110
willy tarreauef900ab2005-12-17 12:52:52 +01001111 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001112 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001113 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001114 else
willy tarreauef900ab2005-12-17 12:52:52 +01001115 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001116 return (unsigned long) ret;
1117}
1118
1119
1120/*
1121 * zeroes a struct timeval
1122 */
1123
1124static inline struct timeval *tv_eternity(struct timeval *tv) {
1125 tv->tv_sec = tv->tv_usec = 0;
1126 return tv;
1127}
1128
1129/*
1130 * returns 1 if tv is null, else 0
1131 */
1132static inline int tv_iseternity(struct timeval *tv) {
1133 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1134 return 1;
1135 else
1136 return 0;
1137}
1138
1139/*
1140 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1141 * considering that 0 is the eternity.
1142 */
1143static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1144 if (tv_iseternity(tv1))
1145 if (tv_iseternity(tv2))
1146 return 0; /* same */
1147 else
1148 return 1; /* tv1 later than tv2 */
1149 else if (tv_iseternity(tv2))
1150 return -1; /* tv2 later than tv1 */
1151
1152 if (tv1->tv_sec > tv2->tv_sec)
1153 return 1;
1154 else if (tv1->tv_sec < tv2->tv_sec)
1155 return -1;
1156 else if (tv1->tv_usec > tv2->tv_usec)
1157 return 1;
1158 else if (tv1->tv_usec < tv2->tv_usec)
1159 return -1;
1160 else
1161 return 0;
1162}
1163
1164/*
1165 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1166 * considering that 0 is the eternity.
1167 */
1168static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1169 if (tv_iseternity(tv1))
1170 if (tv_iseternity(tv2))
1171 return 0; /* same */
1172 else
1173 return 1; /* tv1 later than tv2 */
1174 else if (tv_iseternity(tv2))
1175 return -1; /* tv2 later than tv1 */
1176
willy tarreauefae1842005-12-17 12:51:03 +01001177 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001178 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001179 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001180 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001181 return -1;
1182 else
1183 return 0;
1184 }
1185 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001186 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001187 return 1;
1188 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001189 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001190 return -1;
1191 else
1192 return 0;
1193}
1194
1195/*
1196 * returns the first event between tv1 and tv2 into tvmin.
1197 * a zero tv is ignored. tvmin is returned.
1198 */
1199static inline struct timeval *tv_min(struct timeval *tvmin,
1200 struct timeval *tv1, struct timeval *tv2) {
1201
1202 if (tv_cmp2(tv1, tv2) <= 0)
1203 *tvmin = *tv1;
1204 else
1205 *tvmin = *tv2;
1206
1207 return tvmin;
1208}
1209
1210
1211
1212/***********************************************************/
1213/* fd management ***************************************/
1214/***********************************************************/
1215
1216
1217
willy tarreau5cbea6f2005-12-17 12:48:26 +01001218/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1219 * The file descriptor is also closed.
1220 */
willy tarreau0f7af912005-12-17 12:21:26 +01001221static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001222 FD_CLR(fd, StaticReadEvent);
1223 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001224 close(fd);
1225 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001226
1227 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1228 maxfd--;
1229}
1230
1231/* recomputes the maxfd limit from the fd */
1232static inline void fd_insert(int fd) {
1233 if (fd+1 > maxfd)
1234 maxfd = fd+1;
1235}
1236
1237/*************************************************************/
1238/* task management ***************************************/
1239/*************************************************************/
1240
willy tarreau5cbea6f2005-12-17 12:48:26 +01001241/* puts the task <t> in run queue <q>, and returns <t> */
1242static inline struct task *task_wakeup(struct task **q, struct task *t) {
1243 if (t->state == TASK_RUNNING)
1244 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001245 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001246 t->rqnext = *q;
1247 t->state = TASK_RUNNING;
1248 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001249 }
1250}
1251
willy tarreau5cbea6f2005-12-17 12:48:26 +01001252/* removes the task <t> from the queue <q>
1253 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001254 * set the run queue to point to the next one, and return it
1255 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001256static inline struct task *task_sleep(struct task **q, struct task *t) {
1257 if (t->state == TASK_RUNNING) {
1258 *q = t->rqnext;
1259 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001260 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001261 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001262}
1263
1264/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001265 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001266 * from the run queue. A pointer to the task itself is returned.
1267 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001268static inline struct task *task_delete(struct task *t) {
1269 t->prev->next = t->next;
1270 t->next->prev = t->prev;
1271 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001272}
1273
1274/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001275 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001276 */
1277static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001278 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001279}
1280
willy tarreau5cbea6f2005-12-17 12:48:26 +01001281/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001282 * may be only moved or left where it was, depending on its timing requirements.
1283 * <task> is returned.
1284 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001285struct task *task_queue(struct task *task) {
1286 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001287 struct task *start_from;
1288
1289 /* first, test if the task was already in a list */
1290 if (task->prev == NULL) {
1291 // start_from = list;
1292 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001293#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001294 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001295#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001296 /* insert the unlinked <task> into the list, searching back from the last entry */
1297 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1298 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001299#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001300 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001301#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001302 }
1303
1304 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1305 // start_from = start_from->next;
1306 // stats_tsk_nsrch++;
1307 // }
1308 }
1309 else if (task->prev == list ||
1310 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1311 start_from = task->next;
1312 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001313#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001314 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001315#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001316 return task; /* it's already in the right place */
1317 }
1318
willy tarreau750a4722005-12-17 13:21:24 +01001319#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001320 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001321#endif
1322
1323 /* if the task is not at the right place, there's little chance that
1324 * it has only shifted a bit, and it will nearly always be queued
1325 * at the end of the list because of constant timeouts
1326 * (observed in real case).
1327 */
1328#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1329 start_from = list->prev; /* assume we'll queue to the end of the list */
1330 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1331 start_from = start_from->prev;
1332#if STATTIME > 0
1333 stats_tsk_lsrch++;
1334#endif
1335 }
1336#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001337 /* insert the unlinked <task> into the list, searching after position <start_from> */
1338 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1339 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001340#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001341 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001342#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001343 }
willy tarreau750a4722005-12-17 13:21:24 +01001344#endif /* WE_REALLY_... */
1345
willy tarreau0f7af912005-12-17 12:21:26 +01001346 /* we need to unlink it now */
1347 task_delete(task);
1348 }
1349 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001350#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001351 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001352#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001353#ifdef LEFT_TO_TOP /* not very good */
1354 start_from = list;
1355 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1356 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001357#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001358 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001359#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001360 }
1361#else
1362 start_from = task->prev->prev; /* valid because of the previous test above */
1363 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1364 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001365#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001366 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001367#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001368 }
1369#endif
1370 /* we need to unlink it now */
1371 task_delete(task);
1372 }
1373 task->prev = start_from;
1374 task->next = start_from->next;
1375 task->next->prev = task;
1376 start_from->next = task;
1377 return task;
1378}
1379
1380
1381/*********************************************************************/
1382/* more specific functions ***************************************/
1383/*********************************************************************/
1384
1385/* some prototypes */
1386static int maintain_proxies(void);
1387
willy tarreau5cbea6f2005-12-17 12:48:26 +01001388/* this either returns the sockname or the original destination address. Code
1389 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1390 */
1391static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001392#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001393 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1394#else
willy tarreaua1598082005-12-17 13:08:06 +01001395#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001396 return getsockname(fd, (struct sockaddr *)sa, salen);
1397#else
1398 return -1;
1399#endif
1400#endif
1401}
1402
1403/*
1404 * frees the context associated to a session. It must have been removed first.
1405 */
1406static inline void session_free(struct session *s) {
1407 if (s->req)
1408 pool_free(buffer, s->req);
1409 if (s->rep)
1410 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001411 if (s->logs.uri)
1412 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001413 if (s->logs.cli_cookie)
1414 pool_free(capture, s->logs.cli_cookie);
1415 if (s->logs.srv_cookie)
1416 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001417
willy tarreau5cbea6f2005-12-17 12:48:26 +01001418 pool_free(session, s);
1419}
1420
willy tarreau0f7af912005-12-17 12:21:26 +01001421
1422/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001423 * This function tries to find a running server for the proxy <px>. A first
1424 * pass looks for active servers, and if none is found, a second pass also
1425 * looks for backup servers.
1426 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1427 */
1428static inline struct server *find_server(struct proxy *px) {
1429 struct server *srv = px->cursrv;
1430 int ignore_backup = 1;
1431
1432 do {
1433 do {
1434 if (srv == NULL)
1435 srv = px->srv;
1436 if (srv->state & SRV_RUNNING
1437 && !((srv->state & SRV_BACKUP) && ignore_backup))
1438 return srv;
1439 srv = srv->next;
1440 } while (srv != px->cursrv);
1441 } while (ignore_backup--);
1442 return NULL;
1443}
1444
1445/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001446 * This function initiates a connection to the current server (s->srv) if (s->direct)
1447 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001448 * it's OK, -1 if it's impossible.
1449 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001450int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001451 int one = 1;
1452 int fd;
1453
1454 // fprintf(stderr,"connect_server : s=%p\n",s);
1455
willy tarreaue39cd132005-12-17 13:00:18 +01001456 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001457 s->srv_addr = s->srv->addr;
1458 }
1459 else if (s->proxy->options & PR_O_BALANCE) {
1460 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001461 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001462
willy tarreau8337c6b2005-12-17 13:41:01 +01001463 srv = find_server(s->proxy);
1464
1465 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001466 return -1;
1467
willy tarreau8337c6b2005-12-17 13:41:01 +01001468 s->srv_addr = srv->addr;
1469 s->srv = srv;
1470 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001471 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001472 else /* unknown balancing algorithm */
1473 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001474 }
willy tarreaua1598082005-12-17 13:08:06 +01001475 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001476 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001477 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001478 }
1479 else if (s->proxy->options & PR_O_TRANSP) {
1480 /* in transparent mode, use the original dest addr if no dispatch specified */
1481 int salen = sizeof(struct sockaddr_in);
1482 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1483 qfprintf(stderr, "Cannot get original server address.\n");
1484 return -1;
1485 }
1486 }
willy tarreau0f7af912005-12-17 12:21:26 +01001487
1488 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001489 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001490 return -1;
1491 }
1492
willy tarreau9fe663a2005-12-17 13:02:59 +01001493 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001494 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1495 close(fd);
1496 return -1;
1497 }
1498
willy tarreau0f7af912005-12-17 12:21:26 +01001499 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1500 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001501 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001502 close(fd);
1503 return -1;
1504 }
1505
willy tarreaua1598082005-12-17 13:08:06 +01001506 /* allow specific binding */
1507 if (s->proxy->options & PR_O_BIND_SRC &&
1508 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1509 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1510 close(fd);
1511 return -1;
1512 }
1513
willy tarreau0f7af912005-12-17 12:21:26 +01001514 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1515 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001516 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001517 close(fd);
1518 return -1;
1519 }
1520 else if (errno != EALREADY && errno != EISCONN) {
1521 close(fd);
1522 return -1;
1523 }
1524 }
1525
willy tarreau5cbea6f2005-12-17 12:48:26 +01001526 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001527 fdtab[fd].read = &event_srv_read;
1528 fdtab[fd].write = &event_srv_write;
1529 fdtab[fd].state = FD_STCONN; /* connection in progress */
1530
1531 FD_SET(fd, StaticWriteEvent); /* for connect status */
1532
1533 fd_insert(fd);
1534
1535 if (s->proxy->contimeout)
1536 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1537 else
1538 tv_eternity(&s->cnexpire);
1539 return 0;
1540}
1541
1542/*
1543 * this function is called on a read event from a client socket.
1544 * It returns 0.
1545 */
1546int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001547 struct task *t = fdtab[fd].owner;
1548 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001549 struct buffer *b = s->req;
1550 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001551
1552 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1553
willy tarreau0f7af912005-12-17 12:21:26 +01001554 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001555 while (1) {
1556 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1557 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001558 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001559 }
1560 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001561 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562 }
1563 else {
1564 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001565 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1566 * since it means that the rewrite protection has been removed. This
1567 * implies that the if statement can be removed.
1568 */
1569 if (max > b->rlim - b->data)
1570 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001571 }
1572
1573 if (max == 0) { /* not anymore room to store data */
1574 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001575 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001576 }
1577
willy tarreau3242e862005-12-17 12:27:53 +01001578#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001579 {
1580 int skerr, lskerr;
1581
1582 lskerr = sizeof(skerr);
1583 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1584 if (skerr)
1585 ret = -1;
1586 else
1587 ret = recv(fd, b->r, max, 0);
1588 }
willy tarreau3242e862005-12-17 12:27:53 +01001589#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001590 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001591#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001592 if (ret > 0) {
1593 b->r += ret;
1594 b->l += ret;
1595 s->res_cr = RES_DATA;
1596
1597 if (b->r == b->data + BUFSIZE) {
1598 b->r = b->data; /* wrap around the buffer */
1599 }
willy tarreaua1598082005-12-17 13:08:06 +01001600
1601 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001602 /* we hope to read more data or to get a close on next round */
1603 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001604 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001605 else if (ret == 0) {
1606 s->res_cr = RES_NULL;
1607 break;
1608 }
1609 else if (errno == EAGAIN) {/* ignore EAGAIN */
1610 break;
1611 }
1612 else {
1613 s->res_cr = RES_ERROR;
1614 fdtab[fd].state = FD_STERROR;
1615 break;
1616 }
1617 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001618 }
1619 else {
1620 s->res_cr = RES_ERROR;
1621 fdtab[fd].state = FD_STERROR;
1622 }
1623
willy tarreau5cbea6f2005-12-17 12:48:26 +01001624 if (s->res_cr != RES_SILENT) {
1625 if (s->proxy->clitimeout)
1626 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1627 else
1628 tv_eternity(&s->crexpire);
1629
1630 task_wakeup(&rq, t);
1631 }
willy tarreau0f7af912005-12-17 12:21:26 +01001632
willy tarreau0f7af912005-12-17 12:21:26 +01001633 return 0;
1634}
1635
1636
1637/*
1638 * this function is called on a read event from a server socket.
1639 * It returns 0.
1640 */
1641int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001642 struct task *t = fdtab[fd].owner;
1643 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001644 struct buffer *b = s->rep;
1645 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001646
1647 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1648
willy tarreau0f7af912005-12-17 12:21:26 +01001649 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001650 while (1) {
1651 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1652 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001653 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001654 }
1655 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001656 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001657 }
1658 else {
1659 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001660 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1661 * since it means that the rewrite protection has been removed. This
1662 * implies that the if statement can be removed.
1663 */
1664 if (max > b->rlim - b->data)
1665 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001666 }
1667
1668 if (max == 0) { /* not anymore room to store data */
1669 FD_CLR(fd, StaticReadEvent);
1670 break;
1671 }
1672
willy tarreau3242e862005-12-17 12:27:53 +01001673#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001674 {
1675 int skerr, lskerr;
1676
1677 lskerr = sizeof(skerr);
1678 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1679 if (skerr)
1680 ret = -1;
1681 else
1682 ret = recv(fd, b->r, max, 0);
1683 }
willy tarreau3242e862005-12-17 12:27:53 +01001684#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001685 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001686#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001687 if (ret > 0) {
1688 b->r += ret;
1689 b->l += ret;
1690 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001691
willy tarreau5cbea6f2005-12-17 12:48:26 +01001692 if (b->r == b->data + BUFSIZE) {
1693 b->r = b->data; /* wrap around the buffer */
1694 }
willy tarreaua1598082005-12-17 13:08:06 +01001695
1696 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 /* we hope to read more data or to get a close on next round */
1698 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001699 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700 else if (ret == 0) {
1701 s->res_sr = RES_NULL;
1702 break;
1703 }
1704 else if (errno == EAGAIN) {/* ignore EAGAIN */
1705 break;
1706 }
1707 else {
1708 s->res_sr = RES_ERROR;
1709 fdtab[fd].state = FD_STERROR;
1710 break;
1711 }
1712 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001713 }
1714 else {
1715 s->res_sr = RES_ERROR;
1716 fdtab[fd].state = FD_STERROR;
1717 }
1718
willy tarreau5cbea6f2005-12-17 12:48:26 +01001719 if (s->res_sr != RES_SILENT) {
1720 if (s->proxy->srvtimeout)
1721 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1722 else
1723 tv_eternity(&s->srexpire);
1724
1725 task_wakeup(&rq, t);
1726 }
willy tarreau0f7af912005-12-17 12:21:26 +01001727
willy tarreau0f7af912005-12-17 12:21:26 +01001728 return 0;
1729}
1730
1731/*
1732 * this function is called on a write event from a client socket.
1733 * It returns 0.
1734 */
1735int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001736 struct task *t = fdtab[fd].owner;
1737 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001738 struct buffer *b = s->rep;
1739 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001740
1741 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1742
1743 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001744 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001745 // max = BUFSIZE; BUG !!!!
1746 max = 0;
1747 }
1748 else if (b->r > b->w) {
1749 max = b->r - b->w;
1750 }
1751 else
1752 max = b->data + BUFSIZE - b->w;
1753
willy tarreau0f7af912005-12-17 12:21:26 +01001754 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001755#ifndef MSG_NOSIGNAL
1756 int skerr, lskerr;
1757#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001758
1759 if (max == 0) {
1760 s->res_cw = RES_NULL;
1761 task_wakeup(&rq, t);
1762 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001763 }
1764
willy tarreau3242e862005-12-17 12:27:53 +01001765#ifndef MSG_NOSIGNAL
1766 lskerr=sizeof(skerr);
1767 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1768 if (skerr)
1769 ret = -1;
1770 else
1771 ret = send(fd, b->w, max, MSG_DONTWAIT);
1772#else
willy tarreau0f7af912005-12-17 12:21:26 +01001773 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001774#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001775
1776 if (ret > 0) {
1777 b->l -= ret;
1778 b->w += ret;
1779
1780 s->res_cw = RES_DATA;
1781
1782 if (b->w == b->data + BUFSIZE) {
1783 b->w = b->data; /* wrap around the buffer */
1784 }
1785 }
1786 else if (ret == 0) {
1787 /* nothing written, just make as if we were never called */
1788// s->res_cw = RES_NULL;
1789 return 0;
1790 }
1791 else if (errno == EAGAIN) /* ignore EAGAIN */
1792 return 0;
1793 else {
1794 s->res_cw = RES_ERROR;
1795 fdtab[fd].state = FD_STERROR;
1796 }
1797 }
1798 else {
1799 s->res_cw = RES_ERROR;
1800 fdtab[fd].state = FD_STERROR;
1801 }
1802
1803 if (s->proxy->clitimeout)
1804 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1805 else
1806 tv_eternity(&s->cwexpire);
1807
willy tarreau5cbea6f2005-12-17 12:48:26 +01001808 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001809 return 0;
1810}
1811
1812
1813/*
1814 * this function is called on a write event from a server socket.
1815 * It returns 0.
1816 */
1817int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001818 struct task *t = fdtab[fd].owner;
1819 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001820 struct buffer *b = s->req;
1821 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001822
1823 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1824
1825 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001826 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001827 // max = BUFSIZE; BUG !!!!
1828 max = 0;
1829 }
1830 else if (b->r > b->w) {
1831 max = b->r - b->w;
1832 }
1833 else
1834 max = b->data + BUFSIZE - b->w;
1835
willy tarreau0f7af912005-12-17 12:21:26 +01001836 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001837#ifndef MSG_NOSIGNAL
1838 int skerr, lskerr;
1839#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001840 if (max == 0) {
1841 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001842 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001843 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001844 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001845 return 0;
1846 }
1847
willy tarreauef900ab2005-12-17 12:52:52 +01001848
willy tarreau3242e862005-12-17 12:27:53 +01001849#ifndef MSG_NOSIGNAL
1850 lskerr=sizeof(skerr);
1851 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1852 if (skerr)
1853 ret = -1;
1854 else
1855 ret = send(fd, b->w, max, MSG_DONTWAIT);
1856#else
willy tarreau0f7af912005-12-17 12:21:26 +01001857 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001858#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001859 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001860 if (ret > 0) {
1861 b->l -= ret;
1862 b->w += ret;
1863
1864 s->res_sw = RES_DATA;
1865
1866 if (b->w == b->data + BUFSIZE) {
1867 b->w = b->data; /* wrap around the buffer */
1868 }
1869 }
1870 else if (ret == 0) {
1871 /* nothing written, just make as if we were never called */
1872 // s->res_sw = RES_NULL;
1873 return 0;
1874 }
1875 else if (errno == EAGAIN) /* ignore EAGAIN */
1876 return 0;
1877 else {
1878 s->res_sw = RES_ERROR;
1879 fdtab[fd].state = FD_STERROR;
1880 }
1881 }
1882 else {
1883 s->res_sw = RES_ERROR;
1884 fdtab[fd].state = FD_STERROR;
1885 }
1886
1887 if (s->proxy->srvtimeout)
1888 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1889 else
1890 tv_eternity(&s->swexpire);
1891
willy tarreau5cbea6f2005-12-17 12:48:26 +01001892 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001893 return 0;
1894}
1895
1896
1897/*
willy tarreaue39cd132005-12-17 13:00:18 +01001898 * returns a message to the client ; the connection is shut down for read,
1899 * and the request is cleared so that no server connection can be initiated.
1900 * The client must be in a valid state for this (HEADER, DATA ...).
1901 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01001902 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001903 */
1904void client_retnclose(struct session *s, int len, const char *msg) {
1905 FD_CLR(s->cli_fd, StaticReadEvent);
1906 FD_SET(s->cli_fd, StaticWriteEvent);
1907 tv_eternity(&s->crexpire);
1908 shutdown(s->cli_fd, SHUT_RD);
1909 s->cli_state = CL_STSHUTR;
1910 strcpy(s->rep->data, msg);
1911 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001912 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001913 s->rep->r += len;
1914 s->req->l = 0;
1915}
1916
1917
1918/*
1919 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01001920 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01001921 */
1922void client_return(struct session *s, int len, const char *msg) {
1923 strcpy(s->rep->data, msg);
1924 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01001925 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01001926 s->rep->r += len;
1927 s->req->l = 0;
1928}
1929
willy tarreau9fe663a2005-12-17 13:02:59 +01001930/*
1931 * send a log for the session when we have enough info about it
1932 */
1933void sess_log(struct session *s) {
1934 unsigned char *pn;
1935 struct proxy *p = s->proxy;
1936 int log;
1937 char *uri;
1938 char *pxid;
1939 char *srv;
1940
1941 /* This is a first attempt at a better logging system.
1942 * For now, we rely on send_log() to provide the date, although it obviously
1943 * is the date of the log and not of the request, and most fields are not
1944 * computed.
1945 */
1946
willy tarreaua1598082005-12-17 13:08:06 +01001947 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001948
1949 pn = (log & LW_CLIP) ?
1950 (unsigned char *)&s->cli_addr.sin_addr :
1951 (unsigned char *)"\0\0\0\0";
1952
willy tarreaua1598082005-12-17 13:08:06 +01001953 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001954 pxid = p->id;
1955 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001956 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1957
1958 if (p->to_log & LW_DATE) {
1959 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1960
willy tarreau8337c6b2005-12-17 13:41:01 +01001961 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 %s \"%s\"\n",
willy tarreaua1598082005-12-17 13:08:06 +01001962 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1963 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1964 tm->tm_hour, tm->tm_min, tm->tm_sec,
1965 pxid, srv,
1966 s->logs.t_request,
1967 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1968 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1969 s->logs.t_close,
1970 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001971 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1972 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreaua1598082005-12-17 13:08:06 +01001973 uri);
1974 }
1975 else {
willy tarreau8337c6b2005-12-17 13:41:01 +01001976 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld %s %s \"%s\"\n",
willy tarreaua1598082005-12-17 13:08:06 +01001977 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1978 pxid, srv,
1979 s->logs.t_request,
1980 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1981 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1982 s->logs.t_close,
1983 s->logs.status, s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01001984 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
1985 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreaua1598082005-12-17 13:08:06 +01001986 uri);
1987 }
1988
1989 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001990}
1991
willy tarreaue39cd132005-12-17 13:00:18 +01001992
1993/*
willy tarreau0f7af912005-12-17 12:21:26 +01001994 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001995 * to an accept. It tries to accept as many connections as possible.
1996 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001997 */
1998int event_accept(int fd) {
1999 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002000 struct session *s;
2001 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002002 int cfd;
2003 int one = 1;
2004
willy tarreau5cbea6f2005-12-17 12:48:26 +01002005 while (p->nbconn < p->maxconn) {
2006 struct sockaddr_in addr;
2007 int laddr = sizeof(addr);
2008 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2009 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002010
willy tarreau5cbea6f2005-12-17 12:48:26 +01002011 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2012 Alert("out of memory in event_accept().\n");
2013 FD_CLR(fd, StaticReadEvent);
2014 p->state = PR_STIDLE;
2015 close(cfd);
2016 return 0;
2017 }
willy tarreau0f7af912005-12-17 12:21:26 +01002018
willy tarreau5cbea6f2005-12-17 12:48:26 +01002019 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2020 Alert("out of memory in event_accept().\n");
2021 FD_CLR(fd, StaticReadEvent);
2022 p->state = PR_STIDLE;
2023 close(cfd);
2024 pool_free(session, s);
2025 return 0;
2026 }
willy tarreau0f7af912005-12-17 12:21:26 +01002027
willy tarreau5cbea6f2005-12-17 12:48:26 +01002028 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002029 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002030 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2031 close(cfd);
2032 pool_free(task, t);
2033 pool_free(session, s);
2034 return 0;
2035 }
willy tarreau0f7af912005-12-17 12:21:26 +01002036
willy tarreau5cbea6f2005-12-17 12:48:26 +01002037 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2038 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2039 (char *) &one, sizeof(one)) == -1)) {
2040 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2041 close(cfd);
2042 pool_free(task, t);
2043 pool_free(session, s);
2044 return 0;
2045 }
willy tarreau0f7af912005-12-17 12:21:26 +01002046
willy tarreau9fe663a2005-12-17 13:02:59 +01002047 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2048 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2049 t->state = TASK_IDLE;
2050 t->process = process_session;
2051 t->context = s;
2052
2053 s->task = t;
2054 s->proxy = p;
2055 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2056 s->srv_state = SV_STIDLE;
2057 s->req = s->rep = NULL; /* will be allocated later */
2058 s->flags = 0;
2059 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2060 s->cli_fd = cfd;
2061 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002062 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002063 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002064
2065 s->logs.logwait = p->to_log;
2066 s->logs.tv_accept = now;
2067 s->logs.t_request = -1;
2068 s->logs.t_connect = -1;
2069 s->logs.t_data = -1;
2070 s->logs.t_close = 0;
2071 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002072 s->logs.cli_cookie = NULL;
2073 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002074 s->logs.status = -1;
2075 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002076
willy tarreau5cbea6f2005-12-17 12:48:26 +01002077 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2078 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01002079 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002080 unsigned char *pn, *sn;
2081 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002082
willy tarreau5cbea6f2005-12-17 12:48:26 +01002083 namelen = sizeof(sockname);
2084 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2085 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
2086 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01002087 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01002088
willy tarreau9fe663a2005-12-17 13:02:59 +01002089 if (p->to_log) {
2090 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002091 if (s->logs.logwait & LW_CLIP)
2092 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002093 sess_log(s);
2094 }
2095 else
2096 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
2097 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
2098 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
2099 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01002100 }
willy tarreau0f7af912005-12-17 12:21:26 +01002101
willy tarreau9fe663a2005-12-17 13:02:59 +01002102 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002103 int len;
2104 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
2105 write(1, trash, len);
2106 }
willy tarreau0f7af912005-12-17 12:21:26 +01002107
willy tarreau5cbea6f2005-12-17 12:48:26 +01002108 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2109 close(cfd); /* nothing can be done for this fd without memory */
2110 pool_free(task, t);
2111 pool_free(session, s);
2112 return 0;
2113 }
2114 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002115 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002116 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2117 s->req->rlim = s->req->data + BUFSIZE;
2118 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
2119 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002120
willy tarreau5cbea6f2005-12-17 12:48:26 +01002121 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2122 pool_free(buffer, s->req);
2123 close(cfd); /* nothing can be done for this fd without memory */
2124 pool_free(task, t);
2125 pool_free(session, s);
2126 return 0;
2127 }
2128 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002129 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002130 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 +01002131
willy tarreau5cbea6f2005-12-17 12:48:26 +01002132 fdtab[cfd].read = &event_cli_read;
2133 fdtab[cfd].write = &event_cli_write;
2134 fdtab[cfd].owner = t;
2135 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002136
willy tarreau5cbea6f2005-12-17 12:48:26 +01002137 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01002138 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002139 }
2140 else {
2141 FD_SET(cfd, StaticReadEvent);
2142 }
2143
2144 fd_insert(cfd);
2145
2146 tv_eternity(&s->cnexpire);
2147 tv_eternity(&s->srexpire);
2148 tv_eternity(&s->swexpire);
2149 tv_eternity(&s->cwexpire);
2150
2151 if (s->proxy->clitimeout)
2152 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2153 else
2154 tv_eternity(&s->crexpire);
2155
2156 t->expire = s->crexpire;
2157
2158 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002159
2160 if (p->mode != PR_MODE_HEALTH)
2161 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002162
2163 p->nbconn++;
2164 actconn++;
2165 totalconn++;
2166
2167 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2168 } /* end of while (p->nbconn < p->maxconn) */
2169 return 0;
2170}
willy tarreau0f7af912005-12-17 12:21:26 +01002171
willy tarreau0f7af912005-12-17 12:21:26 +01002172
willy tarreau5cbea6f2005-12-17 12:48:26 +01002173/*
2174 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002175 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2176 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002177 * or -1 if an error occured.
2178 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002179int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002180 struct task *t = fdtab[fd].owner;
2181 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002182
willy tarreau5cbea6f2005-12-17 12:48:26 +01002183 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002184 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002185 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2186 if (skerr)
2187 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002188 else {
2189 if (s->proxy->options & PR_O_HTTP_CHK) {
2190 int ret;
2191 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
2192 * so we'll send the request, and won't wake the checker up now.
2193 */
2194#ifndef MSG_NOSIGNAL
2195 ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT);
2196#else
2197 ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT | MSG_NOSIGNAL);
2198#endif
2199 if (ret == 22) {
2200 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2201 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2202 return 0;
2203 }
2204 else
2205 s->result = -1;
2206 }
2207 else {
2208 /* good TCP connection is enough */
2209 s->result = 1;
2210 }
2211 }
2212
2213 task_wakeup(&rq, t);
2214 return 0;
2215}
2216
willy tarreau0f7af912005-12-17 12:21:26 +01002217
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002218/*
2219 * This function is used only for server health-checks. It handles
2220 * the server's reply to an HTTP request. It returns 1 if the server replies
2221 * 2xx or 3xx (valid responses), or -1 in other cases.
2222 */
2223int event_srv_chk_r(int fd) {
2224 char reply[64];
2225 int len;
2226 struct task *t = fdtab[fd].owner;
2227 struct server *s = t->context;
2228
2229 int skerr, lskerr;
2230 lskerr = sizeof(skerr);
2231 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2232 s->result = -1;
2233 if (!skerr) {
2234#ifndef MSG_NOSIGNAL
2235 len = recv(fd, reply, sizeof(reply), 0);
2236#else
2237 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
2238#endif
2239 if ((len >= sizeof("HTTP/1.0 000")) &&
2240 !memcmp(reply, "HTTP/1.", 7) &&
2241 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2242 s->result = 1;
2243 }
2244
2245 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002246 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002247 return 0;
2248}
2249
2250
2251/*
2252 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2253 * and moves <end> just after the end of <str>.
2254 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2255 * the shift value (positive or negative) is returned.
2256 * If there's no space left, the move is not done.
2257 *
2258 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002259int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002260 int delta;
2261 int len;
2262
2263 len = strlen(str);
2264 delta = len - (end - pos);
2265
2266 if (delta + b->r >= b->data + BUFSIZE)
2267 return 0; /* no space left */
2268
2269 /* first, protect the end of the buffer */
2270 memmove(end + delta, end, b->data + b->l - end);
2271
2272 /* now, copy str over pos */
2273 memcpy(pos, str,len);
2274
willy tarreau5cbea6f2005-12-17 12:48:26 +01002275 /* we only move data after the displaced zone */
2276 if (b->r > pos) b->r += delta;
2277 if (b->w > pos) b->w += delta;
2278 if (b->h > pos) b->h += delta;
2279 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002280 b->l += delta;
2281
2282 return delta;
2283}
2284
willy tarreau8337c6b2005-12-17 13:41:01 +01002285/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002286 * len is 0.
2287 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002288int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002289 int delta;
2290
2291 delta = len - (end - pos);
2292
2293 if (delta + b->r >= b->data + BUFSIZE)
2294 return 0; /* no space left */
2295
2296 /* first, protect the end of the buffer */
2297 memmove(end + delta, end, b->data + b->l - end);
2298
2299 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002300 if (len)
2301 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002302
willy tarreau5cbea6f2005-12-17 12:48:26 +01002303 /* we only move data after the displaced zone */
2304 if (b->r > pos) b->r += delta;
2305 if (b->w > pos) b->w += delta;
2306 if (b->h > pos) b->h += delta;
2307 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002308 b->l += delta;
2309
2310 return delta;
2311}
2312
2313
2314int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2315 char *old_dst = dst;
2316
2317 while (*str) {
2318 if (*str == '\\') {
2319 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002320 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002321 int len, num;
2322
2323 num = *str - '0';
2324 str++;
2325
2326 if (matches[num].rm_so > -1) {
2327 len = matches[num].rm_eo - matches[num].rm_so;
2328 memcpy(dst, src + matches[num].rm_so, len);
2329 dst += len;
2330 }
2331
2332 }
2333 else if (*str == 'x') {
2334 unsigned char hex1, hex2;
2335 str++;
2336
2337 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2338
2339 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2340 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2341 *dst++ = (hex1<<4) + hex2;
2342 }
2343 else
2344 *dst++ = *str++;
2345 }
2346 else
2347 *dst++ = *str++;
2348 }
2349 *dst = 0;
2350 return dst - old_dst;
2351}
2352
willy tarreau9fe663a2005-12-17 13:02:59 +01002353
willy tarreau0f7af912005-12-17 12:21:26 +01002354/*
2355 * manages the client FSM and its socket. BTW, it also tries to handle the
2356 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2357 * 0 else.
2358 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002359int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002360 int s = t->srv_state;
2361 int c = t->cli_state;
2362 struct buffer *req = t->req;
2363 struct buffer *rep = t->rep;
2364
willy tarreau750a4722005-12-17 13:21:24 +01002365#ifdef DEBUG_FULL
2366 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2367#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002368 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2369 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2370 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2371 //);
2372 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002373 /* now parse the partial (or complete) headers */
2374 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2375 char *ptr;
2376 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002377
willy tarreau5cbea6f2005-12-17 12:48:26 +01002378 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002379
willy tarreau0f7af912005-12-17 12:21:26 +01002380 /* look for the end of the current header */
2381 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2382 ptr++;
2383
willy tarreau5cbea6f2005-12-17 12:48:26 +01002384 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002385 int line, len;
2386 /* we can only get here after an end of headers */
2387 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002388
willy tarreaue39cd132005-12-17 13:00:18 +01002389 if (t->flags & SN_CLDENY) {
2390 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002391 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002392 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreaue39cd132005-12-17 13:00:18 +01002393 return 1;
2394 }
2395
willy tarreau5cbea6f2005-12-17 12:48:26 +01002396 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002397 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2398 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002399 }
willy tarreau0f7af912005-12-17 12:21:26 +01002400
willy tarreau9fe663a2005-12-17 13:02:59 +01002401 if (t->proxy->options & PR_O_FWDFOR) {
2402 /* insert an X-Forwarded-For header */
2403 unsigned char *pn;
2404 pn = (unsigned char *)&t->cli_addr.sin_addr;
willy tarreau750a4722005-12-17 13:21:24 +01002405 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01002406 pn[0], pn[1], pn[2], pn[3]);
willy tarreau750a4722005-12-17 13:21:24 +01002407 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau9fe663a2005-12-17 13:02:59 +01002408 }
2409
willy tarreaucd878942005-12-17 13:27:43 +01002410 if (!memcmp(req->data, "POST ", 5))
2411 t->flags |= SN_POST; /* this is a POST request */
2412
willy tarreau5cbea6f2005-12-17 12:48:26 +01002413 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002414 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002415
willy tarreau750a4722005-12-17 13:21:24 +01002416 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002417 /* FIXME: we'll set the client in a wait state while we try to
2418 * connect to the server. Is this really needed ? wouldn't it be
2419 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002420 //FD_CLR(t->cli_fd, StaticReadEvent);
2421 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002422 break;
2423 }
willy tarreau0f7af912005-12-17 12:21:26 +01002424
willy tarreau5cbea6f2005-12-17 12:48:26 +01002425 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2426 if (ptr > req->r - 2) {
2427 /* this is a partial header, let's wait for more to come */
2428 req->lr = ptr;
2429 break;
2430 }
willy tarreau0f7af912005-12-17 12:21:26 +01002431
willy tarreau5cbea6f2005-12-17 12:48:26 +01002432 /* now we know that *ptr is either \r or \n,
2433 * and that there are at least 1 char after it.
2434 */
2435 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2436 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2437 else
2438 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002439
willy tarreau5cbea6f2005-12-17 12:48:26 +01002440 /*
2441 * now we know that we have a full header ; we can do whatever
2442 * we want with these pointers :
2443 * req->h = beginning of header
2444 * ptr = end of header (first \r or \n)
2445 * req->lr = beginning of next line (next rep->h)
2446 * req->r = end of data (not used at this stage)
2447 */
willy tarreau0f7af912005-12-17 12:21:26 +01002448
willy tarreau8337c6b2005-12-17 13:41:01 +01002449 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002450 /* we have a complete HTTP request that we must log */
2451 int urilen;
2452
willy tarreaua1598082005-12-17 13:08:06 +01002453 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002454 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002455 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002456 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau9fe663a2005-12-17 13:02:59 +01002457 return 1;
2458 }
2459
2460 urilen = ptr - req->h;
2461 if (urilen >= REQURI_LEN)
2462 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002463 memcpy(t->logs.uri, req->h, urilen);
2464 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002465
willy tarreaua1598082005-12-17 13:08:06 +01002466 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002467 sess_log(t);
2468 }
2469
willy tarreau5cbea6f2005-12-17 12:48:26 +01002470 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002471
willy tarreau9fe663a2005-12-17 13:02:59 +01002472 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002473 int len, max;
2474 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2475 max = ptr - req->h;
2476 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002477 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002478 trash[len++] = '\n';
2479 write(1, trash, len);
2480 }
willy tarreau0f7af912005-12-17 12:21:26 +01002481
willy tarreau5cbea6f2005-12-17 12:48:26 +01002482 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002483 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2484 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002485 char term;
2486
2487 term = *ptr;
2488 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002489 exp = t->proxy->req_exp;
2490 do {
2491 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2492 switch (exp->action) {
2493 case ACT_ALLOW:
2494 if (!(t->flags & SN_CLDENY))
2495 t->flags |= SN_CLALLOW;
2496 break;
2497 case ACT_REPLACE:
2498 if (!(t->flags & SN_CLDENY)) {
2499 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2500 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2501 }
2502 break;
2503 case ACT_REMOVE:
2504 if (!(t->flags & SN_CLDENY))
2505 delete_header = 1;
2506 break;
2507 case ACT_DENY:
2508 if (!(t->flags & SN_CLALLOW))
2509 t->flags |= SN_CLDENY;
2510 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002511 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002512 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002513 }
willy tarreaue39cd132005-12-17 13:00:18 +01002514 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002515 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002516 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002517
willy tarreau240afa62005-12-17 13:14:35 +01002518 /* Now look for cookies. Conforming to RFC2109, we have to support
2519 * attributes whose name begin with a '$', and associate them with
2520 * the right cookie, if we want to delete this cookie.
2521 * So there are 3 cases for each cookie read :
2522 * 1) it's a special attribute, beginning with a '$' : ignore it.
2523 * 2) it's a server id cookie that we *MAY* want to delete : save
2524 * some pointers on it (last semi-colon, beginning of cookie...)
2525 * 3) it's an application cookie : we *MAY* have to delete a previous
2526 * "special" cookie.
2527 * At the end of loop, if a "special" cookie remains, we may have to
2528 * remove it. If no application cookie persists in the header, we
2529 * *MUST* delete it
2530 */
willy tarreau8337c6b2005-12-17 13:41:01 +01002531 if (!delete_header && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
willy tarreau240afa62005-12-17 13:14:35 +01002532 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau8337c6b2005-12-17 13:41:01 +01002533 && (memcmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002534 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002535 char *del_colon, *del_cookie, *colon;
2536 int app_cookies;
2537
willy tarreau5cbea6f2005-12-17 12:48:26 +01002538 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002539 colon = p1;
2540 /* del_cookie == NULL => nothing to be deleted */
2541 del_colon = del_cookie = NULL;
2542 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002543
2544 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002545 /* skip spaces and colons, but keep an eye on these ones */
2546 while (p1 < ptr) {
2547 if (*p1 == ';' || *p1 == ',')
2548 colon = p1;
2549 else if (!isspace((int)*p1))
2550 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002552 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002553
2554 if (p1 == ptr)
2555 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002556
2557 /* p1 is at the beginning of the cookie name */
2558 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002559 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002560 p2++;
2561
2562 if (p2 == ptr)
2563 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002564
2565 p3 = p2 + 1; /* skips the '=' sign */
2566 if (p3 == ptr)
2567 break;
2568
willy tarreau240afa62005-12-17 13:14:35 +01002569 p4 = p3;
2570 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002571 p4++;
2572
2573 /* here, we have the cookie name between p1 and p2,
2574 * and its value between p3 and p4.
2575 * we can process it.
2576 */
2577
willy tarreau240afa62005-12-17 13:14:35 +01002578 if (*p1 == '$') {
2579 /* skip this one */
2580 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002581 else {
2582 /* first, let's see if we want to capture it */
2583 if (t->proxy->capture_name != NULL &&
2584 t->logs.cli_cookie == NULL &&
2585 (p4 - p1 >= t->proxy->capture_namelen) &&
2586 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
2587 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002588
willy tarreau8337c6b2005-12-17 13:41:01 +01002589 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
2590 Alert("HTTP logging : out of memory.\n");
2591 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002592
willy tarreau8337c6b2005-12-17 13:41:01 +01002593 if (log_len > t->proxy->capture_len)
2594 log_len = t->proxy->capture_len;
2595 memcpy(t->logs.cli_cookie, p1, log_len);
2596 t->logs.cli_cookie[log_len] = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002597 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002598
2599 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
2600 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2601 /* Cool... it's the right one */
2602 struct server *srv = t->proxy->srv;
2603
2604 while (srv &&
2605 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2606 srv = srv->next;
2607 }
2608
2609 if (srv &&
2610 (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST)) {
2611 /* we found the server and it's usable */
2612 t->flags |= SN_DIRECT;
2613 t->srv = srv;
2614 }
2615 /* if this cookie was set in insert+indirect mode, then it's better that the
2616 * server never sees it.
2617 */
2618 if (del_cookie == NULL &&
2619 (t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
willy tarreau240afa62005-12-17 13:14:35 +01002620 del_cookie = p1;
2621 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01002622 }
willy tarreau240afa62005-12-17 13:14:35 +01002623 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002624 else {
2625 /* now we know that we must keep this cookie since it's
2626 * not ours. But if we wanted to delete our cookie
2627 * earlier, we cannot remove the complete header, but we
2628 * can remove the previous block itself.
2629 */
2630 app_cookies++;
2631
2632 if (del_cookie != NULL) {
2633 buffer_replace2(req, del_cookie, p1, NULL, 0);
2634 p4 -= (p1 - del_cookie);
2635 ptr -= (p1 - del_cookie);
2636 del_cookie = del_colon = NULL;
2637 }
willy tarreau240afa62005-12-17 13:14:35 +01002638 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002639 }
willy tarreau240afa62005-12-17 13:14:35 +01002640
willy tarreau5cbea6f2005-12-17 12:48:26 +01002641 /* we'll have to look for another cookie ... */
2642 p1 = p4;
2643 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002644
2645 /* There's no more cookie on this line.
2646 * We may have marked the last one(s) for deletion.
2647 * We must do this now in two ways :
2648 * - if there is no app cookie, we simply delete the header ;
2649 * - if there are app cookies, we must delete the end of the
2650 * string properly, including the colon/semi-colon before
2651 * the cookie name.
2652 */
2653 if (del_cookie != NULL) {
2654 if (app_cookies) {
2655 buffer_replace2(req, del_colon, ptr, NULL, 0);
2656 /* WARNING! <ptr> becomes invalid for now. If some code
2657 * below needs to rely on it before the end of the global
2658 * header loop, we need to correct it with this code :
2659 * ptr = del_colon;
2660 */
2661 }
2662 else
2663 delete_header = 1;
2664 }
2665 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002666
2667 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002668 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002669 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002670 }
willy tarreau240afa62005-12-17 13:14:35 +01002671 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2672
willy tarreau5cbea6f2005-12-17 12:48:26 +01002673 req->h = req->lr;
2674 } /* while (req->lr < req->r) */
2675
2676 /* end of header processing (even if incomplete) */
2677
willy tarreauef900ab2005-12-17 12:52:52 +01002678 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2679 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2680 * full. We cannot loop here since event_cli_read will disable it only if
2681 * req->l == rlim-data
2682 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002683 FD_SET(t->cli_fd, StaticReadEvent);
2684 if (t->proxy->clitimeout)
2685 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2686 else
2687 tv_eternity(&t->crexpire);
2688 }
2689
willy tarreaue39cd132005-12-17 13:00:18 +01002690 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002691 * won't be able to free more later, so the session will never terminate.
2692 */
willy tarreaue39cd132005-12-17 13:00:18 +01002693 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002694 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01002695 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreaue39cd132005-12-17 13:00:18 +01002696 return 1;
2697 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002698 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
2699 /* read error, or last read : give up.
willy tarreaue39cd132005-12-17 13:00:18 +01002700 * since we are in header mode, if there's no space left for headers, we
2701 * won't be able to free more later, so the session will never terminate.
2702 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002703 tv_eternity(&t->crexpire);
2704 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002705 t->cli_state = CL_STCLOSE;
2706 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002707 }
willy tarreau8337c6b2005-12-17 13:41:01 +01002708 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2709
2710 /* read timeout : give up with an error message.
2711 */
2712 t->logs.status = 408;
2713 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
2714 return 1;
2715 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002716
2717 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002718 }
2719 else if (c == CL_STDATA) {
2720 /* read or write error */
2721 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002722 tv_eternity(&t->crexpire);
2723 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002724 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002725 t->cli_state = CL_STCLOSE;
2726 return 1;
2727 }
2728 /* read timeout, last read, or end of server write */
2729 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2730 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002731 FD_CLR(t->cli_fd, StaticReadEvent);
2732 // if (req->l == 0) /* nothing to write on the server side */
2733 // FD_CLR(t->srv_fd, StaticWriteEvent);
2734 tv_eternity(&t->crexpire);
2735 shutdown(t->cli_fd, SHUT_RD);
2736 t->cli_state = CL_STSHUTR;
2737 return 1;
2738 }
2739 /* write timeout, or last server read and buffer empty */
2740 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2741 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002742 FD_CLR(t->cli_fd, StaticWriteEvent);
2743 tv_eternity(&t->cwexpire);
2744 shutdown(t->cli_fd, SHUT_WR);
2745 t->cli_state = CL_STSHUTW;
2746 return 1;
2747 }
2748
willy tarreauef900ab2005-12-17 12:52:52 +01002749 if (req->l >= req->rlim - req->data) {
2750 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002751 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002752 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002753 FD_CLR(t->cli_fd, StaticReadEvent);
2754 tv_eternity(&t->crexpire);
2755 }
2756 }
2757 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002758 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002759 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2760 FD_SET(t->cli_fd, StaticReadEvent);
2761 if (t->proxy->clitimeout)
2762 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2763 else
2764 tv_eternity(&t->crexpire);
2765 }
2766 }
2767
2768 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002769 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002770 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2771 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2772 tv_eternity(&t->cwexpire);
2773 }
2774 }
2775 else { /* buffer not empty */
2776 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2777 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2778 if (t->proxy->clitimeout)
2779 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2780 else
2781 tv_eternity(&t->cwexpire);
2782 }
2783 }
2784 return 0; /* other cases change nothing */
2785 }
2786 else if (c == CL_STSHUTR) {
2787 if ((t->res_cw == RES_ERROR) ||
2788 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002789 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002790 tv_eternity(&t->cwexpire);
2791 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002792 t->cli_state = CL_STCLOSE;
2793 return 1;
2794 }
2795 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002796 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002797 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2798 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2799 tv_eternity(&t->cwexpire);
2800 }
2801 }
2802 else { /* buffer not empty */
2803 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2804 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2805 if (t->proxy->clitimeout)
2806 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2807 else
2808 tv_eternity(&t->cwexpire);
2809 }
2810 }
2811 return 0;
2812 }
2813 else if (c == CL_STSHUTW) {
2814 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002815 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002816 tv_eternity(&t->crexpire);
2817 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002818 t->cli_state = CL_STCLOSE;
2819 return 1;
2820 }
willy tarreauef900ab2005-12-17 12:52:52 +01002821 else if (req->l >= req->rlim - req->data) {
2822 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002823 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002824 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002825 FD_CLR(t->cli_fd, StaticReadEvent);
2826 tv_eternity(&t->crexpire);
2827 }
2828 }
2829 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002830 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002831 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2832 FD_SET(t->cli_fd, StaticReadEvent);
2833 if (t->proxy->clitimeout)
2834 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2835 else
2836 tv_eternity(&t->crexpire);
2837 }
2838 }
2839 return 0;
2840 }
2841 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002842 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002843 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002844 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002845 write(1, trash, len);
2846 }
2847 return 0;
2848 }
2849 return 0;
2850}
2851
2852
2853/*
2854 * manages the server FSM and its socket. It returns 1 if a state has changed
2855 * (and a resync may be needed), 0 else.
2856 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002857int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002858 int s = t->srv_state;
2859 int c = t->cli_state;
2860 struct buffer *req = t->req;
2861 struct buffer *rep = t->rep;
2862
willy tarreau750a4722005-12-17 13:21:24 +01002863#ifdef DEBUG_FULL
2864 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2865#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002866 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2867 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2868 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2869 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002870 if (s == SV_STIDLE) {
2871 if (c == CL_STHEADERS)
2872 return 0; /* stay in idle, waiting for data to reach the client side */
2873 else if (c == CL_STCLOSE ||
2874 c == CL_STSHUTW ||
2875 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2876 tv_eternity(&t->cnexpire);
2877 t->srv_state = SV_STCLOSE;
2878 return 1;
2879 }
2880 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002881 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002882 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2883 t->srv_state = SV_STCONN;
2884 }
2885 else { /* try again */
2886 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002887 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002888 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002889 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2890 }
2891
2892 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002893 t->srv_state = SV_STCONN;
2894 break;
2895 }
2896 }
2897 if (t->conn_retries < 0) {
2898 /* if conn_retries < 0 or other error, let's abort */
2899 tv_eternity(&t->cnexpire);
2900 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01002901 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01002902 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01002903 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau0f7af912005-12-17 12:21:26 +01002904 }
2905 }
2906 return 1;
2907 }
2908 }
2909 else if (s == SV_STCONN) { /* connection in progress */
2910 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2911 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2912 return 0; /* nothing changed */
2913 }
2914 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2915 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2916 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002917 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002918 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002919 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002920 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002921 if (t->conn_retries >= 0) {
2922 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002923 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002924 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2925 }
2926 if (connect_server(t) == 0)
2927 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002928 }
2929 /* if conn_retries < 0 or other error, let's abort */
2930 tv_eternity(&t->cnexpire);
2931 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01002932 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01002933 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01002934 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau0f7af912005-12-17 12:21:26 +01002935 return 1;
2936 }
2937 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01002938 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01002939
willy tarreau0f7af912005-12-17 12:21:26 +01002940 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2941 if (req->l == 0) /* nothing to write */
2942 FD_CLR(t->srv_fd, StaticWriteEvent);
2943 else /* need the right to write */
2944 FD_SET(t->srv_fd, StaticWriteEvent);
2945
2946 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2947 FD_SET(t->srv_fd, StaticReadEvent);
2948 if (t->proxy->srvtimeout)
2949 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2950 else
2951 tv_eternity(&t->srexpire);
2952
2953 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002954 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002955 }
willy tarreauef900ab2005-12-17 12:52:52 +01002956 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002957 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002958 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2959 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002960 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002961 return 1;
2962 }
2963 }
2964 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002965
2966 /* now parse the partial (or complete) headers */
2967 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2968 char *ptr;
2969 int delete_header;
2970
2971 ptr = rep->lr;
2972
2973 /* look for the end of the current header */
2974 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2975 ptr++;
2976
2977 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002978 int line, len;
2979
2980 /* we can only get here after an end of headers */
2981 /* we'll have something else to do here : add new headers ... */
2982
willy tarreaucd878942005-12-17 13:27:43 +01002983 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
2984 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002985 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01002986 * insert a set-cookie here, except if we want to insert only on POST
2987 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01002988 */
willy tarreau750a4722005-12-17 13:21:24 +01002989 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01002990 t->proxy->cookie_name,
2991 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01002992
2993 /* Here, we will tell an eventual cache on the client side that we don't
2994 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
2995 * Some caches understand the correct form: 'no-cache="set-cookie"', but
2996 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
2997 */
willy tarreau240afa62005-12-17 13:14:35 +01002998 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01002999 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3000 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003001
willy tarreau750a4722005-12-17 13:21:24 +01003002 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003003 }
3004
3005 /* headers to be added */
3006 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003007 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3008 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003009 }
3010
3011 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003012 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003013 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003014 break;
3015 }
3016
3017 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3018 if (ptr > rep->r - 2) {
3019 /* this is a partial header, let's wait for more to come */
3020 rep->lr = ptr;
3021 break;
3022 }
3023
3024 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3025 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3026
3027 /* now we know that *ptr is either \r or \n,
3028 * and that there are at least 1 char after it.
3029 */
3030 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3031 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3032 else
3033 rep->lr = ptr + 2; /* \r\n or \n\r */
3034
3035 /*
3036 * now we know that we have a full header ; we can do whatever
3037 * we want with these pointers :
3038 * rep->h = beginning of header
3039 * ptr = end of header (first \r or \n)
3040 * rep->lr = beginning of next line (next rep->h)
3041 * rep->r = end of data (not used at this stage)
3042 */
3043
willy tarreaua1598082005-12-17 13:08:06 +01003044
3045 if (t->logs.logwait & LW_RESP) {
3046 t->logs.logwait &= ~LW_RESP;
3047 t->logs.status = atoi(rep->h + 9);
3048 }
3049
willy tarreau5cbea6f2005-12-17 12:48:26 +01003050 delete_header = 0;
3051
willy tarreau9fe663a2005-12-17 13:02:59 +01003052 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003053 int len, max;
3054 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
3055 max = ptr - rep->h;
3056 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003057 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003058 trash[len++] = '\n';
3059 write(1, trash, len);
3060 }
3061
3062 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01003063 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
3064 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003065 char term;
3066
3067 term = *ptr;
3068 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003069 exp = t->proxy->rsp_exp;
3070 do {
3071 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3072 switch (exp->action) {
3073 case ACT_ALLOW:
3074 if (!(t->flags & SN_SVDENY))
3075 t->flags |= SN_SVALLOW;
3076 break;
3077 case ACT_REPLACE:
3078 if (!(t->flags & SN_SVDENY)) {
3079 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3080 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3081 }
3082 break;
3083 case ACT_REMOVE:
3084 if (!(t->flags & SN_SVDENY))
3085 delete_header = 1;
3086 break;
3087 case ACT_DENY:
3088 if (!(t->flags & SN_SVALLOW))
3089 t->flags |= SN_SVDENY;
3090 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003091 }
3092 break;
3093 }
willy tarreaue39cd132005-12-17 13:00:18 +01003094 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003095 *ptr = term; /* restore the string terminator */
3096 }
3097
3098 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01003099 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
3100 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL)
3101 && (ptr >= rep->h + 12)
3102 && (memcmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103 char *p1, *p2, *p3, *p4;
3104
3105 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
3106
3107 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01003108 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003109 p1++;
3110
3111 if (p1 == ptr || *p1 == ';') /* end of cookie */
3112 break;
3113
3114 /* p1 is at the beginning of the cookie name */
3115 p2 = p1;
3116
3117 while (p2 < ptr && *p2 != '=' && *p2 != ';')
3118 p2++;
3119
3120 if (p2 == ptr || *p2 == ';') /* next cookie */
3121 break;
3122
3123 p3 = p2 + 1; /* skips the '=' sign */
3124 if (p3 == ptr)
3125 break;
3126
3127 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01003128 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003129 p4++;
3130
3131 /* here, we have the cookie name between p1 and p2,
3132 * and its value between p3 and p4.
3133 * we can process it.
3134 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003135
3136 /* first, let's see if we want to capture it */
3137 if (t->proxy->capture_name != NULL &&
3138 t->logs.srv_cookie == NULL &&
3139 (p4 - p1 >= t->proxy->capture_namelen) &&
3140 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3141 int log_len = p4 - p1;
3142
3143 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
3144 Alert("HTTP logging : out of memory.\n");
3145 }
3146
3147 if (log_len > t->proxy->capture_len)
3148 log_len = t->proxy->capture_len;
3149 memcpy(t->logs.srv_cookie, p1, log_len);
3150 t->logs.srv_cookie[log_len] = 0;
3151 }
3152
3153 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3154 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003155 /* Cool... it's the right one */
3156
3157 /* If the cookie is in insert mode on a known server, we'll delete
3158 * this occurrence because we'll insert another one later.
3159 * We'll delete it too if the "indirect" option is set and we're in
3160 * a direct access. */
3161 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003162 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003163 /* this header must be deleted */
3164 delete_header = 1;
3165 }
3166 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3167 /* replace bytes p3->p4 with the cookie name associated
3168 * with this server since we know it.
3169 */
3170 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
3171 }
3172 break;
3173 }
3174 else {
3175 // fprintf(stderr,"Ignoring unknown cookie : ");
3176 // write(2, p1, p2-p1);
3177 // fprintf(stderr," = ");
3178 // write(2, p3, p4-p3);
3179 // fprintf(stderr,"\n");
3180 }
3181 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3182 } /* we're now at the end of the cookie value */
3183 } /* end of cookie processing */
3184
3185 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003186 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003187 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003188
willy tarreau5cbea6f2005-12-17 12:48:26 +01003189 rep->h = rep->lr;
3190 } /* while (rep->lr < rep->r) */
3191
3192 /* end of header processing (even if incomplete) */
3193
willy tarreauef900ab2005-12-17 12:52:52 +01003194 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3195 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3196 * full. We cannot loop here since event_srv_read will disable it only if
3197 * rep->l == rlim-data
3198 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003199 FD_SET(t->srv_fd, StaticReadEvent);
3200 if (t->proxy->srvtimeout)
3201 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3202 else
3203 tv_eternity(&t->srexpire);
3204 }
willy tarreau0f7af912005-12-17 12:21:26 +01003205
willy tarreau8337c6b2005-12-17 13:41:01 +01003206 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01003207 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003208 tv_eternity(&t->srexpire);
3209 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003210 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003211 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003212 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01003213 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau0f7af912005-12-17 12:21:26 +01003214 return 1;
3215 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003216 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01003217 * since we are in header mode, if there's no space left for headers, we
3218 * won't be able to free more later, so the session will never terminate.
3219 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003220 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE || rep->l >= rep->rlim - rep->data) {
willy tarreau0f7af912005-12-17 12:21:26 +01003221 FD_CLR(t->srv_fd, StaticReadEvent);
3222 tv_eternity(&t->srexpire);
3223 shutdown(t->srv_fd, SHUT_RD);
3224 t->srv_state = SV_STSHUTR;
3225 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01003226 }
3227 /* read timeout : return a 504 to the client.
3228 */
3229 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
3230 tv_eternity(&t->srexpire);
3231 tv_eternity(&t->swexpire);
3232 fd_delete(t->srv_fd);
3233 t->srv_state = SV_STCLOSE;
3234 t->logs.status = 504;
3235 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
3236 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003237
3238 }
3239 /* write timeout, or last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003240 /* FIXME!!! here, we don't want to switch to SHUTW if the
3241 * client shuts read too early, because we may still have
3242 * some work to do on the headers.
3243 */
3244 else if (((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) ||
willy tarreau8337c6b2005-12-17 13:41:01 +01003245 (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003246 FD_CLR(t->srv_fd, StaticWriteEvent);
3247 tv_eternity(&t->swexpire);
3248 shutdown(t->srv_fd, SHUT_WR);
3249 t->srv_state = SV_STSHUTW;
3250 return 1;
3251 }
3252
3253 if (req->l == 0) {
3254 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3255 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3256 tv_eternity(&t->swexpire);
3257 }
3258 }
3259 else { /* client buffer not empty */
3260 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3261 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3262 if (t->proxy->srvtimeout)
3263 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3264 else
3265 tv_eternity(&t->swexpire);
3266 }
3267 }
3268
willy tarreau5cbea6f2005-12-17 12:48:26 +01003269 /* be nice with the client side which would like to send a complete header
3270 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3271 * would read all remaining data at once ! The client should not write past rep->lr
3272 * when the server is in header state.
3273 */
3274 //return header_processed;
3275 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003276 }
3277 else if (s == SV_STDATA) {
3278 /* read or write error */
3279 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003280 tv_eternity(&t->srexpire);
3281 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003282 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003283 t->srv_state = SV_STCLOSE;
3284 return 1;
3285 }
3286 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01003287 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
3288 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003289 FD_CLR(t->srv_fd, StaticReadEvent);
3290 tv_eternity(&t->srexpire);
3291 shutdown(t->srv_fd, SHUT_RD);
3292 t->srv_state = SV_STSHUTR;
3293 return 1;
3294
3295 }
3296 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01003297 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
3298 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003299 FD_CLR(t->srv_fd, StaticWriteEvent);
3300 tv_eternity(&t->swexpire);
3301 shutdown(t->srv_fd, SHUT_WR);
3302 t->srv_state = SV_STSHUTW;
3303 return 1;
3304 }
3305 else if (req->l == 0) {
3306 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3307 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3308 tv_eternity(&t->swexpire);
3309 }
3310 }
3311 else { /* buffer not empty */
3312 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3313 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3314 if (t->proxy->srvtimeout)
3315 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3316 else
3317 tv_eternity(&t->swexpire);
3318 }
3319 }
3320
3321 if (rep->l == BUFSIZE) { /* no room to read more data */
3322 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3323 FD_CLR(t->srv_fd, StaticReadEvent);
3324 tv_eternity(&t->srexpire);
3325 }
3326 }
3327 else {
3328 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3329 FD_SET(t->srv_fd, StaticReadEvent);
3330 if (t->proxy->srvtimeout)
3331 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3332 else
3333 tv_eternity(&t->srexpire);
3334 }
3335 }
3336
3337 return 0; /* other cases change nothing */
3338 }
3339 else if (s == SV_STSHUTR) {
3340 if ((t->res_sw == RES_ERROR) ||
3341 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
3342 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003343 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003344 tv_eternity(&t->swexpire);
3345 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003346 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003347 t->srv_state = SV_STCLOSE;
3348 return 1;
3349 }
3350 else if (req->l == 0) {
3351 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3352 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3353 tv_eternity(&t->swexpire);
3354 }
3355 }
3356 else { /* buffer not empty */
3357 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3358 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3359 if (t->proxy->srvtimeout)
3360 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3361 else
3362 tv_eternity(&t->swexpire);
3363 }
3364 }
3365 return 0;
3366 }
3367 else if (s == SV_STSHUTW) {
3368 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
3369 c == CL_STSHUTW || c == CL_STCLOSE ||
3370 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003371 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003372 tv_eternity(&t->srexpire);
3373 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003374 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003375 t->srv_state = SV_STCLOSE;
3376 return 1;
3377 }
3378 else if (rep->l == BUFSIZE) { /* no room to read more data */
3379 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3380 FD_CLR(t->srv_fd, StaticReadEvent);
3381 tv_eternity(&t->srexpire);
3382 }
3383 }
3384 else {
3385 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3386 FD_SET(t->srv_fd, StaticReadEvent);
3387 if (t->proxy->srvtimeout)
3388 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3389 else
3390 tv_eternity(&t->srexpire);
3391 }
3392 }
3393 return 0;
3394 }
3395 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003396 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003397 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003398 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003399 write(1, trash, len);
3400 }
3401 return 0;
3402 }
3403 return 0;
3404}
3405
3406
willy tarreau5cbea6f2005-12-17 12:48:26 +01003407/* Processes the client and server jobs of a session task, then
3408 * puts it back to the wait queue in a clean state, or
3409 * cleans up its resources if it must be deleted. Returns
3410 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003411 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003412int process_session(struct task *t) {
3413 struct session *s = t->context;
3414 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003415
willy tarreau5cbea6f2005-12-17 12:48:26 +01003416 do {
3417 fsm_resync = 0;
3418 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3419 fsm_resync |= process_cli(s);
3420 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3421 fsm_resync |= process_srv(s);
3422 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3423 } while (fsm_resync);
3424
3425 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003426 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003427 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003428
willy tarreau5cbea6f2005-12-17 12:48:26 +01003429 tv_min(&min1, &s->crexpire, &s->cwexpire);
3430 tv_min(&min2, &s->srexpire, &s->swexpire);
3431 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003432 tv_min(&t->expire, &min1, &min2);
3433
3434 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003435 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003436
willy tarreau5cbea6f2005-12-17 12:48:26 +01003437 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003438 }
3439
willy tarreau5cbea6f2005-12-17 12:48:26 +01003440 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003441 actconn--;
3442
willy tarreau9fe663a2005-12-17 13:02:59 +01003443 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003444 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003445 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003446 write(1, trash, len);
3447 }
3448
willy tarreau750a4722005-12-17 13:21:24 +01003449 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003450 if (s->rep != NULL)
3451 s->logs.bytes = s->rep->total;
3452
willy tarreau9fe663a2005-12-17 13:02:59 +01003453 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003454 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003455 sess_log(s);
3456
willy tarreau0f7af912005-12-17 12:21:26 +01003457 /* the task MUST not be in the run queue anymore */
3458 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003459 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003460 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003461 return -1; /* rest in peace for eternity */
3462}
3463
3464
3465
3466/*
3467 * manages a server health-check. Returns
3468 * the time the task accepts to wait, or -1 for infinity.
3469 */
3470int process_chk(struct task *t) {
3471 struct server *s = t->context;
3472 int fd = s->curfd;
3473 int one = 1;
3474
willy tarreauef900ab2005-12-17 12:52:52 +01003475 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003476
3477 if (fd < 0) { /* no check currently running */
3478 //fprintf(stderr, "process_chk: 2\n");
3479 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3480 task_queue(t); /* restore t to its place in the task list */
3481 return tv_remain(&now, &t->expire);
3482 }
3483
3484 /* we'll initiate a new check */
3485 s->result = 0; /* no result yet */
3486 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003487 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003488 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3489 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3490 //fprintf(stderr, "process_chk: 3\n");
3491
3492 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
3493 /* OK, connection in progress or established */
3494
3495 //fprintf(stderr, "process_chk: 4\n");
3496
3497 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3498 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003499 fdtab[fd].read = &event_srv_chk_r;
3500 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003501 fdtab[fd].state = FD_STCONN; /* connection in progress */
3502 FD_SET(fd, StaticWriteEvent); /* for connect status */
3503 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003504 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3505 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003506 task_queue(t); /* restore t to its place in the task list */
3507 return tv_remain(&now, &t->expire);
3508 }
3509 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3510 s->result = -1; /* a real error */
3511 }
3512 }
3513 //fprintf(stderr, "process_chk: 5\n");
3514 close(fd);
3515 }
3516
3517 if (!s->result) { /* nothing done */
3518 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003519 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003520 task_queue(t); /* restore t to its place in the task list */
3521 return tv_remain(&now, &t->expire);
3522 }
3523
3524 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003525 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003526 s->health--; /* still good */
3527 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003528 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003529 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003530 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003531
willy tarreau9fe663a2005-12-17 13:02:59 +01003532 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003533 }
willy tarreauef900ab2005-12-17 12:52:52 +01003534
willy tarreau5cbea6f2005-12-17 12:48:26 +01003535 s->health = 0; /* failure */
3536 s->state &= ~SRV_RUNNING;
3537 }
3538
3539 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003540 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3541 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003542 }
3543 else {
3544 //fprintf(stderr, "process_chk: 8\n");
3545 /* there was a test running */
3546 if (s->result > 0) { /* good server detected */
3547 //fprintf(stderr, "process_chk: 9\n");
3548 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003549 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003550 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003551 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003552 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003553 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003554 }
willy tarreauef900ab2005-12-17 12:52:52 +01003555
willy tarreaue47c8d72005-12-17 12:55:52 +01003556 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003557 s->state |= SRV_RUNNING;
3558 }
willy tarreauef900ab2005-12-17 12:52:52 +01003559 s->curfd = -1; /* no check running anymore */
3560 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003561 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003562 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003563 }
3564 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3565 //fprintf(stderr, "process_chk: 10\n");
3566 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003567 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003568 s->health--; /* still good */
3569 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003570 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003571 if (!(global.mode & MODE_QUIET))
willy tarreau8337c6b2005-12-17 13:41:01 +01003572 Warning("server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003573
3574 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003575 }
willy tarreauef900ab2005-12-17 12:52:52 +01003576
willy tarreau5cbea6f2005-12-17 12:48:26 +01003577 s->health = 0; /* failure */
3578 s->state &= ~SRV_RUNNING;
3579 }
3580 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003581 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003582 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003583 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003584 }
3585 /* if result is 0 and there's no timeout, we have to wait again */
3586 }
3587 //fprintf(stderr, "process_chk: 11\n");
3588 s->result = 0;
3589 task_queue(t); /* restore t to its place in the task list */
3590 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003591}
3592
3593
willy tarreau5cbea6f2005-12-17 12:48:26 +01003594
willy tarreau0f7af912005-12-17 12:21:26 +01003595#if STATTIME > 0
3596int stats(void);
3597#endif
3598
3599/*
3600 * Main select() loop.
3601 */
3602
3603void select_loop() {
3604 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003605 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003606 int status;
3607 int fd,i;
3608 struct timeval delta;
3609 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003610 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003611
willy tarreau5cbea6f2005-12-17 12:48:26 +01003612 tv_now(&now);
3613
3614 while (1) {
3615 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003616
willy tarreau5cbea6f2005-12-17 12:48:26 +01003617 /* look for expired tasks and add them to the run queue.
3618 */
3619 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3620 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3621 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003622 if (t->state & TASK_RUNNING)
3623 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003624
3625 /* wakeup expired entries. It doesn't matter if they are
3626 * already running because of a previous event
3627 */
3628 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003629 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003630 task_wakeup(&rq, t);
3631 }
3632 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003633 /* first non-runnable task. Use its expiration date as an upper bound */
3634 int temp_time = tv_remain(&now, &t->expire);
3635 if (temp_time)
3636 next_time = temp_time;
3637 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003638 break;
3639 }
3640 }
3641
3642 /* process each task in the run queue now. Each task may be deleted
3643 * since we only use tnext.
3644 */
3645 tnext = rq;
3646 while ((t = tnext) != NULL) {
3647 int temp_time;
3648
3649 tnext = t->rqnext;
3650 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003651 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003652 temp_time = t->process(t);
3653 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003654 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003655 }
3656
willy tarreauef900ab2005-12-17 12:52:52 +01003657 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003658
3659 /* maintain all proxies in a consistent state. This should quickly become a task */
3660 time2 = maintain_proxies();
3661 next_time = MINTIME(time2, next_time);
3662
3663 /* stop when there's no connection left and we don't allow them anymore */
3664 if (!actconn && listeners == 0)
3665 break;
3666
willy tarreau0f7af912005-12-17 12:21:26 +01003667
3668#if STATTIME > 0
3669 time2 = stats();
3670 // fprintf(stderr," stats = %d\n", time2);
3671 next_time = MINTIME(time2, next_time);
3672#endif
3673
willy tarreau5cbea6f2005-12-17 12:48:26 +01003674 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003675 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003676 /* to avoid eventual select loops due to timer precision */
3677 next_time += SCHEDULER_RESOLUTION;
3678 delta.tv_sec = next_time / 1000;
3679 delta.tv_usec = (next_time % 1000) * 1000;
3680 }
3681 else if (next_time == 0) { /* allow select to return immediately when needed */
3682 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003683 }
3684
3685
3686 /* let's restore fdset state */
3687
3688 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003689 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003690 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3691 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3692 }
3693
3694// /* just a verification code, needs to be removed for performance */
3695// for (i=0; i<maxfd; i++) {
3696// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3697// abort();
3698// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3699// abort();
3700//
3701// }
3702
3703 status=select(maxfd,
3704 readnotnull ? ReadEvent : NULL,
3705 writenotnull ? WriteEvent : NULL,
3706 NULL,
3707 (next_time >= 0) ? &delta : NULL);
3708
willy tarreau5cbea6f2005-12-17 12:48:26 +01003709 /* this is an experiment on the separation of the select work */
3710 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3711 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3712
willy tarreau0f7af912005-12-17 12:21:26 +01003713 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003714
willy tarreau0f7af912005-12-17 12:21:26 +01003715 if (status > 0) { /* must proceed with events */
3716
3717 int fds;
3718 char count;
3719
3720 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3721 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3722 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3723
willy tarreau5cbea6f2005-12-17 12:48:26 +01003724 /* if we specify read first, the accepts and zero reads will be
3725 * seen first. Moreover, system buffers will be flushed faster.
3726 */
willy tarreau0f7af912005-12-17 12:21:26 +01003727 if (fdtab[fd].state == FD_STCLOSE)
3728 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003729
3730 if (FD_ISSET(fd, ReadEvent))
3731 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003732
willy tarreau5cbea6f2005-12-17 12:48:26 +01003733 if (FD_ISSET(fd, WriteEvent))
3734 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003735 }
3736 }
3737 else {
3738 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3739 }
willy tarreau0f7af912005-12-17 12:21:26 +01003740 }
3741}
3742
3743
3744#if STATTIME > 0
3745/*
3746 * Display proxy statistics regularly. It is designed to be called from the
3747 * select_loop().
3748 */
3749int stats(void) {
3750 static int lines;
3751 static struct timeval nextevt;
3752 static struct timeval lastevt;
3753 static struct timeval starttime = {0,0};
3754 unsigned long totaltime, deltatime;
3755 int ret;
3756
willy tarreau750a4722005-12-17 13:21:24 +01003757 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01003758 deltatime = (tv_diff(&lastevt, &now)?:1);
3759 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01003760
willy tarreau9fe663a2005-12-17 13:02:59 +01003761 if (global.mode & MODE_STATS) {
3762 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003763 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003764 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3765 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003766 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003767 actconn, totalconn,
3768 stats_tsk_new, stats_tsk_good,
3769 stats_tsk_left, stats_tsk_right,
3770 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3771 }
3772 }
3773
3774 tv_delayfrom(&nextevt, &now, STATTIME);
3775
3776 lastevt=now;
3777 }
3778 ret = tv_remain(&now, &nextevt);
3779 return ret;
3780}
3781#endif
3782
3783
3784/*
3785 * this function enables proxies when there are enough free sessions,
3786 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003787 * select_loop(). It returns the time left before next expiration event
3788 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003789 */
3790static int maintain_proxies(void) {
3791 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003792 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003793
3794 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003795 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003796
3797 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003798 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003799 while (p) {
3800 if (p->nbconn < p->maxconn) {
3801 if (p->state == PR_STIDLE) {
3802 FD_SET(p->listen_fd, StaticReadEvent);
3803 p->state = PR_STRUN;
3804 }
3805 }
3806 else {
3807 if (p->state == PR_STRUN) {
3808 FD_CLR(p->listen_fd, StaticReadEvent);
3809 p->state = PR_STIDLE;
3810 }
3811 }
3812 p = p->next;
3813 }
3814 }
3815 else { /* block all proxies */
3816 while (p) {
3817 if (p->state == PR_STRUN) {
3818 FD_CLR(p->listen_fd, StaticReadEvent);
3819 p->state = PR_STIDLE;
3820 }
3821 p = p->next;
3822 }
3823 }
3824
willy tarreau5cbea6f2005-12-17 12:48:26 +01003825 if (stopping) {
3826 p = proxy;
3827 while (p) {
3828 if (p->state != PR_STDISABLED) {
3829 int t;
3830 t = tv_remain(&now, &p->stop_time);
3831 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003832 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003833 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003834
willy tarreau5cbea6f2005-12-17 12:48:26 +01003835 fd_delete(p->listen_fd);
3836 p->state = PR_STDISABLED;
3837 listeners--;
3838 }
3839 else {
3840 tleft = MINTIME(t, tleft);
3841 }
3842 }
3843 p = p->next;
3844 }
3845 }
3846 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003847}
3848
3849/*
3850 * this function disables health-check servers so that the process will quickly be ignored
3851 * by load balancers.
3852 */
3853static void soft_stop(void) {
3854 struct proxy *p;
3855
3856 stopping = 1;
3857 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003858 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003859 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003860 if (p->state != PR_STDISABLED) {
3861 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01003862 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01003863 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01003864 }
willy tarreau0f7af912005-12-17 12:21:26 +01003865 p = p->next;
3866 }
3867}
3868
3869/*
3870 * upon SIGUSR1, let's have a soft stop.
3871 */
3872void sig_soft_stop(int sig) {
3873 soft_stop();
3874 signal(sig, SIG_IGN);
3875}
3876
3877
willy tarreau8337c6b2005-12-17 13:41:01 +01003878/*
3879 * this function dumps every server's state when the process receives SIGHUP.
3880 */
3881void sig_dump_state(int sig) {
3882 struct proxy *p = proxy;
3883
3884 Warning("SIGHUP received, dumping servers states.\n");
3885 while (p) {
3886 struct server *s = p->srv;
3887
3888 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
3889 while (s) {
3890 if (s->state & SRV_RUNNING) {
3891 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
3892 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
3893 }
3894 else {
3895 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
3896 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
3897 }
3898 s = s->next;
3899 }
3900 p = p->next;
3901 }
3902 signal(sig, sig_dump_state);
3903}
3904
willy tarreau0f7af912005-12-17 12:21:26 +01003905void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003906 struct task *t, *tnext;
3907 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003908
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3910 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3911 tnext = t->next;
3912 s = t->context;
3913 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3914 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3915 "req=%d, rep=%d, clifd=%d\n",
3916 s, tv_remain(&now, &t->expire),
3917 s->cli_state,
3918 s->srv_state,
3919 FD_ISSET(s->cli_fd, StaticReadEvent),
3920 FD_ISSET(s->cli_fd, StaticWriteEvent),
3921 FD_ISSET(s->srv_fd, StaticReadEvent),
3922 FD_ISSET(s->srv_fd, StaticWriteEvent),
3923 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3924 );
willy tarreau0f7af912005-12-17 12:21:26 +01003925 }
3926}
3927
willy tarreaue39cd132005-12-17 13:00:18 +01003928void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
3929 struct hdr_exp *exp;
3930
3931 while (*head != NULL)
3932 head = &(*head)->next;
3933
3934 exp = calloc(1, sizeof(struct hdr_exp));
3935
3936 exp->preg = preg;
3937 exp->replace = replace;
3938 exp->action = action;
3939 *head = exp;
3940}
3941
willy tarreau9fe663a2005-12-17 13:02:59 +01003942
willy tarreau0f7af912005-12-17 12:21:26 +01003943/*
willy tarreau9fe663a2005-12-17 13:02:59 +01003944 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01003945 */
willy tarreau9fe663a2005-12-17 13:02:59 +01003946int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01003947
willy tarreau9fe663a2005-12-17 13:02:59 +01003948 if (!strcmp(args[0], "global")) { /* new section */
3949 /* no option, nothing special to do */
3950 return 0;
3951 }
3952 else if (!strcmp(args[0], "daemon")) {
3953 global.mode |= MODE_DAEMON;
3954 }
3955 else if (!strcmp(args[0], "debug")) {
3956 global.mode |= MODE_DEBUG;
3957 }
3958 else if (!strcmp(args[0], "quiet")) {
3959 global.mode |= MODE_QUIET;
3960 }
3961 else if (!strcmp(args[0], "stats")) {
3962 global.mode |= MODE_STATS;
3963 }
3964 else if (!strcmp(args[0], "uid")) {
3965 if (global.uid != 0) {
3966 Alert("parsing [%s:%d] : <uid> already specified. Continuing.\n", file, linenum);
3967 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003968 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003969 if (*(args[1]) == 0) {
3970 Alert("parsing [%s:%d] : <uid> expects an integer argument.\n", file, linenum);
3971 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003973 global.uid = atol(args[1]);
3974 }
3975 else if (!strcmp(args[0], "gid")) {
3976 if (global.gid != 0) {
3977 Alert("parsing [%s:%d] : <gid> already specified. Continuing.\n", file, linenum);
3978 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003979 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003980 if (*(args[1]) == 0) {
3981 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003982 return -1;
3983 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003984 global.gid = atol(args[1]);
3985 }
3986 else if (!strcmp(args[0], "nbproc")) {
3987 if (global.nbproc != 0) {
3988 Alert("parsing [%s:%d] : <nbproc> already specified. Continuing.\n", file, linenum);
3989 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003990 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003991 if (*(args[1]) == 0) {
3992 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
3993 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003994 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003995 global.nbproc = atol(args[1]);
3996 }
3997 else if (!strcmp(args[0], "maxconn")) {
3998 if (global.maxconn != 0) {
3999 Alert("parsing [%s:%d] : <maxconn> already specified. Continuing.\n", file, linenum);
4000 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004001 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004002 if (*(args[1]) == 0) {
4003 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
4004 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004005 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004006 global.maxconn = atol(args[1]);
4007 }
4008 else if (!strcmp(args[0], "chroot")) {
4009 if (global.chroot != NULL) {
4010 Alert("parsing [%s:%d] : <chroot> already specified. Continuing.\n", file, linenum);
4011 return 0;
4012 }
4013 if (*(args[1]) == 0) {
4014 Alert("parsing [%s:%d] : <chroot> expects a directory as an argument.\n", file, linenum);
4015 return -1;
4016 }
4017 global.chroot = strdup(args[1]);
4018 }
4019 else if (!strcmp(args[0], "log")) { /* syslog server address */
4020 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01004021 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004022
4023 if (*(args[1]) == 0 || *(args[2]) == 0) {
4024 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n", file, linenum);
4025 return -1;
4026 }
4027
4028 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4029 if (!strcmp(log_facilities[facility], args[2]))
4030 break;
4031
4032 if (facility >= NB_LOG_FACILITIES) {
4033 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
4034 exit(1);
4035 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004036
4037 level = 7; /* max syslog level = debug */
4038 if (*(args[3])) {
4039 while (level >= 0 && strcmp(log_levels[level], args[3]))
4040 level--;
4041 if (level < 0) {
4042 Alert("parsing [%s:%d] : unknown optionnal log level <%s>\n", file, linenum, args[3]);
4043 exit(1);
4044 }
4045 }
4046
willy tarreau9fe663a2005-12-17 13:02:59 +01004047 sa = str2sa(args[1]);
4048 if (!sa->sin_port)
4049 sa->sin_port = htons(SYSLOG_PORT);
4050
4051 if (global.logfac1 == -1) {
4052 global.logsrv1 = *sa;
4053 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004054 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004055 }
4056 else if (global.logfac2 == -1) {
4057 global.logsrv2 = *sa;
4058 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004059 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01004060 }
4061 else {
4062 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
4063 return -1;
4064 }
4065
4066 }
4067 else {
4068 Alert("parsing [%s:%d] : unknown keyword <%s> in <global> section\n", file, linenum, args[0]);
4069 return -1;
4070 }
4071 return 0;
4072}
4073
4074
4075/*
4076 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
4077 */
4078int cfg_parse_listen(char *file, int linenum, char **args) {
4079 static struct proxy *curproxy = NULL;
4080 struct server *newsrv = NULL;
4081
4082 if (!strcmp(args[0], "listen")) { /* new proxy */
4083 if (strchr(args[2], ':') == NULL) {
4084 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
4085 file, linenum);
4086 return -1;
4087 }
4088
4089 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
4090 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
4091 return -1;
4092 }
4093 curproxy->next = proxy;
4094 proxy = curproxy;
4095 curproxy->id = strdup(args[1]);
4096 curproxy->listen_addr = *str2sa(args[2]);
4097 curproxy->state = PR_STNEW;
4098 /* set default values */
4099 curproxy->maxconn = cfg_maxpconn;
4100 curproxy->conn_retries = CONN_RETRIES;
4101 curproxy->options = 0;
4102 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
4103 curproxy->mode = PR_MODE_TCP;
4104 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
4105 curproxy->to_log = 0;
4106 return 0;
4107 }
4108 else if (curproxy == NULL) {
4109 Alert("parsing [%s:%d] : <listen> expected.\n", file, linenum);
4110 return -1;
4111 }
4112
4113 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
4114 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
4115 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
4116 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
4117 else {
4118 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
4119 return -1;
4120 }
4121 }
4122 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
4123 curproxy->state = PR_STDISABLED;
4124 }
4125 else if (!strcmp(args[0], "cookie")) { /* cookie name */
4126 int cur_arg;
4127 if (curproxy->cookie_name != NULL) {
4128 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
4129 file, linenum);
4130 return 0;
4131 }
4132
4133 if (*(args[1]) == 0) {
4134 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
4135 file, linenum);
4136 return -1;
4137 }
4138 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01004139 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01004140
4141 cur_arg = 2;
4142 while (*(args[cur_arg])) {
4143 if (!strcmp(args[cur_arg], "rewrite")) {
4144 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01004145 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004146 else if (!strcmp(args[cur_arg], "indirect")) {
4147 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01004148 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004149 else if (!strcmp(args[cur_arg], "insert")) {
4150 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01004151 }
willy tarreau240afa62005-12-17 13:14:35 +01004152 else if (!strcmp(args[cur_arg], "nocache")) {
4153 curproxy->options |= PR_O_COOK_NOC;
4154 }
willy tarreaucd878942005-12-17 13:27:43 +01004155 else if (!strcmp(args[cur_arg], "postonly")) {
4156 curproxy->options |= PR_O_COOK_POST;
4157 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004158 else {
willy tarreaucd878942005-12-17 13:27:43 +01004159 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004160 file, linenum);
4161 return -1;
4162 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004163 cur_arg++;
4164 }
4165 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
4166 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
4167 file, linenum);
4168 return -1;
4169 }
4170 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004171 else if (!strcmp(args[0], "capture")) { /* name of a cookie to capture */
4172 if (curproxy->capture_name != NULL) {
4173 Alert("parsing [%s:%d] : capture already specified. Continuing.\n",
4174 file, linenum);
4175 return 0;
4176 }
4177
4178 if (*(args[4]) == 0) {
4179 Alert("parsing [%s:%d] : <capture> expects 'cookie' <cookie_name> 'len' <len>.\n",
4180 file, linenum);
4181 return -1;
4182 }
4183 curproxy->capture_name = strdup(args[2]);
4184 curproxy->capture_namelen = strlen(curproxy->capture_name);
4185 curproxy->capture_len = atol(args[4]);
4186 if (curproxy->capture_len >= CAPTURE_LEN) {
4187 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
4188 file, linenum, CAPTURE_LEN - 1);
4189 curproxy->capture_len = CAPTURE_LEN - 1;
4190 }
4191 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004192 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
4193 if (curproxy->contimeout != 0) {
4194 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n", file, linenum);
4195 return 0;
4196 }
4197 if (*(args[1]) == 0) {
4198 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
4199 file, linenum);
4200 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004201 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004202 curproxy->contimeout = atol(args[1]);
4203 }
4204 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
4205 if (curproxy->clitimeout != 0) {
4206 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
4207 file, linenum);
4208 return 0;
4209 }
4210 if (*(args[1]) == 0) {
4211 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
4212 file, linenum);
4213 return -1;
4214 }
4215 curproxy->clitimeout = atol(args[1]);
4216 }
4217 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
4218 if (curproxy->srvtimeout != 0) {
4219 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n", file, linenum);
4220 return 0;
4221 }
4222 if (*(args[1]) == 0) {
4223 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004224 file, linenum);
4225 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004226 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004227 curproxy->srvtimeout = atol(args[1]);
4228 }
4229 else if (!strcmp(args[0], "retries")) { /* connection retries */
4230 if (*(args[1]) == 0) {
4231 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
4232 file, linenum);
4233 return -1;
4234 }
4235 curproxy->conn_retries = atol(args[1]);
4236 }
4237 else if (!strcmp(args[0], "option")) {
4238 if (*(args[1]) == 0) {
4239 Alert("parsing [%s:%d] : <option> expects an option name.\n", file, linenum);
4240 return -1;
4241 }
4242 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004243 /* enable reconnections to dispatch */
4244 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004245#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004246 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004247 /* enable transparent proxy connections */
4248 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004249#endif
4250 else if (!strcmp(args[1], "keepalive"))
4251 /* enable keep-alive */
4252 curproxy->options |= PR_O_KEEPALIVE;
4253 else if (!strcmp(args[1], "forwardfor"))
4254 /* insert x-forwarded-for field */
4255 curproxy->options |= PR_O_FWDFOR;
4256 else if (!strcmp(args[1], "httplog")) {
4257 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01004258 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
4259 }
4260 else if (!strcmp(args[1], "dontlognull")) {
4261 /* don't log empty requests */
4262 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004263 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004264 else if (!strcmp(args[1], "httpchk")) {
4265 /* use HTTP request to check servers' health */
4266 curproxy->options |= PR_O_HTTP_CHK;
4267 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004268 else if (!strcmp(args[1], "persist")) {
4269 /* persist on using the server specified by the cookie, even when it's down */
4270 curproxy->options |= PR_O_PERSIST;
4271 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004272 else {
4273 Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
4274 return -1;
4275 }
4276 return 0;
4277 }
4278 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4279 /* enable reconnections to dispatch */
4280 curproxy->options |= PR_O_REDISP;
4281 }
willy tarreaua1598082005-12-17 13:08:06 +01004282#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004283 else if (!strcmp(args[0], "transparent")) {
4284 /* enable transparent proxy connections */
4285 curproxy->options |= PR_O_TRANSP;
4286 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004287#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004288 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4289 if (*(args[1]) == 0) {
4290 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
4291 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004292 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004293 curproxy->maxconn = atol(args[1]);
4294 }
4295 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4296 if (*(args[1]) == 0) {
4297 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n", file, linenum);
4298 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004299 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004300 curproxy->grace = atol(args[1]);
4301 }
4302 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
4303 if (strchr(args[1], ':') == NULL) {
4304 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n", file, linenum);
4305 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004306 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004307 curproxy->dispatch_addr = *str2sa(args[1]);
4308 }
4309 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
4310 if (*(args[1])) {
4311 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004312 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004313 }
4314 else {
4315 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n", file, linenum);
4316 return -1;
4317 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004318 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004319 else /* if no option is set, use round-robin by default */
4320 curproxy->options |= PR_O_BALANCE_RR;
4321 }
4322 else if (!strcmp(args[0], "server")) { /* server address */
4323 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004324
willy tarreau9fe663a2005-12-17 13:02:59 +01004325 if (strchr(args[2], ':') == NULL) {
4326 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
4327 file, linenum);
4328 return -1;
4329 }
4330 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4331 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4332 return -1;
4333 }
4334 newsrv->next = curproxy->srv;
4335 curproxy->srv = newsrv;
4336 newsrv->proxy = curproxy;
4337 newsrv->id = strdup(args[1]);
4338 newsrv->addr = *str2sa(args[2]);
4339 newsrv->state = SRV_RUNNING; /* early server setup */
4340 newsrv->curfd = -1; /* no health-check in progress */
4341 newsrv->inter = DEF_CHKINTR;
4342 newsrv->rise = DEF_RISETIME;
4343 newsrv->fall = DEF_FALLTIME;
4344 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4345 cur_arg = 3;
4346 while (*args[cur_arg]) {
4347 if (!strcmp(args[cur_arg], "cookie")) {
4348 newsrv->cookie = strdup(args[cur_arg + 1]);
4349 newsrv->cklen = strlen(args[cur_arg + 1]);
4350 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004351 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004352 else if (!strcmp(args[cur_arg], "rise")) {
4353 newsrv->rise = atol(args[cur_arg + 1]);
4354 newsrv->health = newsrv->rise;
4355 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004356 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004357 else if (!strcmp(args[cur_arg], "fall")) {
4358 newsrv->fall = atol(args[cur_arg + 1]);
4359 cur_arg += 2;
4360 }
4361 else if (!strcmp(args[cur_arg], "inter")) {
4362 newsrv->inter = atol(args[cur_arg + 1]);
4363 cur_arg += 2;
4364 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004365 else if (!strcmp(args[cur_arg], "backup")) {
4366 newsrv->state |= SRV_BACKUP;
4367 cur_arg ++;
4368 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004369 else if (!strcmp(args[cur_arg], "check")) {
4370 struct task *t;
4371
4372 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
4373 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004374 return -1;
4375 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004376
4377 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4378 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4379 t->state = TASK_IDLE;
4380 t->process = process_chk;
4381 t->context = newsrv;
4382
4383 if (curproxy->state != PR_STDISABLED) {
4384 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4385 task_queue(t);
4386 task_wakeup(&rq, t);
4387 }
4388
4389 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004390 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004391 else {
4392 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
4393 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004394 return -1;
4395 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004396 }
4397 curproxy->nbservers++;
4398 }
4399 else if (!strcmp(args[0], "log")) { /* syslog server address */
4400 struct sockaddr_in *sa;
4401 int facility;
4402
4403 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4404 curproxy->logfac1 = global.logfac1;
4405 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004406 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01004407 curproxy->logfac2 = global.logfac2;
4408 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01004409 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01004410 }
4411 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01004412 int level;
4413
willy tarreau0f7af912005-12-17 12:21:26 +01004414 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4415 if (!strcmp(log_facilities[facility], args[2]))
4416 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004417
willy tarreau0f7af912005-12-17 12:21:26 +01004418 if (facility >= NB_LOG_FACILITIES) {
4419 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
4420 exit(1);
4421 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004422
willy tarreau8337c6b2005-12-17 13:41:01 +01004423 level = 7; /* max syslog level = debug */
4424 if (*(args[3])) {
4425 while (level >= 0 && strcmp(log_levels[level], args[3]))
4426 level--;
4427 if (level < 0) {
4428 Alert("parsing [%s:%d] : unknown optionnal log level <%s>\n", file, linenum, args[3]);
4429 exit(1);
4430 }
4431 }
4432
willy tarreau0f7af912005-12-17 12:21:26 +01004433 sa = str2sa(args[1]);
4434 if (!sa->sin_port)
4435 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004436
willy tarreau0f7af912005-12-17 12:21:26 +01004437 if (curproxy->logfac1 == -1) {
4438 curproxy->logsrv1 = *sa;
4439 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004440 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004441 }
4442 else if (curproxy->logfac2 == -1) {
4443 curproxy->logsrv2 = *sa;
4444 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01004445 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01004446 }
4447 else {
4448 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004449 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004450 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004451 }
4452 else {
4453 Alert("parsing [%s:%d] : <log> expects either <address[:port]> and <facility> or 'global' as arguments.\n",
4454 file, linenum);
4455 return -1;
4456 }
4457 }
willy tarreaua1598082005-12-17 13:08:06 +01004458 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
4459 if (strchr(args[1], ':') == NULL) {
4460 Alert("parsing [%s:%d] : <source> expects <addr:port> as argument.\n",
4461 file, linenum);
4462 return -1;
4463 }
4464
4465 curproxy->source_addr = *str2sa(args[1]);
4466 curproxy->options |= PR_O_BIND_SRC;
4467 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004468 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4469 regex_t *preg;
4470
4471 if (*(args[1]) == 0 || *(args[2]) == 0) {
4472 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
4473 file, linenum);
4474 return -1;
4475 }
4476
4477 preg = calloc(1, sizeof(regex_t));
4478 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4479 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4480 return -1;
4481 }
4482
4483 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4484 }
4485 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4486 regex_t *preg;
4487
4488 if (*(args[1]) == 0) {
4489 Alert("parsing [%s:%d] : <reqdel> expects <regex> as an argument.\n", file, linenum);
4490 return -1;
4491 }
4492
4493 preg = calloc(1, sizeof(regex_t));
4494 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4495 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4496 return -1;
4497 }
4498
4499 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4500 }
4501 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
4502 regex_t *preg;
4503
4504 if (*(args[1]) == 0) {
4505 Alert("parsing [%s:%d] : <reqdeny> expects <regex> as an argument.\n", file, linenum);
4506 return -1;
4507 }
4508
4509 preg = calloc(1, sizeof(regex_t));
4510 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4511 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4512 return -1;
4513 }
4514
4515 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4516 }
4517 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4518 regex_t *preg;
4519
4520 if (*(args[1]) == 0) {
4521 Alert("parsing [%s:%d] : <reqallow> expects <regex> as an argument.\n", file, linenum);
4522 return -1;
4523 }
4524
4525 preg = calloc(1, sizeof(regex_t));
4526 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4527 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4528 return -1;
4529 }
4530
4531 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4532 }
4533 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4534 regex_t *preg;
4535
4536 if (*(args[1]) == 0 || *(args[2]) == 0) {
4537 Alert("parsing [%s:%d] : <reqirep> expects <search> and <replace> as arguments.\n",
4538 file, linenum);
4539 return -1;
4540 }
4541
4542 preg = calloc(1, sizeof(regex_t));
4543 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4544 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4545 return -1;
4546 }
4547
4548 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4549 }
4550 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4551 regex_t *preg;
4552
4553 if (*(args[1]) == 0) {
4554 Alert("parsing [%s:%d] : <reqidel> expects <regex> as an argument.\n", file, linenum);
4555 return -1;
4556 }
4557
4558 preg = calloc(1, sizeof(regex_t));
4559 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4560 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4561 return -1;
4562 }
4563
4564 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4565 }
4566 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4567 regex_t *preg;
4568
4569 if (*(args[1]) == 0) {
4570 Alert("parsing [%s:%d] : <reqideny> expects <regex> as an argument.\n", file, linenum);
4571 return -1;
4572 }
4573
4574 preg = calloc(1, sizeof(regex_t));
4575 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4576 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4577 return -1;
4578 }
4579
4580 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4581 }
4582 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4583 regex_t *preg;
4584
4585 if (*(args[1]) == 0) {
4586 Alert("parsing [%s:%d] : <reqiallow> expects <regex> as an argument.\n", file, linenum);
4587 return -1;
4588 }
4589
4590 preg = calloc(1, sizeof(regex_t));
4591 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4592 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4593 return -1;
4594 }
4595
4596 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4597 }
4598 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4599 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
4600 Alert("parsing [%s:%d] : too many `reqadd'. Continuing.\n", file, linenum);
4601 return 0;
4602 }
4603
4604 if (*(args[1]) == 0) {
4605 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n", file, linenum);
4606 return -1;
4607 }
4608
4609 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004610 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004611 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004612 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004613
4614 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004615 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004616 file, linenum);
4617 return -1;
4618 }
4619
4620 preg = calloc(1, sizeof(regex_t));
4621 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4622 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4623 return -1;
4624 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004625
4626 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4627 }
4628 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4629 regex_t *preg;
4630
4631 if (*(args[1]) == 0) {
4632 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n", file, linenum);
4633 return -1;
4634 }
willy tarreaue39cd132005-12-17 13:00:18 +01004635
willy tarreau9fe663a2005-12-17 13:02:59 +01004636 preg = calloc(1, sizeof(regex_t));
4637 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4638 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4639 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004640 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004641
4642 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4643 }
4644 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004645 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004646
willy tarreau9fe663a2005-12-17 13:02:59 +01004647 if (*(args[1]) == 0 || *(args[2]) == 0) {
4648 Alert("parsing [%s:%d] : <rspirep> expects <search> and <replace> as arguments.\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01004649 file, linenum);
willy tarreaue39cd132005-12-17 13:00:18 +01004650 return -1;
4651 }
4652
4653 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004654 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreaue39cd132005-12-17 13:00:18 +01004655 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4656 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004657 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004658
4659 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4660 }
4661 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4662 regex_t *preg;
4663
4664 if (*(args[1]) == 0) {
4665 Alert("parsing [%s:%d] : <rspidel> expects <search> as an argument.\n", file, linenum);
4666 return -1;
4667 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004668
willy tarreau9fe663a2005-12-17 13:02:59 +01004669 preg = calloc(1, sizeof(regex_t));
4670 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4671 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4672 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004673 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004674
4675 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4676 }
4677 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4678 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
4679 Alert("parsing [%s:%d] : too many `rspadd'. Continuing.\n", file, linenum);
4680 return 0;
4681 }
4682
4683 if (*(args[1]) == 0) {
4684 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n", file, linenum);
4685 return -1;
4686 }
4687
4688 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4689 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004690 else if (!strcmp(args[0], "errorloc")) { /* error location */
4691 int errnum;
4692 char *err;
4693
4694 if (*(args[2]) == 0) {
4695 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
4696 return -1;
4697 }
4698
4699 errnum = atol(args[1]);
4700 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
4701 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
4702
4703 if (errnum == 400) {
4704 if (curproxy->errmsg.msg400) {
4705 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4706 free(curproxy->errmsg.msg400);
4707 }
4708 curproxy->errmsg.msg400 = err;
4709 curproxy->errmsg.len400 = strlen(err);
4710 }
4711 else if (errnum == 403) {
4712 if (curproxy->errmsg.msg403) {
4713 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4714 free(curproxy->errmsg.msg403);
4715 }
4716 curproxy->errmsg.msg403 = err;
4717 curproxy->errmsg.len403 = strlen(err);
4718 }
4719 else if (errnum == 408) {
4720 if (curproxy->errmsg.msg408) {
4721 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4722 free(curproxy->errmsg.msg408);
4723 }
4724 curproxy->errmsg.msg408 = err;
4725 curproxy->errmsg.len408 = strlen(err);
4726 }
4727 else if (errnum == 500) {
4728 if (curproxy->errmsg.msg500) {
4729 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4730 free(curproxy->errmsg.msg500);
4731 }
4732 curproxy->errmsg.msg500 = err;
4733 curproxy->errmsg.len500 = strlen(err);
4734 }
4735 else if (errnum == 502) {
4736 if (curproxy->errmsg.msg502) {
4737 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4738 free(curproxy->errmsg.msg502);
4739 }
4740 curproxy->errmsg.msg502 = err;
4741 curproxy->errmsg.len502 = strlen(err);
4742 }
4743 else if (errnum == 503) {
4744 if (curproxy->errmsg.msg503) {
4745 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4746 free(curproxy->errmsg.msg503);
4747 }
4748 curproxy->errmsg.msg503 = err;
4749 curproxy->errmsg.len503 = strlen(err);
4750 }
4751 else if (errnum == 504) {
4752 if (curproxy->errmsg.msg504) {
4753 Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
4754 free(curproxy->errmsg.msg504);
4755 }
4756 curproxy->errmsg.msg504 = err;
4757 curproxy->errmsg.len504 = strlen(err);
4758 }
4759 else {
4760 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
4761 free(err);
4762 }
4763 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004764 else {
4765 Alert("parsing [%s:%d] : unknown keyword <%s> in <listen> section\n", file, linenum, args[0]);
4766 return -1;
4767 }
4768 return 0;
4769}
willy tarreaue39cd132005-12-17 13:00:18 +01004770
willy tarreau5cbea6f2005-12-17 12:48:26 +01004771
willy tarreau9fe663a2005-12-17 13:02:59 +01004772/*
4773 * This function reads and parses the configuration file given in the argument.
4774 * returns 0 if OK, -1 if error.
4775 */
4776int readcfgfile(char *file) {
4777 char thisline[256];
4778 char *line;
4779 FILE *f;
4780 int linenum = 0;
4781 char *end;
4782 char *args[MAX_LINE_ARGS];
4783 int arg;
4784 int cfgerr = 0;
4785 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01004786
willy tarreau9fe663a2005-12-17 13:02:59 +01004787 struct proxy *curproxy = NULL;
4788 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01004789
willy tarreau9fe663a2005-12-17 13:02:59 +01004790 if ((f=fopen(file,"r")) == NULL)
4791 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004792
willy tarreau9fe663a2005-12-17 13:02:59 +01004793 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
4794 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004795
willy tarreau9fe663a2005-12-17 13:02:59 +01004796 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004797
willy tarreau9fe663a2005-12-17 13:02:59 +01004798 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01004799 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01004800 line++;
4801
4802 arg = 0;
4803 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01004804
willy tarreau9fe663a2005-12-17 13:02:59 +01004805 while (*line && arg < MAX_LINE_ARGS) {
4806 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
4807 * C equivalent value. Other combinations left unchanged (eg: \1).
4808 */
4809 if (*line == '\\') {
4810 int skip = 0;
4811 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
4812 *line = line[1];
4813 skip = 1;
4814 }
4815 else if (line[1] == 'r') {
4816 *line = '\r';
4817 skip = 1;
4818 }
4819 else if (line[1] == 'n') {
4820 *line = '\n';
4821 skip = 1;
4822 }
4823 else if (line[1] == 't') {
4824 *line = '\t';
4825 skip = 1;
4826 }
4827 else if (line[1] == 'x' && (line + 3 < end )) {
4828 unsigned char hex1, hex2;
4829 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
4830 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4831 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4832 *line = (hex1<<4) + hex2;
4833 skip = 3;
4834 }
4835 if (skip) {
4836 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
4837 end -= skip;
4838 }
4839 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004840 }
willy tarreaua1598082005-12-17 13:08:06 +01004841 else if (*line == '#' || *line == '\n' || *line == '\r') {
4842 /* end of string, end of loop */
4843 *line = 0;
4844 break;
4845 }
willy tarreauc29948c2005-12-17 13:10:27 +01004846 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004847 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01004848 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01004849 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01004850 line++;
4851 args[++arg] = line;
4852 }
4853 else {
4854 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004855 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004856 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004857
willy tarreau9fe663a2005-12-17 13:02:59 +01004858 /* empty line */
4859 if (!**args)
4860 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01004861
willy tarreau9fe663a2005-12-17 13:02:59 +01004862 /* zero out remaining args */
4863 while (++arg < MAX_LINE_ARGS) {
4864 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004865 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004866
willy tarreau9fe663a2005-12-17 13:02:59 +01004867 if (!strcmp(args[0], "listen")) /* new proxy */
4868 confsect = CFG_LISTEN;
4869 else if (!strcmp(args[0], "global")) /* global config */
4870 confsect = CFG_GLOBAL;
4871 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004872
willy tarreau9fe663a2005-12-17 13:02:59 +01004873 switch (confsect) {
4874 case CFG_LISTEN:
4875 if (cfg_parse_listen(file, linenum, args) < 0)
4876 return -1;
4877 break;
4878 case CFG_GLOBAL:
4879 if (cfg_parse_global(file, linenum, args) < 0)
4880 return -1;
4881 break;
4882 default:
4883 Alert("parsing [%s:%d] : unknown keyword <%s> out of section.\n", file, linenum, args[0]);
4884 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004885 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004886
4887
willy tarreau0f7af912005-12-17 12:21:26 +01004888 }
4889 fclose(f);
4890
4891 /*
4892 * Now, check for the integrity of all that we have collected.
4893 */
4894
4895 if ((curproxy = proxy) == NULL) {
4896 Alert("parsing %s : no <listen> line. Nothing to do !\n",
4897 file);
4898 return -1;
4899 }
4900
4901 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01004902 if (curproxy->state == PR_STDISABLED) {
4903 curproxy = curproxy->next;
4904 continue;
4905 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004906 if ((curproxy->mode != PR_MODE_HEALTH) &&
4907 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01004908 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004909 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
4910 file, curproxy->id);
4911 cfgerr++;
4912 }
4913 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
4914 if (curproxy->options & PR_O_TRANSP) {
4915 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
4916 file, curproxy->id);
4917 cfgerr++;
4918 }
4919 else if (curproxy->srv == NULL) {
4920 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
4921 file, curproxy->id);
4922 cfgerr++;
4923 }
willy tarreaua1598082005-12-17 13:08:06 +01004924 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004925 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
4926 file, curproxy->id);
4927 }
4928 }
4929 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01004930 if (curproxy->cookie_name != NULL) {
4931 Warning("parsing %s : cookie will be ignored for listener %s.\n",
4932 file, curproxy->id);
4933 }
4934 if ((newsrv = curproxy->srv) != NULL) {
4935 Warning("parsing %s : servers will be ignored for listener %s.\n",
4936 file, curproxy->id);
4937 }
willy tarreaue39cd132005-12-17 13:00:18 +01004938 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004939 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
4940 file, curproxy->id);
4941 }
willy tarreaue39cd132005-12-17 13:00:18 +01004942 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004943 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
4944 file, curproxy->id);
4945 }
4946 }
4947 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
4948 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
4949 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
4950 file, curproxy->id);
4951 cfgerr++;
4952 }
4953 else {
4954 while (newsrv != NULL) {
4955 /* nothing to check for now */
4956 newsrv = newsrv->next;
4957 }
4958 }
4959 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004960 if (curproxy->errmsg.msg400 == NULL) {
4961 curproxy->errmsg.msg400 = (char *)HTTP_400;
4962 curproxy->errmsg.len400 = strlen(HTTP_400);
4963 }
4964 if (curproxy->errmsg.msg403 == NULL) {
4965 curproxy->errmsg.msg403 = (char *)HTTP_403;
4966 curproxy->errmsg.len403 = strlen(HTTP_403);
4967 }
4968 if (curproxy->errmsg.msg408 == NULL) {
4969 curproxy->errmsg.msg408 = (char *)HTTP_408;
4970 curproxy->errmsg.len408 = strlen(HTTP_408);
4971 }
4972 if (curproxy->errmsg.msg500 == NULL) {
4973 curproxy->errmsg.msg500 = (char *)HTTP_500;
4974 curproxy->errmsg.len500 = strlen(HTTP_500);
4975 }
4976 if (curproxy->errmsg.msg502 == NULL) {
4977 curproxy->errmsg.msg502 = (char *)HTTP_502;
4978 curproxy->errmsg.len502 = strlen(HTTP_502);
4979 }
4980 if (curproxy->errmsg.msg503 == NULL) {
4981 curproxy->errmsg.msg503 = (char *)HTTP_503;
4982 curproxy->errmsg.len503 = strlen(HTTP_503);
4983 }
4984 if (curproxy->errmsg.msg504 == NULL) {
4985 curproxy->errmsg.msg504 = (char *)HTTP_504;
4986 curproxy->errmsg.len504 = strlen(HTTP_504);
4987 }
willy tarreau0f7af912005-12-17 12:21:26 +01004988 curproxy = curproxy->next;
4989 }
4990 if (cfgerr > 0) {
4991 Alert("Errors found in configuration file, aborting.\n");
4992 return -1;
4993 }
4994 else
4995 return 0;
4996}
4997
4998
4999/*
5000 * This function initializes all the necessary variables. It only returns
5001 * if everything is OK. If something fails, it exits.
5002 */
5003void init(int argc, char **argv) {
5004 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01005005 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01005006 char *old_argv = *argv;
5007 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01005008 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01005009
5010 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005011 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005012 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
5013 sizeof(int)*8);
5014 exit(1);
5015 }
5016
5017 pid = getpid();
5018 progname = *argv;
5019 while ((tmp = strchr(progname, '/')) != NULL)
5020 progname = tmp + 1;
5021
5022 argc--; argv++;
5023 while (argc > 0) {
5024 char *flag;
5025
5026 if (**argv == '-') {
5027 flag = *argv+1;
5028
5029 /* 1 arg */
5030 if (*flag == 'v') {
5031 display_version();
5032 exit(0);
5033 }
5034 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01005035 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01005036 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01005037 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005038 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01005039 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01005040#if STATTIME > 0
5041 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01005042 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01005043 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01005044 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01005045#endif
5046 else { /* >=2 args */
5047 argv++; argc--;
5048 if (argc == 0)
5049 usage(old_argv);
5050
5051 switch (*flag) {
5052 case 'n' : cfg_maxconn = atol(*argv); break;
5053 case 'N' : cfg_maxpconn = atol(*argv); break;
5054 case 'f' : cfg_cfgfile = *argv; break;
5055 default: usage(old_argv);
5056 }
5057 }
5058 }
5059 else
5060 usage(old_argv);
5061 argv++; argc--;
5062 }
5063
willy tarreau0f7af912005-12-17 12:21:26 +01005064 if (!cfg_cfgfile)
5065 usage(old_argv);
5066
5067 gethostname(hostname, MAX_HOSTNAME_LEN);
5068
5069 if (readcfgfile(cfg_cfgfile) < 0) {
5070 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
5071 exit(1);
5072 }
5073
willy tarreau9fe663a2005-12-17 13:02:59 +01005074 if (cfg_maxconn > 0)
5075 global.maxconn = cfg_maxconn;
5076
5077 if (global.maxconn == 0)
5078 global.maxconn = DEFAULT_MAXCONN;
5079
5080 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
5081
5082 if (arg_mode & MODE_DEBUG) {
5083 /* command line debug mode inhibits configuration mode */
5084 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5085 }
willy tarreau750a4722005-12-17 13:21:24 +01005086 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01005087
5088 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
5089 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
5090 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
5091 }
5092
5093 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
5094 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
5095 global.nbproc = 1;
5096 }
5097
5098 if (global.nbproc < 1)
5099 global.nbproc = 1;
5100
willy tarreau0f7af912005-12-17 12:21:26 +01005101 ReadEvent = (fd_set *)calloc(1,
5102 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005103 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005104 WriteEvent = (fd_set *)calloc(1,
5105 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005106 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005107 StaticReadEvent = (fd_set *)calloc(1,
5108 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005109 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005110 StaticWriteEvent = (fd_set *)calloc(1,
5111 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01005112 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01005113
5114 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01005115 sizeof(struct fdtab) * (global.maxsock));
5116 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01005117 fdtab[i].state = FD_STCLOSE;
5118 }
5119}
5120
5121/*
5122 * this function starts all the proxies. It returns 0 if OK, -1 if not.
5123 */
5124int start_proxies() {
5125 struct proxy *curproxy;
5126 int one = 1;
5127 int fd;
5128
5129 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
5130
5131 if (curproxy->state == PR_STDISABLED)
5132 continue;
5133
5134 if ((fd = curproxy->listen_fd =
5135 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
5136 Alert("cannot create listening socket for proxy %s. Aborting.\n",
5137 curproxy->id);
5138 return -1;
5139 }
5140
willy tarreau9fe663a2005-12-17 13:02:59 +01005141 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005142 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
5143 curproxy->id);
5144 close(fd);
5145 return -1;
5146 }
5147
willy tarreau0f7af912005-12-17 12:21:26 +01005148 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
5149 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
5150 (char *) &one, sizeof(one)) == -1)) {
5151 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
5152 curproxy->id);
5153 close(fd);
5154 return -1;
5155 }
5156
5157 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
5158 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
5159 curproxy->id);
5160 }
5161
5162 if (bind(fd,
5163 (struct sockaddr *)&curproxy->listen_addr,
5164 sizeof(curproxy->listen_addr)) == -1) {
5165 Alert("cannot bind socket for proxy %s. Aborting.\n",
5166 curproxy->id);
5167 close(fd);
5168 return -1;
5169 }
5170
5171 if (listen(fd, curproxy->maxconn) == -1) {
5172 Alert("cannot listen to socket for proxy %s. Aborting.\n",
5173 curproxy->id);
5174 close(fd);
5175 return -1;
5176 }
5177
5178 /* the function for the accept() event */
5179 fdtab[fd].read = &event_accept;
5180 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005181 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01005182 curproxy->state = PR_STRUN;
5183 fdtab[fd].state = FD_STLISTEN;
5184 FD_SET(fd, StaticReadEvent);
5185 fd_insert(fd);
5186 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01005187
willy tarreaua1598082005-12-17 13:08:06 +01005188 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005189
willy tarreau0f7af912005-12-17 12:21:26 +01005190 }
5191 return 0;
5192}
5193
5194
5195int main(int argc, char **argv) {
5196 init(argc, argv);
5197
willy tarreau9fe663a2005-12-17 13:02:59 +01005198 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01005199 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01005201 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01005202 }
5203
5204 signal(SIGQUIT, dump);
5205 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01005206 signal(SIGHUP, sig_dump_state);
willy tarreau0f7af912005-12-17 12:21:26 +01005207
5208 /* on very high loads, a sigpipe sometimes happen just between the
5209 * getsockopt() which tells "it's OK to write", and the following write :-(
5210 */
willy tarreau3242e862005-12-17 12:27:53 +01005211#ifndef MSG_NOSIGNAL
5212 signal(SIGPIPE, SIG_IGN);
5213#endif
willy tarreau0f7af912005-12-17 12:21:26 +01005214
5215 if (start_proxies() < 0)
5216 exit(1);
5217
willy tarreau9fe663a2005-12-17 13:02:59 +01005218 /* open log files */
5219
5220 /* chroot if needed */
5221 if (global.chroot != NULL) {
5222 if (chroot(global.chroot) == -1) {
5223 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
5224 exit(1);
5225 }
5226 chdir("/");
5227 }
5228
5229 /* setgid / setuid */
5230 if (global.gid && setregid(global.gid, global.gid) == -1) {
5231 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
5232 exit(1);
5233 }
5234
5235 if (global.uid && setreuid(global.uid, global.uid) == -1) {
5236 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
5237 exit(1);
5238 }
5239
5240 if (global.mode & MODE_DAEMON) {
5241 int ret = 0;
5242 int proc;
5243
5244 /* the father launches the required number of processes */
5245 for (proc = 0; proc < global.nbproc; proc++) {
5246 ret = fork();
5247 if (ret < 0) {
5248 Alert("[%s.main()] Cannot fork.\n", argv[0]);
5249 exit(1); /* there has been an error */
5250 }
5251 else if (ret == 0) /* child breaks here */
5252 break;
5253 }
5254 if (proc == global.nbproc)
5255 exit(0); /* parent must leave */
5256
willy tarreau750a4722005-12-17 13:21:24 +01005257 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
5258 * that we can detach from the TTY. We MUST NOT do it in other cases since
5259 * it would have already be done, and 0-2 would have been affected to listening
5260 * sockets
5261 */
5262 if (!(global.mode & MODE_QUIET)) {
5263 /* detach from the tty */
5264 fclose(stdin); fclose(stdout); fclose(stderr);
5265 close(0); close(1); close(2); /* close all fd's */
5266 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
5267 }
willy tarreaua1598082005-12-17 13:08:06 +01005268 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01005269 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01005270 }
5271
willy tarreau0f7af912005-12-17 12:21:26 +01005272 select_loop();
5273
5274 exit(0);
5275}
willy tarreaua1598082005-12-17 13:08:06 +01005276