blob: d51ea2d24f3763808c1516b87f37dfa638bc2e2d [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
14 * the snprintf() bug since requests we simple (GET / HTTP/1.0).
willy tarreauef900ab2005-12-17 12:52:52 +010015 * - cookie in insert+indirect mode sometimes segfaults !
16 * - a proxy with an invalid config will prevent the startup even if disabled.
willy tarreaucd878942005-12-17 13:27:43 +010017 * - it may be nice to return HTTP 502 when a server returns no header nor data.
willy tarreauef900ab2005-12-17 12:52:52 +010018 *
willy tarreau0f7af912005-12-17 12:21:26 +010019 * ChangeLog :
20 *
willy tarreaue867b482005-12-17 13:28:43 +010021 * 2002/08/07 : 1.1.15
22 * - replaced setpgid()/setpgrp() with setsid() for better portability, because
23 * setpgrp() doesn't have the same meaning under Solaris, Linux, and OpenBSD.
willy tarreaucd878942005-12-17 13:27:43 +010024 * 2002/07/20 : 1.1.14
25 * - added "postonly" cookie mode
willy tarreau6e682ce2005-12-17 13:26:49 +010026 * 2002/07/15 : 1.1.13
27 * - tv_diff used inverted parameters which led to negative times !
willy tarreaucd878942005-12-17 13:27:43 +010028 * 2002/07/13 : 1.1.12
willy tarreau750a4722005-12-17 13:21:24 +010029 * - fixed stats monitoring, and optimized some tv_* for most common cases.
30 * - replaced temporary 'newhdr' with 'trash' to reduce stack size
31 * - made HTTP errors more HTML-fiendly.
32 * - renamed strlcpy() to strlcpy2() because of a slightly difference between
33 * their behaviour (return value), to avoid confusion.
34 * - restricted HTTP messages to HTTP proxies only
35 * - added a 502 message when the connection has been refused by the server,
36 * to prevent clients from believing this is a zero-byte HTTP 0.9 reply.
37 * - changed 'Cache-control:' from 'no-cache="set-cookie"' to 'private' when
38 * inserting a cookie, because some caches (apache) don't understand it.
39 * - fixed processing of server headers when client is in SHUTR state
40 * 2002/07/04 :
41 * - automatically close fd's 0,1 and 2 when going daemon ; setpgrp() after
42 * setpgid()
willy tarreau240afa62005-12-17 13:14:35 +010043 * 2002/06/04 : 1.1.11
44 * - fixed multi-cookie handling in client request to allow clean deletion
45 * in insert+indirect mode. Now, only the server cookie is deleted and not
46 * all the header. Should now be compliant to RFC2109.
47 * - added a "nocache" option to "cookie" to specify that we explicitly want
48 * to add a "cache-control" header when we add a cookie.
49 * It is also possible to add an "Expires: <old-date>" to keep compatibility
50 * with old/broken caches.
willy tarreau96d40372005-12-17 13:11:56 +010051 * 2002/05/10 : 1.1.10
52 * - if a cookie is used in insert+indirect mode, it's desirable that the
53 * the servers don't see it. It was not possible to remove it correctly
54 * with regexps, so now it's removed automatically.
willy tarreauc29948c2005-12-17 13:10:27 +010055 * 2002/04/19 : 1.1.9
56 * - don't use snprintf()'s return value as an end of message since it may
57 * be larger. This caused bus errors and segfaults in internal libc's
58 * getenv() during localtime() in send_log().
59 * - removed dead insecure send_syslog() function and all references to it.
60 * - fixed warnings on Solaris due to buggy implementation of isXXXX().
willy tarreaua1598082005-12-17 13:08:06 +010061 * 2002/04/18 : 1.1.8
62 * - option "dontlognull"
63 * - fixed "double space" bug in config parser
64 * - fixed an uninitialized server field in case of dispatch
65 * with no existing server which could cause a segfault during
66 * logging.
67 * - the pid logged was always the father's, which was wrong for daemons.
68 * - fixed wrong level "LOG_INFO" for message "proxy started".
69 * 2002/04/13 :
70 * - http logging is now complete :
71 * - ip:port, date, proxy, server
72 * - req_time, conn_time, hdr_time, tot_time
73 * - status, size, request
74 * - source address
willy tarreau9fe663a2005-12-17 13:02:59 +010075 * 2002/04/12 : 1.1.7
76 * - added option forwardfor
77 * - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel
78 * - added "log global" in "listen" section.
79 * 2002/04/09 :
80 * - added a new "global" section :
81 * - logs
82 * - debug, quiet, daemon modes
83 * - uid, gid, chroot, nbproc, maxconn
willy tarreaue39cd132005-12-17 13:00:18 +010084 * 2002/04/08 : 1.1.6
85 * - regex are now chained and not limited anymore.
86 * - unavailable server now returns HTTP/502.
87 * - increased per-line args limit to 40
88 * - added reqallow/reqdeny to block some request on matches
89 * - added HTTP 400/403 responses
90 * 2002/04/03 : 1.1.5
willy tarreau535ae7a2005-12-17 12:58:00 +010091 * - connection logging displayed incorrect source address.
92 * - added proxy start/stop and server up/down log events.
93 * - replaced log message short buffers with larger trash.
94 * - enlarged buffer to 8 kB and replace buffer to 4 kB.
willy tarreaue39cd132005-12-17 13:00:18 +010095 * 2002/03/25 : 1.1.4
willy tarreaue47c8d72005-12-17 12:55:52 +010096 * - made rise/fall/interval time configurable
willy tarreaue39cd132005-12-17 13:00:18 +010097 * 2002/03/22 : 1.1.3
willy tarreaub719f002005-12-17 12:55:07 +010098 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
99 * which could lead to loops.
willy tarreaue39cd132005-12-17 13:00:18 +0100100 * 2002/03/21 : 1.1.2
willy tarreauef900ab2005-12-17 12:52:52 +0100101 * - fixed a bug in buffer management where we could have a loop
102 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
103 * => implemented an adjustable buffer limit.
104 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
105 * and running tasks are skipped.
106 * - added some debug lines for accept events.
107 * - send warnings for servers up/down.
willy tarreaue39cd132005-12-17 13:00:18 +0100108 * 2002/03/12 : 1.1.1
willy tarreauefae1842005-12-17 12:51:03 +0100109 * - fixed a bug in total failure handling
110 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreaue39cd132005-12-17 13:00:18 +0100111 * 2002/03/10 : 1.1.0
willy tarreau5cbea6f2005-12-17 12:48:26 +0100112 * - fixed a few timeout bugs
113 * - rearranged the task scheduler subsystem to improve performance,
114 * add new tasks, and make it easier to later port to librt ;
115 * - allow multiple accept() for one select() wake up ;
116 * - implemented internal load balancing with basic health-check ;
117 * - cookie insertion and header add/replace/delete, with better strings
118 * support.
119 * 2002/03/08
120 * - reworked buffer handling to fix a few rewrite bugs, and
121 * improve overall performance.
122 * - implement the "purge" option to delete server cookies in direct mode.
123 * 2002/03/07
124 * - fixed some error cases where the maxfd was not decreased.
125 * 2002/02/26
126 * - now supports transparent proxying, at least on linux 2.4.
127 * 2002/02/12
128 * - soft stop works again (fixed select timeout computation).
129 * - it seems that TCP proxies sometimes cannot timeout.
130 * - added a "quiet" mode.
131 * - enforce file descriptor limitation on socket() and accept().
132 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +0100133 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +0100134 * 2001/12/16 : release of version 1.0.0.
135 * 2001/12/16 : added syslog capability for each accepted connection.
136 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
137 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
138 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
139 * with or without cookies (use keyword http for this).
140 * 2001/09/01 : added client/server header replacing with regexps.
141 * eg:
142 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
143 * srvexp ^Server:\ .* Server:\ Apache
144 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
145 * 2000/11/28 : major rewrite
146 * 2000/11/26 : first write
147 *
willy tarreau5cbea6f2005-12-17 12:48:26 +0100148 * TODO:
149 * - handle properly intermediate incomplete server headers. Done ?
150 * - log proxies start/stop
151 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +0100152 *
153 */
154
155#include <stdio.h>
156#include <stdlib.h>
157#include <unistd.h>
158#include <string.h>
159#include <ctype.h>
160#include <sys/time.h>
161#include <sys/types.h>
162#include <sys/socket.h>
163#include <netinet/tcp.h>
164#include <netinet/in.h>
165#include <arpa/inet.h>
166#include <netdb.h>
167#include <fcntl.h>
168#include <errno.h>
169#include <signal.h>
170#include <stdarg.h>
171#include <sys/resource.h>
172#include <time.h>
173#include <regex.h>
174#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +0100175#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100176#include <linux/netfilter_ipv4.h>
177#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100178
willy tarreaue867b482005-12-17 13:28:43 +0100179#define HAPROXY_VERSION "1.1.15"
180#define HAPROXY_DATE "2002/08/07"
willy tarreau0f7af912005-12-17 12:21:26 +0100181
182/* this is for libc5 for example */
183#ifndef TCP_NODELAY
184#define TCP_NODELAY 1
185#endif
186
187#ifndef SHUT_RD
188#define SHUT_RD 0
189#endif
190
191#ifndef SHUT_WR
192#define SHUT_WR 1
193#endif
194
willy tarreau535ae7a2005-12-17 12:58:00 +0100195#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +0100196
197// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +0100198#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +0100199#define REQURI_LEN 1024
willy tarreau0f7af912005-12-17 12:21:26 +0100200
willy tarreau5cbea6f2005-12-17 12:48:26 +0100201// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100202#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100203
willy tarreaue39cd132005-12-17 13:00:18 +0100204// max # of added headers per request
205#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100206
207// max # of matches per regexp
208#define MAX_MATCH 10
209
willy tarreau5cbea6f2005-12-17 12:48:26 +0100210/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100211#define COOKIENAME_LEN 16
212#define SERVERID_LEN 16
213#define CONN_RETRIES 3
214
willy tarreau5cbea6f2005-12-17 12:48:26 +0100215#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100216#define DEF_CHKINTR 2000
217#define DEF_FALLTIME 3
218#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100219
willy tarreau9fe663a2005-12-17 13:02:59 +0100220/* default connections limit */
221#define DEFAULT_MAXCONN 2000
222
willy tarreau0f7af912005-12-17 12:21:26 +0100223/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
224#define INTBITS 5
225
226/* show stats this every millisecond, 0 to disable */
227#ifndef STATTIME
228#define STATTIME 2000
229#endif
230
willy tarreau5cbea6f2005-12-17 12:48:26 +0100231/* this reduces the number of calls to select() by choosing appropriate
232 * sheduler precision in milliseconds. It should be near the minimum
233 * time that is needed by select() to collect all events. All timeouts
234 * are rounded up by adding this value prior to pass it to select().
235 */
236#define SCHEDULER_RESOLUTION 9
237
willy tarreau0f7af912005-12-17 12:21:26 +0100238#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
239#define SETNOW(a) (*a=now)
240
willy tarreau9da061b2005-12-17 12:29:56 +0100241/****** string-specific macros and functions ******/
242/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
243#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
244
245/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
246#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
247
willy tarreau9da061b2005-12-17 12:29:56 +0100248/*
249 * copies at most <size-1> chars from <src> to <dst>. Last char is always
250 * set to 0, unless <size> is 0. The number of chars copied is returned
251 * (excluding the terminating zero).
252 * This code has been optimized for size and speed : on x86, it's 45 bytes
253 * long, uses only registers, and consumes only 4 cycles per char.
254 */
willy tarreau750a4722005-12-17 13:21:24 +0100255int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100256 char *orig = dst;
257 if (size) {
258 while (--size && (*dst = *src)) {
259 src++; dst++;
260 }
261 *dst = 0;
262 }
263 return dst - orig;
264}
willy tarreau9da061b2005-12-17 12:29:56 +0100265
willy tarreau0f7af912005-12-17 12:21:26 +0100266#define MEM_OPTIM
267#ifdef MEM_OPTIM
268/*
269 * Returns a pointer to type <type> taken from the
270 * pool <pool_type> or dynamically allocated. In the
271 * first case, <pool_type> is updated to point to the
272 * next element in the list.
273 */
274#define pool_alloc(type) ({ \
275 void *p; \
276 if ((p = pool_##type) == NULL) \
277 p = malloc(sizeof_##type); \
278 else { \
279 pool_##type = *(void **)pool_##type; \
280 } \
281 p; \
282})
283
284/*
285 * Puts a memory area back to the corresponding pool.
286 * Items are chained directly through a pointer that
287 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100288 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100289 * that each memory area is at least as big as one
290 * pointer.
291 */
292#define pool_free(type, ptr) ({ \
293 *(void **)ptr = (void *)pool_##type; \
294 pool_##type = (void *)ptr; \
295})
296
297#else
298#define pool_alloc(type) (calloc(1,sizeof_##type));
299#define pool_free(type, ptr) (free(ptr));
300#endif /* MEM_OPTIM */
301
willy tarreau5cbea6f2005-12-17 12:48:26 +0100302#define sizeof_task sizeof(struct task)
303#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100304#define sizeof_buffer sizeof(struct buffer)
305#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100306#define sizeof_requri REQURI_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100307
willy tarreau5cbea6f2005-12-17 12:48:26 +0100308/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100309#define FD_STCLOSE 0
310#define FD_STLISTEN 1
311#define FD_STCONN 2
312#define FD_STREADY 3
313#define FD_STERROR 4
314
willy tarreau5cbea6f2005-12-17 12:48:26 +0100315/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100316#define TASK_IDLE 0
317#define TASK_RUNNING 1
318
willy tarreau5cbea6f2005-12-17 12:48:26 +0100319/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100320#define PR_STNEW 0
321#define PR_STIDLE 1
322#define PR_STRUN 2
323#define PR_STDISABLED 3
324
willy tarreau5cbea6f2005-12-17 12:48:26 +0100325/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100326#define PR_MODE_TCP 0
327#define PR_MODE_HTTP 1
328#define PR_MODE_HEALTH 2
329
willy tarreau5cbea6f2005-12-17 12:48:26 +0100330/* bits for proxy->options */
331#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
332#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
333#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
334#define PR_O_COOK_IND 8 /* keep only indirect cookies */
335#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
336#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
337#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
338#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100339#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
340#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100341#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
342#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100343#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100344#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreau9fe663a2005-12-17 13:02:59 +0100345
willy tarreau5cbea6f2005-12-17 12:48:26 +0100346
willy tarreaue39cd132005-12-17 13:00:18 +0100347/* various session flags */
348#define SN_DIRECT 1 /* connection made on the server matching the client cookie */
349#define SN_CLDENY 2 /* a client header matches a deny regex */
350#define SN_CLALLOW 4 /* a client header matches an allow regex */
351#define SN_SVDENY 8 /* a server header matches a deny regex */
352#define SN_SVALLOW 16 /* a server header matches an allow regex */
willy tarreaucd878942005-12-17 13:27:43 +0100353#define SN_POST 32 /* the request was an HTTP POST */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354
355/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100356#define CL_STHEADERS 0
357#define CL_STDATA 1
358#define CL_STSHUTR 2
359#define CL_STSHUTW 3
360#define CL_STCLOSE 4
361
willy tarreau5cbea6f2005-12-17 12:48:26 +0100362/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100363#define SV_STIDLE 0
364#define SV_STCONN 1
365#define SV_STHEADERS 2
366#define SV_STDATA 3
367#define SV_STSHUTR 4
368#define SV_STSHUTW 5
369#define SV_STCLOSE 6
370
371/* result of an I/O event */
372#define RES_SILENT 0 /* didn't happen */
373#define RES_DATA 1 /* data were sent or received */
374#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
375#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
376
willy tarreau9fe663a2005-12-17 13:02:59 +0100377/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100378#define MODE_DEBUG 1
379#define MODE_STATS 2
380#define MODE_LOG 4
381#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100382#define MODE_QUIET 16
383
384/* server flags */
385#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100386
willy tarreaue39cd132005-12-17 13:00:18 +0100387/* what to do when a header matches a regex */
388#define ACT_ALLOW 0 /* allow the request */
389#define ACT_REPLACE 1 /* replace the matching header */
390#define ACT_REMOVE 2 /* remove the matching header */
391#define ACT_DENY 3 /* deny the request */
392
willy tarreau9fe663a2005-12-17 13:02:59 +0100393/* configuration sections */
394#define CFG_NONE 0
395#define CFG_GLOBAL 1
396#define CFG_LISTEN 2
397
willy tarreaua1598082005-12-17 13:08:06 +0100398/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100399#define LW_DATE 1 /* date */
400#define LW_CLIP 2 /* CLient IP */
401#define LW_SVIP 4 /* SerVer IP */
402#define LW_SVID 8 /* server ID */
403#define LW_REQ 16 /* http REQuest */
404#define LW_RESP 32 /* http RESPonse */
405#define LW_PXIP 64 /* proxy IP */
406#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100407#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100408
willy tarreau0f7af912005-12-17 12:21:26 +0100409/*********************************************************************/
410
411#define LIST_HEAD(a) ((void *)(&(a)))
412
413/*********************************************************************/
414
415struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100416 struct hdr_exp *next;
417 regex_t *preg; /* expression to look for */
418 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
419 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100420};
421
422struct buffer {
423 unsigned int l; /* data length */
424 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100425 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100426 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100427 char data[BUFSIZE];
428};
429
430struct server {
431 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100432 int state; /* server state (SRV_*) */
433 int cklen; /* the len of the cookie, to speed up checks */
434 char *cookie; /* the id set in the cookie */
435 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100436 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100437 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100438 int rise, fall; /* time in iterations */
439 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100440 int result; /* 0 = connect OK, -1 = connect KO */
441 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100442 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100443};
444
willy tarreau5cbea6f2005-12-17 12:48:26 +0100445/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100446struct task {
447 struct task *next, *prev; /* chaining ... */
448 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100449 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100450 int state; /* task state : IDLE or RUNNING */
451 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100452 int (*process)(struct task *t); /* the function which processes the task */
453 void *context; /* the task's context */
454};
455
456/* WARNING: if new fields are added, they must be initialized in event_accept() */
457struct session {
458 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100459 /* application specific below */
460 struct timeval crexpire; /* expiration date for a client read */
461 struct timeval cwexpire; /* expiration date for a client write */
462 struct timeval srexpire; /* expiration date for a server read */
463 struct timeval swexpire; /* expiration date for a server write */
464 struct timeval cnexpire; /* expiration date for a connect */
465 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
466 struct proxy *proxy; /* the proxy this socket belongs to */
467 int cli_fd; /* the client side fd */
468 int srv_fd; /* the server side fd */
469 int cli_state; /* state of the client side */
470 int srv_state; /* state of the server side */
471 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100472 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100473 struct buffer *req; /* request buffer */
474 struct buffer *rep; /* response buffer */
475 struct sockaddr_in cli_addr; /* the client address */
476 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100477 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100478 struct {
479 int logwait; /* log fields waiting to be collected : LW_* */
480 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
481 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
482 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
483 long t_data; /* delay before the first data byte from the server ... */
484 unsigned long t_close; /* total session duration */
485 char *uri; /* first line if log needed, NULL otherwise */
486 int status; /* HTTP status from the server, negative if from proxy */
487 long long bytes; /* number of bytes transferred from the server */
488 } logs;
willy tarreau0f7af912005-12-17 12:21:26 +0100489};
490
491struct proxy {
492 int listen_fd; /* the listen socket */
493 int state; /* proxy state */
494 struct sockaddr_in listen_addr; /* the address we listen to */
495 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100496 struct server *srv, *cursrv; /* known servers, current server */
497 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100498 char *cookie_name; /* name of the cookie to look for */
499 int clitimeout; /* client I/O timeout (in milliseconds) */
500 int srvtimeout; /* server I/O timeout (in milliseconds) */
501 int contimeout; /* connect timeout (in milliseconds) */
502 char *id; /* proxy id */
503 int nbconn; /* # of active sessions */
504 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100505 int conn_retries; /* maximum number of connect retries */
506 int options; /* PR_O_REDISP, PR_O_TRANSP */
507 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100508 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100509 struct proxy *next;
510 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
511 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau9fe663a2005-12-17 13:02:59 +0100512 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100513 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100514 int nb_reqadd, nb_rspadd;
515 struct hdr_exp *req_exp; /* regular expressions for request headers */
516 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
517 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100518 int grace; /* grace time after stop request */
519};
520
521/* info about one given fd */
522struct fdtab {
523 int (*read)(int fd); /* read function */
524 int (*write)(int fd); /* write function */
525 struct task *owner; /* the session (or proxy) associated with this fd */
526 int state; /* the state of this fd */
527};
528
529/*********************************************************************/
530
willy tarreau0f7af912005-12-17 12:21:26 +0100531int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100532char *cfg_cfgfile = NULL; /* configuration file */
533char *progname = NULL; /* program name */
534int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100535
536/* global options */
537static struct {
538 int uid;
539 int gid;
540 int nbproc;
541 int maxconn;
542 int maxsock; /* max # of sockets */
543 int mode;
544 char *chroot;
545 int logfac1, logfac2;
546 struct sockaddr_in logsrv1, logsrv2;
547} global = {
548 logfac1 : -1,
549 logfac2 : -1,
550 /* others NULL OK */
551};
552
willy tarreau0f7af912005-12-17 12:21:26 +0100553/*********************************************************************/
554
555fd_set *ReadEvent,
556 *WriteEvent,
557 *StaticReadEvent,
558 *StaticWriteEvent;
559
560void **pool_session = NULL,
561 **pool_buffer = NULL,
562 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100563 **pool_requri = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100564 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100565
566struct proxy *proxy = NULL; /* list of all existing proxies */
567struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100568struct task *rq = NULL; /* global run queue */
569struct task wait_queue = { /* global wait queue */
570 prev:LIST_HEAD(wait_queue),
571 next:LIST_HEAD(wait_queue)
572};
willy tarreau0f7af912005-12-17 12:21:26 +0100573
willy tarreau0f7af912005-12-17 12:21:26 +0100574static int totalconn = 0; /* total # of terminated sessions */
575static int actconn = 0; /* # of active sessions */
576static int maxfd = 0; /* # of the highest fd + 1 */
577static int listeners = 0; /* # of listeners */
578static int stopping = 0; /* non zero means stopping in progress */
579static struct timeval now = {0,0}; /* the current date at any moment */
580
581static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100582/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100583static char trash[BUFSIZE];
584
585/*
586 * Syslog facilities and levels
587 */
588
589#define MAX_SYSLOG_LEN 1024
590#define NB_LOG_FACILITIES 24
591const char *log_facilities[NB_LOG_FACILITIES] = {
592 "kern", "user", "mail", "daemon",
593 "auth", "syslog", "lpr", "news",
594 "uucp", "cron", "auth2", "ftp",
595 "ntp", "audit", "alert", "cron2",
596 "local0", "local1", "local2", "local3",
597 "local4", "local5", "local6", "local7"
598};
599
600
601#define NB_LOG_LEVELS 8
602const char *log_levels[NB_LOG_LEVELS] = {
603 "emerg", "alert", "crit", "err",
604 "warning", "notice", "info", "debug"
605};
606
607#define SYSLOG_PORT 514
608
609const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
610 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
611#define MAX_HOSTNAME_LEN 32
612static char hostname[MAX_HOSTNAME_LEN] = "";
613
willy tarreaua1598082005-12-17 13:08:06 +0100614const char *HTTP_400 =
615 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100616 "Cache-Control: no-cache\r\n"
617 "Connection: close\r\n"
618 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100619 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100620
willy tarreaua1598082005-12-17 13:08:06 +0100621const char *HTTP_403 =
622 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100623 "Cache-Control: no-cache\r\n"
624 "Connection: close\r\n"
625 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100626 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
627
628const char *HTTP_500 =
629 "HTTP/1.0 500 Server Error\r\n"
630 "Cache-Control: no-cache\r\n"
631 "Connection: close\r\n"
632 "\r\n"
633 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100634
635const char *HTTP_502 =
636 "HTTP/1.0 502 Proxy Error\r\n"
637 "Cache-Control: no-cache\r\n"
638 "Connection: close\r\n"
639 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100640 "<html><body><h1>502 Proxy Error</h1>\nNo server is available to handle this request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100641
willy tarreau0f7af912005-12-17 12:21:26 +0100642/*********************************************************************/
643/* statistics ******************************************************/
644/*********************************************************************/
645
willy tarreau750a4722005-12-17 13:21:24 +0100646#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100647static int stats_tsk_lsrch, stats_tsk_rsrch,
648 stats_tsk_good, stats_tsk_right, stats_tsk_left,
649 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100650#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100651
652
653/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100654/* debugging *******************************************************/
655/*********************************************************************/
656#ifdef DEBUG_FULL
657static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
658static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
659#endif
660
661/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100662/* function prototypes *********************************************/
663/*********************************************************************/
664
665int event_accept(int fd);
666int event_cli_read(int fd);
667int event_cli_write(int fd);
668int event_srv_read(int fd);
669int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100670int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100671
672/*********************************************************************/
673/* general purpose functions ***************************************/
674/*********************************************************************/
675
676void display_version() {
677 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100678 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100679}
680
681/*
682 * This function prints the command line usage and exits
683 */
684void usage(char *name) {
685 display_version();
686 fprintf(stderr,
687 "Usage : %s -f <cfgfile> [ -vd"
688#if STATTIME > 0
689 "sl"
690#endif
691 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
692 " -v displays version\n"
693 " -d enters debug mode\n"
694#if STATTIME > 0
695 " -s enables statistics output\n"
696 " -l enables long statistics format\n"
697#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100698 " -D goes daemon ; implies -q\n"
699 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100700 " -n sets the maximum total # of connections (%d)\n"
701 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100702 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100703 exit(1);
704}
705
706
707/*
708 * Displays the message on stderr with the date and pid.
709 */
710void Alert(char *fmt, ...) {
711 va_list argp;
712 struct timeval tv;
713 struct tm *tm;
714
willy tarreau9fe663a2005-12-17 13:02:59 +0100715 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100716 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100717
willy tarreau5cbea6f2005-12-17 12:48:26 +0100718 gettimeofday(&tv, NULL);
719 tm=localtime(&tv.tv_sec);
720 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100721 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100722 vfprintf(stderr, fmt, argp);
723 fflush(stderr);
724 va_end(argp);
725 }
willy tarreau0f7af912005-12-17 12:21:26 +0100726}
727
728
729/*
730 * Displays the message on stderr with the date and pid.
731 */
732void Warning(char *fmt, ...) {
733 va_list argp;
734 struct timeval tv;
735 struct tm *tm;
736
willy tarreau9fe663a2005-12-17 13:02:59 +0100737 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100738 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100739
willy tarreau5cbea6f2005-12-17 12:48:26 +0100740 gettimeofday(&tv, NULL);
741 tm=localtime(&tv.tv_sec);
742 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100743 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100744 vfprintf(stderr, fmt, argp);
745 fflush(stderr);
746 va_end(argp);
747 }
748}
749
750/*
751 * Displays the message on <out> only if quiet mode is not set.
752 */
753void qfprintf(FILE *out, char *fmt, ...) {
754 va_list argp;
755
willy tarreau9fe663a2005-12-17 13:02:59 +0100756 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100757 va_start(argp, fmt);
758 vfprintf(out, fmt, argp);
759 fflush(out);
760 va_end(argp);
761 }
willy tarreau0f7af912005-12-17 12:21:26 +0100762}
763
764
765/*
766 * converts <str> to a struct sockaddr_in* which is locally allocated.
767 * The format is "addr:port", where "addr" can be empty or "*" to indicate
768 * INADDR_ANY.
769 */
770struct sockaddr_in *str2sa(char *str) {
771 static struct sockaddr_in sa;
772 char *c;
773 int port;
774
willy tarreaua1598082005-12-17 13:08:06 +0100775 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100776 str=strdup(str);
777
778 if ((c=strrchr(str,':')) != NULL) {
779 *c++=0;
780 port=atol(c);
781 }
782 else
783 port=0;
784
785 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
786 sa.sin_addr.s_addr = INADDR_ANY;
787 }
788 else if (
789#ifndef SOLARIS
790 !inet_aton(str, &sa.sin_addr)
791#else
792 !inet_pton(AF_INET, str, &sa.sin_addr)
793#endif
794 ) {
795 struct hostent *he;
796
797 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100798 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100799 }
800 else
801 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
802 }
803 sa.sin_port=htons(port);
804 sa.sin_family=AF_INET;
805
806 free(str);
807 return &sa;
808}
809
willy tarreau9fe663a2005-12-17 13:02:59 +0100810
811/*
812 * This function sends a syslog message to both log servers of a proxy,
813 * or to global log servers if the proxy is NULL.
814 * It also tries not to waste too much time computing the message header.
815 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100816 */
817void send_log(struct proxy *p, int level, char *message, ...) {
818 static int logfd = -1; /* syslog UDP socket */
819 static long tvsec = -1; /* to force the string to be initialized */
820 struct timeval tv;
821 va_list argp;
822 static char logmsg[MAX_SYSLOG_LEN];
823 static char *dataptr = NULL;
824 int fac_level;
825 int hdr_len, data_len;
826 struct sockaddr_in *sa[2];
827 int facilities[2];
828 int nbloggers = 0;
829 char *log_ptr;
830
831 if (logfd < 0) {
832 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
833 return;
834 }
835
836 if (level < 0 || progname == NULL || message == NULL)
837 return;
838
839 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100840 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100841 /* this string is rebuild only once a second */
842 struct tm *tm = localtime(&tv.tv_sec);
843 tvsec = tv.tv_sec;
844
willy tarreauc29948c2005-12-17 13:10:27 +0100845 hdr_len = snprintf(logmsg, sizeof(logmsg),
846 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
847 monthname[tm->tm_mon],
848 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
849 progname, pid);
850 /* WARNING: depending upon implementations, snprintf may return
851 * either -1 or the number of bytes that would be needed to store
852 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100853 */
willy tarreauc29948c2005-12-17 13:10:27 +0100854 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
855 hdr_len = sizeof(logmsg);
856
857 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100858 }
859
860 va_start(argp, message);
861 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100862 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
863 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100864 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100865 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100866
867 if (p == NULL) {
868 if (global.logfac1 >= 0) {
869 sa[nbloggers] = &global.logsrv1;
870 facilities[nbloggers] = global.logfac1;
871 nbloggers++;
872 }
873 if (global.logfac2 >= 0) {
874 sa[nbloggers] = &global.logsrv2;
875 facilities[nbloggers] = global.logfac2;
876 nbloggers++;
877 }
878 } else {
879 if (p->logfac1 >= 0) {
880 sa[nbloggers] = &p->logsrv1;
881 facilities[nbloggers] = p->logfac1;
882 nbloggers++;
883 }
884 if (p->logfac2 >= 0) {
885 sa[nbloggers] = &p->logsrv2;
886 facilities[nbloggers] = p->logfac2;
887 nbloggers++;
888 }
889 }
890
891 while (nbloggers-- > 0) {
willy tarreauc29948c2005-12-17 13:10:27 +0100892 /* For each target, we may have a different facility.
893 * We can also have a different log level for each message.
894 * This induces variations in the message header length.
895 * Since we don't want to recompute it each time, nor copy it every
896 * time, we only change the facility in the pre-computed header,
897 * and we change the pointer to the header accordingly.
898 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100899 fac_level = (facilities[nbloggers] << 3) + level;
900 log_ptr = logmsg + 3; /* last digit of the log level */
901 do {
902 *log_ptr = '0' + fac_level % 10;
903 fac_level /= 10;
904 log_ptr--;
905 } while (fac_level && log_ptr > logmsg);
906 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100907
willy tarreauc29948c2005-12-17 13:10:27 +0100908 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100909
910#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100911 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100912 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
913#else
willy tarreauc29948c2005-12-17 13:10:27 +0100914 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100915 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
916#endif
917 }
willy tarreau0f7af912005-12-17 12:21:26 +0100918}
919
920
921/* sets <tv> to the current time */
922static inline struct timeval *tv_now(struct timeval *tv) {
923 if (tv)
924 gettimeofday(tv, NULL);
925 return tv;
926}
927
928/*
929 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
930 */
931static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
932 if (!tv || !from)
933 return NULL;
934 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
935 tv->tv_sec = from->tv_sec + (ms/1000);
936 while (tv->tv_usec >= 1000000) {
937 tv->tv_usec -= 1000000;
938 tv->tv_sec++;
939 }
940 return tv;
941}
942
943/*
944 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
945 */
946static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +0100947 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100948 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100949 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100950 return 1;
951 else if (tv1->tv_usec < tv2->tv_usec)
952 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100953 else if (tv1->tv_usec > tv2->tv_usec)
954 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +0100955 else
956 return 0;
957}
958
959/*
960 * returns the absolute difference, in ms, between tv1 and tv2
961 */
962unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
963 int cmp;
964 unsigned long ret;
965
966
willy tarreauef900ab2005-12-17 12:52:52 +0100967 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100968 if (!cmp)
969 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +0100970 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100971 struct timeval *tmp = tv1;
972 tv1 = tv2;
973 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100974 }
willy tarreauef900ab2005-12-17 12:52:52 +0100975 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100976 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100977 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100978 else
willy tarreauef900ab2005-12-17 12:52:52 +0100979 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100980 return (unsigned long) ret;
981}
982
983/*
willy tarreau750a4722005-12-17 13:21:24 +0100984 * returns the difference, in ms, between tv1 and tv2
985 */
986static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
987 unsigned long ret;
988
willy tarreau6e682ce2005-12-17 13:26:49 +0100989 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
990 if (tv2->tv_usec > tv1->tv_usec)
991 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100992 else
willy tarreau6e682ce2005-12-17 13:26:49 +0100993 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100994 return (unsigned long) ret;
995}
996
997/*
willy tarreau0f7af912005-12-17 12:21:26 +0100998 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
999 */
1000static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001001 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001002 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001003 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001004 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1005 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001006 else
1007 return 0;
1008 }
willy tarreau0f7af912005-12-17 12:21:26 +01001009 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001010 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001011 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001012 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1013 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1014 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001015 else
1016 return 0;
1017}
1018
1019/*
1020 * returns the remaining time between tv1=now and event=tv2
1021 * if tv2 is passed, 0 is returned.
1022 */
1023static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1024 unsigned long ret;
1025
willy tarreau0f7af912005-12-17 12:21:26 +01001026 if (tv_cmp_ms(tv1, tv2) >= 0)
1027 return 0; /* event elapsed */
1028
willy tarreauef900ab2005-12-17 12:52:52 +01001029 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001030 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001031 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001032 else
willy tarreauef900ab2005-12-17 12:52:52 +01001033 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001034 return (unsigned long) ret;
1035}
1036
1037
1038/*
1039 * zeroes a struct timeval
1040 */
1041
1042static inline struct timeval *tv_eternity(struct timeval *tv) {
1043 tv->tv_sec = tv->tv_usec = 0;
1044 return tv;
1045}
1046
1047/*
1048 * returns 1 if tv is null, else 0
1049 */
1050static inline int tv_iseternity(struct timeval *tv) {
1051 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1052 return 1;
1053 else
1054 return 0;
1055}
1056
1057/*
1058 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1059 * considering that 0 is the eternity.
1060 */
1061static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1062 if (tv_iseternity(tv1))
1063 if (tv_iseternity(tv2))
1064 return 0; /* same */
1065 else
1066 return 1; /* tv1 later than tv2 */
1067 else if (tv_iseternity(tv2))
1068 return -1; /* tv2 later than tv1 */
1069
1070 if (tv1->tv_sec > tv2->tv_sec)
1071 return 1;
1072 else if (tv1->tv_sec < tv2->tv_sec)
1073 return -1;
1074 else if (tv1->tv_usec > tv2->tv_usec)
1075 return 1;
1076 else if (tv1->tv_usec < tv2->tv_usec)
1077 return -1;
1078 else
1079 return 0;
1080}
1081
1082/*
1083 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1084 * considering that 0 is the eternity.
1085 */
1086static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1087 if (tv_iseternity(tv1))
1088 if (tv_iseternity(tv2))
1089 return 0; /* same */
1090 else
1091 return 1; /* tv1 later than tv2 */
1092 else if (tv_iseternity(tv2))
1093 return -1; /* tv2 later than tv1 */
1094
willy tarreauefae1842005-12-17 12:51:03 +01001095 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001096 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001097 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001098 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001099 return -1;
1100 else
1101 return 0;
1102 }
1103 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001104 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001105 return 1;
1106 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001107 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001108 return -1;
1109 else
1110 return 0;
1111}
1112
1113/*
1114 * returns the first event between tv1 and tv2 into tvmin.
1115 * a zero tv is ignored. tvmin is returned.
1116 */
1117static inline struct timeval *tv_min(struct timeval *tvmin,
1118 struct timeval *tv1, struct timeval *tv2) {
1119
1120 if (tv_cmp2(tv1, tv2) <= 0)
1121 *tvmin = *tv1;
1122 else
1123 *tvmin = *tv2;
1124
1125 return tvmin;
1126}
1127
1128
1129
1130/***********************************************************/
1131/* fd management ***************************************/
1132/***********************************************************/
1133
1134
1135
willy tarreau5cbea6f2005-12-17 12:48:26 +01001136/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1137 * The file descriptor is also closed.
1138 */
willy tarreau0f7af912005-12-17 12:21:26 +01001139static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001140 FD_CLR(fd, StaticReadEvent);
1141 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001142 close(fd);
1143 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001144
1145 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1146 maxfd--;
1147}
1148
1149/* recomputes the maxfd limit from the fd */
1150static inline void fd_insert(int fd) {
1151 if (fd+1 > maxfd)
1152 maxfd = fd+1;
1153}
1154
1155/*************************************************************/
1156/* task management ***************************************/
1157/*************************************************************/
1158
willy tarreau5cbea6f2005-12-17 12:48:26 +01001159/* puts the task <t> in run queue <q>, and returns <t> */
1160static inline struct task *task_wakeup(struct task **q, struct task *t) {
1161 if (t->state == TASK_RUNNING)
1162 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001163 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001164 t->rqnext = *q;
1165 t->state = TASK_RUNNING;
1166 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001167 }
1168}
1169
willy tarreau5cbea6f2005-12-17 12:48:26 +01001170/* removes the task <t> from the queue <q>
1171 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001172 * set the run queue to point to the next one, and return it
1173 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001174static inline struct task *task_sleep(struct task **q, struct task *t) {
1175 if (t->state == TASK_RUNNING) {
1176 *q = t->rqnext;
1177 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001178 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001179 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001180}
1181
1182/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001183 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001184 * from the run queue. A pointer to the task itself is returned.
1185 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001186static inline struct task *task_delete(struct task *t) {
1187 t->prev->next = t->next;
1188 t->next->prev = t->prev;
1189 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001190}
1191
1192/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001193 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001194 */
1195static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001196 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001197}
1198
willy tarreau5cbea6f2005-12-17 12:48:26 +01001199/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001200 * may be only moved or left where it was, depending on its timing requirements.
1201 * <task> is returned.
1202 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001203struct task *task_queue(struct task *task) {
1204 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001205 struct task *start_from;
1206
1207 /* first, test if the task was already in a list */
1208 if (task->prev == NULL) {
1209 // start_from = list;
1210 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001211#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001212 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001213#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001214 /* insert the unlinked <task> into the list, searching back from the last entry */
1215 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1216 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001217#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001218 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001219#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001220 }
1221
1222 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1223 // start_from = start_from->next;
1224 // stats_tsk_nsrch++;
1225 // }
1226 }
1227 else if (task->prev == list ||
1228 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1229 start_from = task->next;
1230 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001231#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001232 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001233#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001234 return task; /* it's already in the right place */
1235 }
1236
willy tarreau750a4722005-12-17 13:21:24 +01001237#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001238 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001239#endif
1240
1241 /* if the task is not at the right place, there's little chance that
1242 * it has only shifted a bit, and it will nearly always be queued
1243 * at the end of the list because of constant timeouts
1244 * (observed in real case).
1245 */
1246#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1247 start_from = list->prev; /* assume we'll queue to the end of the list */
1248 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1249 start_from = start_from->prev;
1250#if STATTIME > 0
1251 stats_tsk_lsrch++;
1252#endif
1253 }
1254#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001255 /* insert the unlinked <task> into the list, searching after position <start_from> */
1256 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1257 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001258#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001259 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001260#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001261 }
willy tarreau750a4722005-12-17 13:21:24 +01001262#endif /* WE_REALLY_... */
1263
willy tarreau0f7af912005-12-17 12:21:26 +01001264 /* we need to unlink it now */
1265 task_delete(task);
1266 }
1267 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001268#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001269 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001270#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001271#ifdef LEFT_TO_TOP /* not very good */
1272 start_from = list;
1273 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1274 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001275#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001276 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001277#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001278 }
1279#else
1280 start_from = task->prev->prev; /* valid because of the previous test above */
1281 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1282 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001283#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001284 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001285#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001286 }
1287#endif
1288 /* we need to unlink it now */
1289 task_delete(task);
1290 }
1291 task->prev = start_from;
1292 task->next = start_from->next;
1293 task->next->prev = task;
1294 start_from->next = task;
1295 return task;
1296}
1297
1298
1299/*********************************************************************/
1300/* more specific functions ***************************************/
1301/*********************************************************************/
1302
1303/* some prototypes */
1304static int maintain_proxies(void);
1305
willy tarreau5cbea6f2005-12-17 12:48:26 +01001306/* this either returns the sockname or the original destination address. Code
1307 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1308 */
1309static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001310#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001311 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1312#else
willy tarreaua1598082005-12-17 13:08:06 +01001313#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001314 return getsockname(fd, (struct sockaddr *)sa, salen);
1315#else
1316 return -1;
1317#endif
1318#endif
1319}
1320
1321/*
1322 * frees the context associated to a session. It must have been removed first.
1323 */
1324static inline void session_free(struct session *s) {
1325 if (s->req)
1326 pool_free(buffer, s->req);
1327 if (s->rep)
1328 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001329 if (s->logs.uri)
1330 pool_free(requri, s->logs.uri);
willy tarreau9fe663a2005-12-17 13:02:59 +01001331
willy tarreau5cbea6f2005-12-17 12:48:26 +01001332 pool_free(session, s);
1333}
1334
willy tarreau0f7af912005-12-17 12:21:26 +01001335
1336/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001337 * This function initiates a connection to the current server (s->srv) if (s->direct)
1338 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001339 * it's OK, -1 if it's impossible.
1340 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001341int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001342 int one = 1;
1343 int fd;
1344
1345 // fprintf(stderr,"connect_server : s=%p\n",s);
1346
willy tarreaue39cd132005-12-17 13:00:18 +01001347 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001348 s->srv_addr = s->srv->addr;
1349 }
1350 else if (s->proxy->options & PR_O_BALANCE) {
1351 if (s->proxy->options & PR_O_BALANCE_RR) {
1352 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001353 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001354 if (s->proxy->cursrv == NULL)
1355 s->proxy->cursrv = s->proxy->srv;
1356 if (s->proxy->cursrv->state & SRV_RUNNING)
1357 break;
1358 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001359 retry--;
1360 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001361
1362 if (retry == 0) /* no server left */
1363 return -1;
1364
1365 s->srv = s->proxy->cursrv;
1366 s->srv_addr = s->srv->addr;
1367 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001368 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001369 else /* unknown balancing algorithm */
1370 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001371 }
willy tarreaua1598082005-12-17 13:08:06 +01001372 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001373 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001374 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001375 }
1376 else if (s->proxy->options & PR_O_TRANSP) {
1377 /* in transparent mode, use the original dest addr if no dispatch specified */
1378 int salen = sizeof(struct sockaddr_in);
1379 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1380 qfprintf(stderr, "Cannot get original server address.\n");
1381 return -1;
1382 }
1383 }
willy tarreau0f7af912005-12-17 12:21:26 +01001384
1385 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001386 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001387 return -1;
1388 }
1389
willy tarreau9fe663a2005-12-17 13:02:59 +01001390 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001391 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1392 close(fd);
1393 return -1;
1394 }
1395
willy tarreau0f7af912005-12-17 12:21:26 +01001396 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1397 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001398 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001399 close(fd);
1400 return -1;
1401 }
1402
willy tarreaua1598082005-12-17 13:08:06 +01001403 /* allow specific binding */
1404 if (s->proxy->options & PR_O_BIND_SRC &&
1405 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1406 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1407 close(fd);
1408 return -1;
1409 }
1410
willy tarreau0f7af912005-12-17 12:21:26 +01001411 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1412 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001413 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001414 close(fd);
1415 return -1;
1416 }
1417 else if (errno != EALREADY && errno != EISCONN) {
1418 close(fd);
1419 return -1;
1420 }
1421 }
1422
willy tarreau5cbea6f2005-12-17 12:48:26 +01001423 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001424 fdtab[fd].read = &event_srv_read;
1425 fdtab[fd].write = &event_srv_write;
1426 fdtab[fd].state = FD_STCONN; /* connection in progress */
1427
1428 FD_SET(fd, StaticWriteEvent); /* for connect status */
1429
1430 fd_insert(fd);
1431
1432 if (s->proxy->contimeout)
1433 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1434 else
1435 tv_eternity(&s->cnexpire);
1436 return 0;
1437}
1438
1439/*
1440 * this function is called on a read event from a client socket.
1441 * It returns 0.
1442 */
1443int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001444 struct task *t = fdtab[fd].owner;
1445 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001446 struct buffer *b = s->req;
1447 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001448
1449 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1450
willy tarreau0f7af912005-12-17 12:21:26 +01001451 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001452 while (1) {
1453 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1454 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001455 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001456 }
1457 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001458 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001459 }
1460 else {
1461 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001462 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1463 * since it means that the rewrite protection has been removed. This
1464 * implies that the if statement can be removed.
1465 */
1466 if (max > b->rlim - b->data)
1467 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001468 }
1469
1470 if (max == 0) { /* not anymore room to store data */
1471 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001472 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001473 }
1474
willy tarreau3242e862005-12-17 12:27:53 +01001475#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001476 {
1477 int skerr, lskerr;
1478
1479 lskerr = sizeof(skerr);
1480 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1481 if (skerr)
1482 ret = -1;
1483 else
1484 ret = recv(fd, b->r, max, 0);
1485 }
willy tarreau3242e862005-12-17 12:27:53 +01001486#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001487 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001488#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001489 if (ret > 0) {
1490 b->r += ret;
1491 b->l += ret;
1492 s->res_cr = RES_DATA;
1493
1494 if (b->r == b->data + BUFSIZE) {
1495 b->r = b->data; /* wrap around the buffer */
1496 }
willy tarreaua1598082005-12-17 13:08:06 +01001497
1498 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001499 /* we hope to read more data or to get a close on next round */
1500 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001501 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001502 else if (ret == 0) {
1503 s->res_cr = RES_NULL;
1504 break;
1505 }
1506 else if (errno == EAGAIN) {/* ignore EAGAIN */
1507 break;
1508 }
1509 else {
1510 s->res_cr = RES_ERROR;
1511 fdtab[fd].state = FD_STERROR;
1512 break;
1513 }
1514 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001515 }
1516 else {
1517 s->res_cr = RES_ERROR;
1518 fdtab[fd].state = FD_STERROR;
1519 }
1520
willy tarreau5cbea6f2005-12-17 12:48:26 +01001521 if (s->res_cr != RES_SILENT) {
1522 if (s->proxy->clitimeout)
1523 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1524 else
1525 tv_eternity(&s->crexpire);
1526
1527 task_wakeup(&rq, t);
1528 }
willy tarreau0f7af912005-12-17 12:21:26 +01001529
willy tarreau0f7af912005-12-17 12:21:26 +01001530 return 0;
1531}
1532
1533
1534/*
1535 * this function is called on a read event from a server socket.
1536 * It returns 0.
1537 */
1538int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001539 struct task *t = fdtab[fd].owner;
1540 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001541 struct buffer *b = s->rep;
1542 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001543
1544 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1545
willy tarreau0f7af912005-12-17 12:21:26 +01001546 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001547 while (1) {
1548 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1549 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001550 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001551 }
1552 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001553 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001554 }
1555 else {
1556 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001557 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1558 * since it means that the rewrite protection has been removed. This
1559 * implies that the if statement can be removed.
1560 */
1561 if (max > b->rlim - b->data)
1562 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001563 }
1564
1565 if (max == 0) { /* not anymore room to store data */
1566 FD_CLR(fd, StaticReadEvent);
1567 break;
1568 }
1569
willy tarreau3242e862005-12-17 12:27:53 +01001570#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001571 {
1572 int skerr, lskerr;
1573
1574 lskerr = sizeof(skerr);
1575 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1576 if (skerr)
1577 ret = -1;
1578 else
1579 ret = recv(fd, b->r, max, 0);
1580 }
willy tarreau3242e862005-12-17 12:27:53 +01001581#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001582 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001583#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001584 if (ret > 0) {
1585 b->r += ret;
1586 b->l += ret;
1587 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001588
willy tarreau5cbea6f2005-12-17 12:48:26 +01001589 if (b->r == b->data + BUFSIZE) {
1590 b->r = b->data; /* wrap around the buffer */
1591 }
willy tarreaua1598082005-12-17 13:08:06 +01001592
1593 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594 /* we hope to read more data or to get a close on next round */
1595 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001596 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001597 else if (ret == 0) {
1598 s->res_sr = RES_NULL;
1599 break;
1600 }
1601 else if (errno == EAGAIN) {/* ignore EAGAIN */
1602 break;
1603 }
1604 else {
1605 s->res_sr = RES_ERROR;
1606 fdtab[fd].state = FD_STERROR;
1607 break;
1608 }
1609 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001610 }
1611 else {
1612 s->res_sr = RES_ERROR;
1613 fdtab[fd].state = FD_STERROR;
1614 }
1615
willy tarreau5cbea6f2005-12-17 12:48:26 +01001616 if (s->res_sr != RES_SILENT) {
1617 if (s->proxy->srvtimeout)
1618 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1619 else
1620 tv_eternity(&s->srexpire);
1621
1622 task_wakeup(&rq, t);
1623 }
willy tarreau0f7af912005-12-17 12:21:26 +01001624
willy tarreau0f7af912005-12-17 12:21:26 +01001625 return 0;
1626}
1627
1628/*
1629 * this function is called on a write event from a client socket.
1630 * It returns 0.
1631 */
1632int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001633 struct task *t = fdtab[fd].owner;
1634 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001635 struct buffer *b = s->rep;
1636 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001637
1638 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1639
1640 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001641 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001642 // max = BUFSIZE; BUG !!!!
1643 max = 0;
1644 }
1645 else if (b->r > b->w) {
1646 max = b->r - b->w;
1647 }
1648 else
1649 max = b->data + BUFSIZE - b->w;
1650
willy tarreau0f7af912005-12-17 12:21:26 +01001651 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001652#ifndef MSG_NOSIGNAL
1653 int skerr, lskerr;
1654#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001655
1656 if (max == 0) {
1657 s->res_cw = RES_NULL;
1658 task_wakeup(&rq, t);
1659 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001660 }
1661
willy tarreau3242e862005-12-17 12:27:53 +01001662#ifndef MSG_NOSIGNAL
1663 lskerr=sizeof(skerr);
1664 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1665 if (skerr)
1666 ret = -1;
1667 else
1668 ret = send(fd, b->w, max, MSG_DONTWAIT);
1669#else
willy tarreau0f7af912005-12-17 12:21:26 +01001670 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001671#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001672
1673 if (ret > 0) {
1674 b->l -= ret;
1675 b->w += ret;
1676
1677 s->res_cw = RES_DATA;
1678
1679 if (b->w == b->data + BUFSIZE) {
1680 b->w = b->data; /* wrap around the buffer */
1681 }
1682 }
1683 else if (ret == 0) {
1684 /* nothing written, just make as if we were never called */
1685// s->res_cw = RES_NULL;
1686 return 0;
1687 }
1688 else if (errno == EAGAIN) /* ignore EAGAIN */
1689 return 0;
1690 else {
1691 s->res_cw = RES_ERROR;
1692 fdtab[fd].state = FD_STERROR;
1693 }
1694 }
1695 else {
1696 s->res_cw = RES_ERROR;
1697 fdtab[fd].state = FD_STERROR;
1698 }
1699
1700 if (s->proxy->clitimeout)
1701 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1702 else
1703 tv_eternity(&s->cwexpire);
1704
willy tarreau5cbea6f2005-12-17 12:48:26 +01001705 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001706 return 0;
1707}
1708
1709
1710/*
1711 * this function is called on a write event from a server socket.
1712 * It returns 0.
1713 */
1714int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001715 struct task *t = fdtab[fd].owner;
1716 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001717 struct buffer *b = s->req;
1718 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001719
1720 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1721
1722 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001723 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001724 // max = BUFSIZE; BUG !!!!
1725 max = 0;
1726 }
1727 else if (b->r > b->w) {
1728 max = b->r - b->w;
1729 }
1730 else
1731 max = b->data + BUFSIZE - b->w;
1732
willy tarreau0f7af912005-12-17 12:21:26 +01001733 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001734#ifndef MSG_NOSIGNAL
1735 int skerr, lskerr;
1736#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001737 if (max == 0) {
1738 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001739 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001740 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001741 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001742 return 0;
1743 }
1744
willy tarreauef900ab2005-12-17 12:52:52 +01001745
willy tarreau3242e862005-12-17 12:27:53 +01001746#ifndef MSG_NOSIGNAL
1747 lskerr=sizeof(skerr);
1748 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1749 if (skerr)
1750 ret = -1;
1751 else
1752 ret = send(fd, b->w, max, MSG_DONTWAIT);
1753#else
willy tarreau0f7af912005-12-17 12:21:26 +01001754 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001755#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001756 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001757 if (ret > 0) {
1758 b->l -= ret;
1759 b->w += ret;
1760
1761 s->res_sw = RES_DATA;
1762
1763 if (b->w == b->data + BUFSIZE) {
1764 b->w = b->data; /* wrap around the buffer */
1765 }
1766 }
1767 else if (ret == 0) {
1768 /* nothing written, just make as if we were never called */
1769 // s->res_sw = RES_NULL;
1770 return 0;
1771 }
1772 else if (errno == EAGAIN) /* ignore EAGAIN */
1773 return 0;
1774 else {
1775 s->res_sw = RES_ERROR;
1776 fdtab[fd].state = FD_STERROR;
1777 }
1778 }
1779 else {
1780 s->res_sw = RES_ERROR;
1781 fdtab[fd].state = FD_STERROR;
1782 }
1783
1784 if (s->proxy->srvtimeout)
1785 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1786 else
1787 tv_eternity(&s->swexpire);
1788
willy tarreau5cbea6f2005-12-17 12:48:26 +01001789 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001790 return 0;
1791}
1792
1793
1794/*
willy tarreaue39cd132005-12-17 13:00:18 +01001795 * returns a message to the client ; the connection is shut down for read,
1796 * and the request is cleared so that no server connection can be initiated.
1797 * The client must be in a valid state for this (HEADER, DATA ...).
1798 * Nothing is performed on the server side.
1799 * The reply buffer must be empty before this.
1800 */
1801void client_retnclose(struct session *s, int len, const char *msg) {
1802 FD_CLR(s->cli_fd, StaticReadEvent);
1803 FD_SET(s->cli_fd, StaticWriteEvent);
1804 tv_eternity(&s->crexpire);
1805 shutdown(s->cli_fd, SHUT_RD);
1806 s->cli_state = CL_STSHUTR;
1807 strcpy(s->rep->data, msg);
1808 s->rep->l = len;
1809 s->rep->r += len;
1810 s->req->l = 0;
1811}
1812
1813
1814/*
1815 * returns a message into the rep buffer, and flushes the req buffer.
1816 * The reply buffer must be empty before this.
1817 */
1818void client_return(struct session *s, int len, const char *msg) {
1819 strcpy(s->rep->data, msg);
1820 s->rep->l = len;
1821 s->rep->r += len;
1822 s->req->l = 0;
1823}
1824
willy tarreau9fe663a2005-12-17 13:02:59 +01001825/*
1826 * send a log for the session when we have enough info about it
1827 */
1828void sess_log(struct session *s) {
1829 unsigned char *pn;
1830 struct proxy *p = s->proxy;
1831 int log;
1832 char *uri;
1833 char *pxid;
1834 char *srv;
1835
1836 /* This is a first attempt at a better logging system.
1837 * For now, we rely on send_log() to provide the date, although it obviously
1838 * is the date of the log and not of the request, and most fields are not
1839 * computed.
1840 */
1841
willy tarreaua1598082005-12-17 13:08:06 +01001842 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001843
1844 pn = (log & LW_CLIP) ?
1845 (unsigned char *)&s->cli_addr.sin_addr :
1846 (unsigned char *)"\0\0\0\0";
1847
willy tarreaua1598082005-12-17 13:08:06 +01001848 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001849 pxid = p->id;
1850 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001851 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1852
1853 if (p->to_log & LW_DATE) {
1854 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1855
1856 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld \"%s\"\n",
1857 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1858 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1859 tm->tm_hour, tm->tm_min, tm->tm_sec,
1860 pxid, srv,
1861 s->logs.t_request,
1862 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1863 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1864 s->logs.t_close,
1865 s->logs.status, s->logs.bytes,
1866 uri);
1867 }
1868 else {
1869 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld \"%s\"\n",
1870 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1871 pxid, srv,
1872 s->logs.t_request,
1873 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1874 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1875 s->logs.t_close,
1876 s->logs.status, s->logs.bytes,
1877 uri);
1878 }
1879
1880 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001881}
1882
willy tarreaue39cd132005-12-17 13:00:18 +01001883
1884/*
willy tarreau0f7af912005-12-17 12:21:26 +01001885 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001886 * to an accept. It tries to accept as many connections as possible.
1887 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001888 */
1889int event_accept(int fd) {
1890 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001891 struct session *s;
1892 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001893 int cfd;
1894 int one = 1;
1895
willy tarreau5cbea6f2005-12-17 12:48:26 +01001896 while (p->nbconn < p->maxconn) {
1897 struct sockaddr_in addr;
1898 int laddr = sizeof(addr);
1899 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1900 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001901
willy tarreau5cbea6f2005-12-17 12:48:26 +01001902 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1903 Alert("out of memory in event_accept().\n");
1904 FD_CLR(fd, StaticReadEvent);
1905 p->state = PR_STIDLE;
1906 close(cfd);
1907 return 0;
1908 }
willy tarreau0f7af912005-12-17 12:21:26 +01001909
willy tarreau5cbea6f2005-12-17 12:48:26 +01001910 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1911 Alert("out of memory in event_accept().\n");
1912 FD_CLR(fd, StaticReadEvent);
1913 p->state = PR_STIDLE;
1914 close(cfd);
1915 pool_free(session, s);
1916 return 0;
1917 }
willy tarreau0f7af912005-12-17 12:21:26 +01001918
willy tarreau5cbea6f2005-12-17 12:48:26 +01001919 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001920 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001921 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1922 close(cfd);
1923 pool_free(task, t);
1924 pool_free(session, s);
1925 return 0;
1926 }
willy tarreau0f7af912005-12-17 12:21:26 +01001927
willy tarreau5cbea6f2005-12-17 12:48:26 +01001928 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1929 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1930 (char *) &one, sizeof(one)) == -1)) {
1931 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1932 close(cfd);
1933 pool_free(task, t);
1934 pool_free(session, s);
1935 return 0;
1936 }
willy tarreau0f7af912005-12-17 12:21:26 +01001937
willy tarreau9fe663a2005-12-17 13:02:59 +01001938 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1939 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1940 t->state = TASK_IDLE;
1941 t->process = process_session;
1942 t->context = s;
1943
1944 s->task = t;
1945 s->proxy = p;
1946 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1947 s->srv_state = SV_STIDLE;
1948 s->req = s->rep = NULL; /* will be allocated later */
1949 s->flags = 0;
1950 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1951 s->cli_fd = cfd;
1952 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01001953 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01001954 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01001955
1956 s->logs.logwait = p->to_log;
1957 s->logs.tv_accept = now;
1958 s->logs.t_request = -1;
1959 s->logs.t_connect = -1;
1960 s->logs.t_data = -1;
1961 s->logs.t_close = 0;
1962 s->logs.uri = NULL;
1963 s->logs.status = -1;
1964 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001965
willy tarreau5cbea6f2005-12-17 12:48:26 +01001966 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1967 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01001968 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001969 unsigned char *pn, *sn;
1970 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01001971
willy tarreau5cbea6f2005-12-17 12:48:26 +01001972 namelen = sizeof(sockname);
1973 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1974 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1975 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01001976 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001977
willy tarreau9fe663a2005-12-17 13:02:59 +01001978 if (p->to_log) {
1979 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01001980 if (s->logs.logwait & LW_CLIP)
1981 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01001982 sess_log(s);
1983 }
1984 else
1985 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1986 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1987 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1988 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01001989 }
willy tarreau0f7af912005-12-17 12:21:26 +01001990
willy tarreau9fe663a2005-12-17 13:02:59 +01001991 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreauef900ab2005-12-17 12:52:52 +01001992 int len;
1993 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1994 write(1, trash, len);
1995 }
willy tarreau0f7af912005-12-17 12:21:26 +01001996
willy tarreau5cbea6f2005-12-17 12:48:26 +01001997 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1998 close(cfd); /* nothing can be done for this fd without memory */
1999 pool_free(task, t);
2000 pool_free(session, s);
2001 return 0;
2002 }
2003 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002004 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002005 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2006 s->req->rlim = s->req->data + BUFSIZE;
2007 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
2008 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002009
willy tarreau5cbea6f2005-12-17 12:48:26 +01002010 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2011 pool_free(buffer, s->req);
2012 close(cfd); /* nothing can be done for this fd without memory */
2013 pool_free(task, t);
2014 pool_free(session, s);
2015 return 0;
2016 }
2017 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002018 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002019 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 +01002020
willy tarreau5cbea6f2005-12-17 12:48:26 +01002021 fdtab[cfd].read = &event_cli_read;
2022 fdtab[cfd].write = &event_cli_write;
2023 fdtab[cfd].owner = t;
2024 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002025
willy tarreau5cbea6f2005-12-17 12:48:26 +01002026 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01002027 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002028 }
2029 else {
2030 FD_SET(cfd, StaticReadEvent);
2031 }
2032
2033 fd_insert(cfd);
2034
2035 tv_eternity(&s->cnexpire);
2036 tv_eternity(&s->srexpire);
2037 tv_eternity(&s->swexpire);
2038 tv_eternity(&s->cwexpire);
2039
2040 if (s->proxy->clitimeout)
2041 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2042 else
2043 tv_eternity(&s->crexpire);
2044
2045 t->expire = s->crexpire;
2046
2047 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002048
2049 if (p->mode != PR_MODE_HEALTH)
2050 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002051
2052 p->nbconn++;
2053 actconn++;
2054 totalconn++;
2055
2056 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2057 } /* end of while (p->nbconn < p->maxconn) */
2058 return 0;
2059}
willy tarreau0f7af912005-12-17 12:21:26 +01002060
willy tarreau0f7af912005-12-17 12:21:26 +01002061
willy tarreau5cbea6f2005-12-17 12:48:26 +01002062/*
2063 * This function is used only for server health-checks. It handles
2064 * the connection acknowledgement and returns 1 if the socket is OK,
2065 * or -1 if an error occured.
2066 */
2067int event_srv_hck(int fd) {
2068 struct task *t = fdtab[fd].owner;
2069 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002070
willy tarreau5cbea6f2005-12-17 12:48:26 +01002071 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002072 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002073 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2074 if (skerr)
2075 s->result = -1;
2076 else
2077 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002078
willy tarreau5cbea6f2005-12-17 12:48:26 +01002079 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002080 return 0;
2081}
2082
2083
2084/*
2085 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2086 * and moves <end> just after the end of <str>.
2087 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2088 * the shift value (positive or negative) is returned.
2089 * If there's no space left, the move is not done.
2090 *
2091 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002092int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002093 int delta;
2094 int len;
2095
2096 len = strlen(str);
2097 delta = len - (end - pos);
2098
2099 if (delta + b->r >= b->data + BUFSIZE)
2100 return 0; /* no space left */
2101
2102 /* first, protect the end of the buffer */
2103 memmove(end + delta, end, b->data + b->l - end);
2104
2105 /* now, copy str over pos */
2106 memcpy(pos, str,len);
2107
willy tarreau5cbea6f2005-12-17 12:48:26 +01002108 /* we only move data after the displaced zone */
2109 if (b->r > pos) b->r += delta;
2110 if (b->w > pos) b->w += delta;
2111 if (b->h > pos) b->h += delta;
2112 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002113 b->l += delta;
2114
2115 return delta;
2116}
2117
willy tarreau240afa62005-12-17 13:14:35 +01002118/* same except that the string len is given, which allows str to be NULL if
2119 * len is 0.
2120 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002121int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002122 int delta;
2123
2124 delta = len - (end - pos);
2125
2126 if (delta + b->r >= b->data + BUFSIZE)
2127 return 0; /* no space left */
2128
2129 /* first, protect the end of the buffer */
2130 memmove(end + delta, end, b->data + b->l - end);
2131
2132 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002133 if (len)
2134 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002135
willy tarreau5cbea6f2005-12-17 12:48:26 +01002136 /* we only move data after the displaced zone */
2137 if (b->r > pos) b->r += delta;
2138 if (b->w > pos) b->w += delta;
2139 if (b->h > pos) b->h += delta;
2140 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002141 b->l += delta;
2142
2143 return delta;
2144}
2145
2146
2147int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2148 char *old_dst = dst;
2149
2150 while (*str) {
2151 if (*str == '\\') {
2152 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002153 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002154 int len, num;
2155
2156 num = *str - '0';
2157 str++;
2158
2159 if (matches[num].rm_so > -1) {
2160 len = matches[num].rm_eo - matches[num].rm_so;
2161 memcpy(dst, src + matches[num].rm_so, len);
2162 dst += len;
2163 }
2164
2165 }
2166 else if (*str == 'x') {
2167 unsigned char hex1, hex2;
2168 str++;
2169
2170 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2171
2172 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2173 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2174 *dst++ = (hex1<<4) + hex2;
2175 }
2176 else
2177 *dst++ = *str++;
2178 }
2179 else
2180 *dst++ = *str++;
2181 }
2182 *dst = 0;
2183 return dst - old_dst;
2184}
2185
willy tarreau9fe663a2005-12-17 13:02:59 +01002186
willy tarreau0f7af912005-12-17 12:21:26 +01002187/*
2188 * manages the client FSM and its socket. BTW, it also tries to handle the
2189 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2190 * 0 else.
2191 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002192int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002193 int s = t->srv_state;
2194 int c = t->cli_state;
2195 struct buffer *req = t->req;
2196 struct buffer *rep = t->rep;
2197
willy tarreau750a4722005-12-17 13:21:24 +01002198#ifdef DEBUG_FULL
2199 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2200#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002201 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2202 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2203 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2204 //);
2205 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002206 /* now parse the partial (or complete) headers */
2207 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2208 char *ptr;
2209 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002210
willy tarreau5cbea6f2005-12-17 12:48:26 +01002211 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002212
willy tarreau0f7af912005-12-17 12:21:26 +01002213 /* look for the end of the current header */
2214 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2215 ptr++;
2216
willy tarreau5cbea6f2005-12-17 12:48:26 +01002217 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002218 int line, len;
2219 /* we can only get here after an end of headers */
2220 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002221
willy tarreaue39cd132005-12-17 13:00:18 +01002222 if (t->flags & SN_CLDENY) {
2223 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002224 t->logs.status = 403;
willy tarreau750a4722005-12-17 13:21:24 +01002225 if (t->proxy->mode == PR_MODE_HTTP)
2226 client_retnclose(t, strlen(HTTP_403), HTTP_403);
willy tarreaue39cd132005-12-17 13:00:18 +01002227 return 1;
2228 }
2229
willy tarreau5cbea6f2005-12-17 12:48:26 +01002230 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002231 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2232 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002233 }
willy tarreau0f7af912005-12-17 12:21:26 +01002234
willy tarreau9fe663a2005-12-17 13:02:59 +01002235 if (t->proxy->options & PR_O_FWDFOR) {
2236 /* insert an X-Forwarded-For header */
2237 unsigned char *pn;
2238 pn = (unsigned char *)&t->cli_addr.sin_addr;
willy tarreau750a4722005-12-17 13:21:24 +01002239 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01002240 pn[0], pn[1], pn[2], pn[3]);
willy tarreau750a4722005-12-17 13:21:24 +01002241 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau9fe663a2005-12-17 13:02:59 +01002242 }
2243
willy tarreaucd878942005-12-17 13:27:43 +01002244 if (!memcmp(req->data, "POST ", 5))
2245 t->flags |= SN_POST; /* this is a POST request */
2246
willy tarreau5cbea6f2005-12-17 12:48:26 +01002247 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002248 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002249
willy tarreau750a4722005-12-17 13:21:24 +01002250 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002251 /* FIXME: we'll set the client in a wait state while we try to
2252 * connect to the server. Is this really needed ? wouldn't it be
2253 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002254 //FD_CLR(t->cli_fd, StaticReadEvent);
2255 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002256 break;
2257 }
willy tarreau0f7af912005-12-17 12:21:26 +01002258
willy tarreau5cbea6f2005-12-17 12:48:26 +01002259 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2260 if (ptr > req->r - 2) {
2261 /* this is a partial header, let's wait for more to come */
2262 req->lr = ptr;
2263 break;
2264 }
willy tarreau0f7af912005-12-17 12:21:26 +01002265
willy tarreau5cbea6f2005-12-17 12:48:26 +01002266 /* now we know that *ptr is either \r or \n,
2267 * and that there are at least 1 char after it.
2268 */
2269 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2270 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2271 else
2272 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002273
willy tarreau5cbea6f2005-12-17 12:48:26 +01002274 /*
2275 * now we know that we have a full header ; we can do whatever
2276 * we want with these pointers :
2277 * req->h = beginning of header
2278 * ptr = end of header (first \r or \n)
2279 * req->lr = beginning of next line (next rep->h)
2280 * req->r = end of data (not used at this stage)
2281 */
willy tarreau0f7af912005-12-17 12:21:26 +01002282
willy tarreaua1598082005-12-17 13:08:06 +01002283 if (t->logs.logwait & LW_REQ &&
2284 t->proxy->mode & PR_MODE_HTTP) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002285 /* we have a complete HTTP request that we must log */
2286 int urilen;
2287
willy tarreaua1598082005-12-17 13:08:06 +01002288 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002289 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002290 t->logs.status = 500;
2291 if (t->proxy->mode == PR_MODE_HTTP)
2292 client_retnclose(t, strlen(HTTP_500), HTTP_500);
willy tarreau9fe663a2005-12-17 13:02:59 +01002293 return 1;
2294 }
2295
2296 urilen = ptr - req->h;
2297 if (urilen >= REQURI_LEN)
2298 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002299 memcpy(t->logs.uri, req->h, urilen);
2300 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002301
willy tarreaua1598082005-12-17 13:08:06 +01002302 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002303 sess_log(t);
2304 }
2305
willy tarreau5cbea6f2005-12-17 12:48:26 +01002306 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002307
willy tarreau9fe663a2005-12-17 13:02:59 +01002308 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002309 int len, max;
2310 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2311 max = ptr - req->h;
2312 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002313 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002314 trash[len++] = '\n';
2315 write(1, trash, len);
2316 }
willy tarreau0f7af912005-12-17 12:21:26 +01002317
willy tarreau5cbea6f2005-12-17 12:48:26 +01002318 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002319 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2320 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 char term;
2322
2323 term = *ptr;
2324 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002325 exp = t->proxy->req_exp;
2326 do {
2327 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2328 switch (exp->action) {
2329 case ACT_ALLOW:
2330 if (!(t->flags & SN_CLDENY))
2331 t->flags |= SN_CLALLOW;
2332 break;
2333 case ACT_REPLACE:
2334 if (!(t->flags & SN_CLDENY)) {
2335 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2336 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2337 }
2338 break;
2339 case ACT_REMOVE:
2340 if (!(t->flags & SN_CLDENY))
2341 delete_header = 1;
2342 break;
2343 case ACT_DENY:
2344 if (!(t->flags & SN_CLALLOW))
2345 t->flags |= SN_CLDENY;
2346 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002347 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002348 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002349 }
willy tarreaue39cd132005-12-17 13:00:18 +01002350 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002351 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002352 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002353
willy tarreau240afa62005-12-17 13:14:35 +01002354 /* Now look for cookies. Conforming to RFC2109, we have to support
2355 * attributes whose name begin with a '$', and associate them with
2356 * the right cookie, if we want to delete this cookie.
2357 * So there are 3 cases for each cookie read :
2358 * 1) it's a special attribute, beginning with a '$' : ignore it.
2359 * 2) it's a server id cookie that we *MAY* want to delete : save
2360 * some pointers on it (last semi-colon, beginning of cookie...)
2361 * 3) it's an application cookie : we *MAY* have to delete a previous
2362 * "special" cookie.
2363 * At the end of loop, if a "special" cookie remains, we may have to
2364 * remove it. If no application cookie persists in the header, we
2365 * *MUST* delete it
2366 */
2367 if (!delete_header && (t->proxy->cookie_name != NULL)
2368 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002369 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
2370 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002371 char *del_colon, *del_cookie, *colon;
2372 int app_cookies;
2373
willy tarreau5cbea6f2005-12-17 12:48:26 +01002374 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002375 colon = p1;
2376 /* del_cookie == NULL => nothing to be deleted */
2377 del_colon = del_cookie = NULL;
2378 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002379
2380 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002381 /* skip spaces and colons, but keep an eye on these ones */
2382 while (p1 < ptr) {
2383 if (*p1 == ';' || *p1 == ',')
2384 colon = p1;
2385 else if (!isspace((int)*p1))
2386 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002387 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002388 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002389
2390 if (p1 == ptr)
2391 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002392
2393 /* p1 is at the beginning of the cookie name */
2394 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002395 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002396 p2++;
2397
2398 if (p2 == ptr)
2399 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002400
2401 p3 = p2 + 1; /* skips the '=' sign */
2402 if (p3 == ptr)
2403 break;
2404
willy tarreau240afa62005-12-17 13:14:35 +01002405 p4 = p3;
2406 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002407 p4++;
2408
2409 /* here, we have the cookie name between p1 and p2,
2410 * and its value between p3 and p4.
2411 * we can process it.
2412 */
2413
willy tarreau240afa62005-12-17 13:14:35 +01002414 if (*p1 == '$') {
2415 /* skip this one */
2416 }
2417 else if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2418 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002419 /* Cool... it's the right one */
2420 struct server *srv = t->proxy->srv;
2421
2422 while (srv &&
2423 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2424 srv = srv->next;
2425 }
2426
2427 if (srv) { /* we found the server */
willy tarreaue39cd132005-12-17 13:00:18 +01002428 t->flags |= SN_DIRECT;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002429 t->srv = srv;
2430 }
willy tarreau240afa62005-12-17 13:14:35 +01002431 /* if this cookie was set in insert+indirect mode, then it's better that the
2432 * server never sees it.
2433 */
2434 if (del_cookie == NULL &&
2435 (t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
2436 del_cookie = p1;
2437 del_colon = colon;
2438 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002439 }
2440 else {
willy tarreau240afa62005-12-17 13:14:35 +01002441 /* now we know that we must keep this cookie since it's
2442 * not ours. But if we wanted to delete our cookie
2443 * earlier, we cannot remove the complete header, but we
2444 * can remove the previous block itself.
2445 */
2446 app_cookies++;
2447
2448 if (del_cookie != NULL) {
2449 buffer_replace2(req, del_cookie, p1, NULL, 0);
2450 p4 -= (p1 - del_cookie);
2451 ptr -= (p1 - del_cookie);
2452 del_cookie = del_colon = NULL;
2453 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002454 }
willy tarreau240afa62005-12-17 13:14:35 +01002455
willy tarreau5cbea6f2005-12-17 12:48:26 +01002456 /* we'll have to look for another cookie ... */
2457 p1 = p4;
2458 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002459
2460 /* There's no more cookie on this line.
2461 * We may have marked the last one(s) for deletion.
2462 * We must do this now in two ways :
2463 * - if there is no app cookie, we simply delete the header ;
2464 * - if there are app cookies, we must delete the end of the
2465 * string properly, including the colon/semi-colon before
2466 * the cookie name.
2467 */
2468 if (del_cookie != NULL) {
2469 if (app_cookies) {
2470 buffer_replace2(req, del_colon, ptr, NULL, 0);
2471 /* WARNING! <ptr> becomes invalid for now. If some code
2472 * below needs to rely on it before the end of the global
2473 * header loop, we need to correct it with this code :
2474 * ptr = del_colon;
2475 */
2476 }
2477 else
2478 delete_header = 1;
2479 }
2480 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002481
2482 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002483 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002484 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002485 }
willy tarreau240afa62005-12-17 13:14:35 +01002486 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2487
willy tarreau5cbea6f2005-12-17 12:48:26 +01002488 req->h = req->lr;
2489 } /* while (req->lr < req->r) */
2490
2491 /* end of header processing (even if incomplete) */
2492
willy tarreauef900ab2005-12-17 12:52:52 +01002493 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2494 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2495 * full. We cannot loop here since event_cli_read will disable it only if
2496 * req->l == rlim-data
2497 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002498 FD_SET(t->cli_fd, StaticReadEvent);
2499 if (t->proxy->clitimeout)
2500 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2501 else
2502 tv_eternity(&t->crexpire);
2503 }
2504
willy tarreaue39cd132005-12-17 13:00:18 +01002505 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002506 * won't be able to free more later, so the session will never terminate.
2507 */
willy tarreaue39cd132005-12-17 13:00:18 +01002508 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002509 t->logs.status = 400;
willy tarreau750a4722005-12-17 13:21:24 +01002510 if (t->proxy->mode == PR_MODE_HTTP)
2511 client_retnclose(t, strlen(HTTP_400), HTTP_400);
willy tarreaue39cd132005-12-17 13:00:18 +01002512 return 1;
2513 }
2514 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2515 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2516
2517 /* read timeout, read error, or last read : give up.
2518 * since we are in header mode, if there's no space left for headers, we
2519 * won't be able to free more later, so the session will never terminate.
2520 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002521 tv_eternity(&t->crexpire);
2522 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002523 t->cli_state = CL_STCLOSE;
2524 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002525 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002526
2527 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002528 }
2529 else if (c == CL_STDATA) {
2530 /* read or write error */
2531 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002532 tv_eternity(&t->crexpire);
2533 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002534 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002535 t->cli_state = CL_STCLOSE;
2536 return 1;
2537 }
2538 /* read timeout, last read, or end of server write */
2539 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2540 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002541 FD_CLR(t->cli_fd, StaticReadEvent);
2542 // if (req->l == 0) /* nothing to write on the server side */
2543 // FD_CLR(t->srv_fd, StaticWriteEvent);
2544 tv_eternity(&t->crexpire);
2545 shutdown(t->cli_fd, SHUT_RD);
2546 t->cli_state = CL_STSHUTR;
2547 return 1;
2548 }
2549 /* write timeout, or last server read and buffer empty */
2550 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2551 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002552 FD_CLR(t->cli_fd, StaticWriteEvent);
2553 tv_eternity(&t->cwexpire);
2554 shutdown(t->cli_fd, SHUT_WR);
2555 t->cli_state = CL_STSHUTW;
2556 return 1;
2557 }
2558
willy tarreauef900ab2005-12-17 12:52:52 +01002559 if (req->l >= req->rlim - req->data) {
2560 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002561 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002562 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002563 FD_CLR(t->cli_fd, StaticReadEvent);
2564 tv_eternity(&t->crexpire);
2565 }
2566 }
2567 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002568 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002569 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2570 FD_SET(t->cli_fd, StaticReadEvent);
2571 if (t->proxy->clitimeout)
2572 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2573 else
2574 tv_eternity(&t->crexpire);
2575 }
2576 }
2577
2578 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002579 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002580 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2581 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2582 tv_eternity(&t->cwexpire);
2583 }
2584 }
2585 else { /* buffer not empty */
2586 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2587 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2588 if (t->proxy->clitimeout)
2589 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2590 else
2591 tv_eternity(&t->cwexpire);
2592 }
2593 }
2594 return 0; /* other cases change nothing */
2595 }
2596 else if (c == CL_STSHUTR) {
2597 if ((t->res_cw == RES_ERROR) ||
2598 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002599 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002600 tv_eternity(&t->cwexpire);
2601 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002602 t->cli_state = CL_STCLOSE;
2603 return 1;
2604 }
2605 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002606 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002607 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2608 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2609 tv_eternity(&t->cwexpire);
2610 }
2611 }
2612 else { /* buffer not empty */
2613 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2614 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2615 if (t->proxy->clitimeout)
2616 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2617 else
2618 tv_eternity(&t->cwexpire);
2619 }
2620 }
2621 return 0;
2622 }
2623 else if (c == CL_STSHUTW) {
2624 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002625 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002626 tv_eternity(&t->crexpire);
2627 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002628 t->cli_state = CL_STCLOSE;
2629 return 1;
2630 }
willy tarreauef900ab2005-12-17 12:52:52 +01002631 else if (req->l >= req->rlim - req->data) {
2632 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002633 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002634 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002635 FD_CLR(t->cli_fd, StaticReadEvent);
2636 tv_eternity(&t->crexpire);
2637 }
2638 }
2639 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002640 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002641 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2642 FD_SET(t->cli_fd, StaticReadEvent);
2643 if (t->proxy->clitimeout)
2644 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2645 else
2646 tv_eternity(&t->crexpire);
2647 }
2648 }
2649 return 0;
2650 }
2651 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002652 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002653 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002654 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002655 write(1, trash, len);
2656 }
2657 return 0;
2658 }
2659 return 0;
2660}
2661
2662
2663/*
2664 * manages the server FSM and its socket. It returns 1 if a state has changed
2665 * (and a resync may be needed), 0 else.
2666 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002667int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002668 int s = t->srv_state;
2669 int c = t->cli_state;
2670 struct buffer *req = t->req;
2671 struct buffer *rep = t->rep;
2672
willy tarreau750a4722005-12-17 13:21:24 +01002673#ifdef DEBUG_FULL
2674 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2675#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002676 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2677 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2678 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2679 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002680 if (s == SV_STIDLE) {
2681 if (c == CL_STHEADERS)
2682 return 0; /* stay in idle, waiting for data to reach the client side */
2683 else if (c == CL_STCLOSE ||
2684 c == CL_STSHUTW ||
2685 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2686 tv_eternity(&t->cnexpire);
2687 t->srv_state = SV_STCLOSE;
2688 return 1;
2689 }
2690 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002691 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002692 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2693 t->srv_state = SV_STCONN;
2694 }
2695 else { /* try again */
2696 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002697 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002698 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002699 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2700 }
2701
2702 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002703 t->srv_state = SV_STCONN;
2704 break;
2705 }
2706 }
2707 if (t->conn_retries < 0) {
2708 /* if conn_retries < 0 or other error, let's abort */
2709 tv_eternity(&t->cnexpire);
2710 t->srv_state = SV_STCLOSE;
willy tarreaua1598082005-12-17 13:08:06 +01002711 t->logs.status = 502;
willy tarreau750a4722005-12-17 13:21:24 +01002712 if (t->proxy->mode == PR_MODE_HTTP)
2713 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002714 }
2715 }
2716 return 1;
2717 }
2718 }
2719 else if (s == SV_STCONN) { /* connection in progress */
2720 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2721 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2722 return 0; /* nothing changed */
2723 }
2724 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2725 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2726 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002727 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002728 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002729 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002730 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002731 if (t->conn_retries >= 0) {
2732 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002733 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002734 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2735 }
2736 if (connect_server(t) == 0)
2737 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002738 }
2739 /* if conn_retries < 0 or other error, let's abort */
2740 tv_eternity(&t->cnexpire);
2741 t->srv_state = SV_STCLOSE;
willy tarreau750a4722005-12-17 13:21:24 +01002742 t->logs.status = 502;
2743 if (t->proxy->mode == PR_MODE_HTTP)
2744 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002745 return 1;
2746 }
2747 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01002748 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01002749
willy tarreau0f7af912005-12-17 12:21:26 +01002750 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2751 if (req->l == 0) /* nothing to write */
2752 FD_CLR(t->srv_fd, StaticWriteEvent);
2753 else /* need the right to write */
2754 FD_SET(t->srv_fd, StaticWriteEvent);
2755
2756 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2757 FD_SET(t->srv_fd, StaticReadEvent);
2758 if (t->proxy->srvtimeout)
2759 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2760 else
2761 tv_eternity(&t->srexpire);
2762
2763 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002764 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002765 }
willy tarreauef900ab2005-12-17 12:52:52 +01002766 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002767 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002768 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2769 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002770 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002771 return 1;
2772 }
2773 }
2774 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002775
2776 /* now parse the partial (or complete) headers */
2777 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2778 char *ptr;
2779 int delete_header;
2780
2781 ptr = rep->lr;
2782
2783 /* look for the end of the current header */
2784 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2785 ptr++;
2786
2787 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002788 int line, len;
2789
2790 /* we can only get here after an end of headers */
2791 /* we'll have something else to do here : add new headers ... */
2792
willy tarreaucd878942005-12-17 13:27:43 +01002793 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
2794 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002795 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01002796 * insert a set-cookie here, except if we want to insert only on POST
2797 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01002798 */
willy tarreau750a4722005-12-17 13:21:24 +01002799 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01002800 t->proxy->cookie_name, t->srv->cookie);
willy tarreau750a4722005-12-17 13:21:24 +01002801
2802 /* Here, we will tell an eventual cache on the client side that we don't
2803 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
2804 * Some caches understand the correct form: 'no-cache="set-cookie"', but
2805 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
2806 */
willy tarreau240afa62005-12-17 13:14:35 +01002807 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01002808 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
2809 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01002810
willy tarreau750a4722005-12-17 13:21:24 +01002811 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002812 }
2813
2814 /* headers to be added */
2815 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002816 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
2817 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002818 }
2819
2820 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002821 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01002822 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002823 break;
2824 }
2825
2826 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2827 if (ptr > rep->r - 2) {
2828 /* this is a partial header, let's wait for more to come */
2829 rep->lr = ptr;
2830 break;
2831 }
2832
2833 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2834 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2835
2836 /* now we know that *ptr is either \r or \n,
2837 * and that there are at least 1 char after it.
2838 */
2839 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2840 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2841 else
2842 rep->lr = ptr + 2; /* \r\n or \n\r */
2843
2844 /*
2845 * now we know that we have a full header ; we can do whatever
2846 * we want with these pointers :
2847 * rep->h = beginning of header
2848 * ptr = end of header (first \r or \n)
2849 * rep->lr = beginning of next line (next rep->h)
2850 * rep->r = end of data (not used at this stage)
2851 */
2852
willy tarreaua1598082005-12-17 13:08:06 +01002853
2854 if (t->logs.logwait & LW_RESP) {
2855 t->logs.logwait &= ~LW_RESP;
2856 t->logs.status = atoi(rep->h + 9);
2857 }
2858
willy tarreau5cbea6f2005-12-17 12:48:26 +01002859 delete_header = 0;
2860
willy tarreau9fe663a2005-12-17 13:02:59 +01002861 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002862 int len, max;
2863 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2864 max = ptr - rep->h;
2865 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002866 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002867 trash[len++] = '\n';
2868 write(1, trash, len);
2869 }
2870
2871 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002872 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
2873 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002874 char term;
2875
2876 term = *ptr;
2877 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002878 exp = t->proxy->rsp_exp;
2879 do {
2880 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2881 switch (exp->action) {
2882 case ACT_ALLOW:
2883 if (!(t->flags & SN_SVDENY))
2884 t->flags |= SN_SVALLOW;
2885 break;
2886 case ACT_REPLACE:
2887 if (!(t->flags & SN_SVDENY)) {
2888 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2889 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2890 }
2891 break;
2892 case ACT_REMOVE:
2893 if (!(t->flags & SN_SVDENY))
2894 delete_header = 1;
2895 break;
2896 case ACT_DENY:
2897 if (!(t->flags & SN_SVALLOW))
2898 t->flags |= SN_SVDENY;
2899 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002900 }
2901 break;
2902 }
willy tarreaue39cd132005-12-17 13:00:18 +01002903 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002904 *ptr = term; /* restore the string terminator */
2905 }
2906
2907 /* check for server cookies */
willy tarreau240afa62005-12-17 13:14:35 +01002908 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY)
2909 && (t->proxy->cookie_name != NULL) && (ptr >= rep->h + 12)
2910 && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002911 char *p1, *p2, *p3, *p4;
2912
2913 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2914
2915 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01002916 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002917 p1++;
2918
2919 if (p1 == ptr || *p1 == ';') /* end of cookie */
2920 break;
2921
2922 /* p1 is at the beginning of the cookie name */
2923 p2 = p1;
2924
2925 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2926 p2++;
2927
2928 if (p2 == ptr || *p2 == ';') /* next cookie */
2929 break;
2930
2931 p3 = p2 + 1; /* skips the '=' sign */
2932 if (p3 == ptr)
2933 break;
2934
2935 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01002936 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002937 p4++;
2938
2939 /* here, we have the cookie name between p1 and p2,
2940 * and its value between p3 and p4.
2941 * we can process it.
2942 */
2943
2944 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2945 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2946 /* Cool... it's the right one */
2947
2948 /* If the cookie is in insert mode on a known server, we'll delete
2949 * this occurrence because we'll insert another one later.
2950 * We'll delete it too if the "indirect" option is set and we're in
2951 * a direct access. */
2952 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01002953 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002954 /* this header must be deleted */
2955 delete_header = 1;
2956 }
2957 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2958 /* replace bytes p3->p4 with the cookie name associated
2959 * with this server since we know it.
2960 */
2961 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2962 }
2963 break;
2964 }
2965 else {
2966 // fprintf(stderr,"Ignoring unknown cookie : ");
2967 // write(2, p1, p2-p1);
2968 // fprintf(stderr," = ");
2969 // write(2, p3, p4-p3);
2970 // fprintf(stderr,"\n");
2971 }
2972 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2973 } /* we're now at the end of the cookie value */
2974 } /* end of cookie processing */
2975
2976 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002977 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002978 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01002979
willy tarreau5cbea6f2005-12-17 12:48:26 +01002980 rep->h = rep->lr;
2981 } /* while (rep->lr < rep->r) */
2982
2983 /* end of header processing (even if incomplete) */
2984
willy tarreauef900ab2005-12-17 12:52:52 +01002985 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2986 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2987 * full. We cannot loop here since event_srv_read will disable it only if
2988 * rep->l == rlim-data
2989 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002990 FD_SET(t->srv_fd, StaticReadEvent);
2991 if (t->proxy->srvtimeout)
2992 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2993 else
2994 tv_eternity(&t->srexpire);
2995 }
willy tarreau0f7af912005-12-17 12:21:26 +01002996
2997 /* read or write error */
2998 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002999 tv_eternity(&t->srexpire);
3000 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003001 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003002 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003003 t->logs.status = 502;
3004 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01003005 return 1;
3006 }
willy tarreauef900ab2005-12-17 12:52:52 +01003007 /* read timeout, last read, or end of client write
3008 * since we are in header mode, if there's no space left for headers, we
3009 * won't be able to free more later, so the session will never terminate.
3010 */
3011 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
3012 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003013 FD_CLR(t->srv_fd, StaticReadEvent);
3014 tv_eternity(&t->srexpire);
3015 shutdown(t->srv_fd, SHUT_RD);
3016 t->srv_state = SV_STSHUTR;
3017 return 1;
3018
3019 }
3020 /* write timeout, or last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003021 /* FIXME!!! here, we don't want to switch to SHUTW if the
3022 * client shuts read too early, because we may still have
3023 * some work to do on the headers.
3024 */
3025 else if (((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) ||
willy tarreau0f7af912005-12-17 12:21:26 +01003026 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
3027 FD_CLR(t->srv_fd, StaticWriteEvent);
3028 tv_eternity(&t->swexpire);
3029 shutdown(t->srv_fd, SHUT_WR);
3030 t->srv_state = SV_STSHUTW;
3031 return 1;
3032 }
3033
3034 if (req->l == 0) {
3035 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3036 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3037 tv_eternity(&t->swexpire);
3038 }
3039 }
3040 else { /* client buffer not empty */
3041 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3042 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3043 if (t->proxy->srvtimeout)
3044 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3045 else
3046 tv_eternity(&t->swexpire);
3047 }
3048 }
3049
willy tarreau5cbea6f2005-12-17 12:48:26 +01003050 /* be nice with the client side which would like to send a complete header
3051 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3052 * would read all remaining data at once ! The client should not write past rep->lr
3053 * when the server is in header state.
3054 */
3055 //return header_processed;
3056 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003057 }
3058 else if (s == SV_STDATA) {
3059 /* read or write error */
3060 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003061 tv_eternity(&t->srexpire);
3062 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003063 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003064 t->srv_state = SV_STCLOSE;
3065 return 1;
3066 }
3067 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01003068 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
3069 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003070 FD_CLR(t->srv_fd, StaticReadEvent);
3071 tv_eternity(&t->srexpire);
3072 shutdown(t->srv_fd, SHUT_RD);
3073 t->srv_state = SV_STSHUTR;
3074 return 1;
3075
3076 }
3077 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01003078 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
3079 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003080 FD_CLR(t->srv_fd, StaticWriteEvent);
3081 tv_eternity(&t->swexpire);
3082 shutdown(t->srv_fd, SHUT_WR);
3083 t->srv_state = SV_STSHUTW;
3084 return 1;
3085 }
3086 else if (req->l == 0) {
3087 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3088 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3089 tv_eternity(&t->swexpire);
3090 }
3091 }
3092 else { /* buffer not empty */
3093 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3094 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3095 if (t->proxy->srvtimeout)
3096 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3097 else
3098 tv_eternity(&t->swexpire);
3099 }
3100 }
3101
3102 if (rep->l == BUFSIZE) { /* no room to read more data */
3103 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3104 FD_CLR(t->srv_fd, StaticReadEvent);
3105 tv_eternity(&t->srexpire);
3106 }
3107 }
3108 else {
3109 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3110 FD_SET(t->srv_fd, StaticReadEvent);
3111 if (t->proxy->srvtimeout)
3112 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3113 else
3114 tv_eternity(&t->srexpire);
3115 }
3116 }
3117
3118 return 0; /* other cases change nothing */
3119 }
3120 else if (s == SV_STSHUTR) {
3121 if ((t->res_sw == RES_ERROR) ||
3122 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
3123 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003124 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003125 tv_eternity(&t->swexpire);
3126 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003128 t->srv_state = SV_STCLOSE;
3129 return 1;
3130 }
3131 else if (req->l == 0) {
3132 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3133 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3134 tv_eternity(&t->swexpire);
3135 }
3136 }
3137 else { /* buffer not empty */
3138 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3139 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3140 if (t->proxy->srvtimeout)
3141 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3142 else
3143 tv_eternity(&t->swexpire);
3144 }
3145 }
3146 return 0;
3147 }
3148 else if (s == SV_STSHUTW) {
3149 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
3150 c == CL_STSHUTW || c == CL_STCLOSE ||
3151 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003152 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003153 tv_eternity(&t->srexpire);
3154 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003155 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003156 t->srv_state = SV_STCLOSE;
3157 return 1;
3158 }
3159 else if (rep->l == BUFSIZE) { /* no room to read more data */
3160 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3161 FD_CLR(t->srv_fd, StaticReadEvent);
3162 tv_eternity(&t->srexpire);
3163 }
3164 }
3165 else {
3166 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3167 FD_SET(t->srv_fd, StaticReadEvent);
3168 if (t->proxy->srvtimeout)
3169 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3170 else
3171 tv_eternity(&t->srexpire);
3172 }
3173 }
3174 return 0;
3175 }
3176 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003177 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003178 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003179 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003180 write(1, trash, len);
3181 }
3182 return 0;
3183 }
3184 return 0;
3185}
3186
3187
willy tarreau5cbea6f2005-12-17 12:48:26 +01003188/* Processes the client and server jobs of a session task, then
3189 * puts it back to the wait queue in a clean state, or
3190 * cleans up its resources if it must be deleted. Returns
3191 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003192 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003193int process_session(struct task *t) {
3194 struct session *s = t->context;
3195 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003196
willy tarreau5cbea6f2005-12-17 12:48:26 +01003197 do {
3198 fsm_resync = 0;
3199 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3200 fsm_resync |= process_cli(s);
3201 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3202 fsm_resync |= process_srv(s);
3203 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3204 } while (fsm_resync);
3205
3206 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003207 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003208 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003209
willy tarreau5cbea6f2005-12-17 12:48:26 +01003210 tv_min(&min1, &s->crexpire, &s->cwexpire);
3211 tv_min(&min2, &s->srexpire, &s->swexpire);
3212 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003213 tv_min(&t->expire, &min1, &min2);
3214
3215 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003216 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003217
willy tarreau5cbea6f2005-12-17 12:48:26 +01003218 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003219 }
3220
willy tarreau5cbea6f2005-12-17 12:48:26 +01003221 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003222 actconn--;
3223
willy tarreau9fe663a2005-12-17 13:02:59 +01003224 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003225 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003226 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003227 write(1, trash, len);
3228 }
3229
willy tarreau750a4722005-12-17 13:21:24 +01003230 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003231 if (s->rep != NULL)
3232 s->logs.bytes = s->rep->total;
3233
willy tarreau9fe663a2005-12-17 13:02:59 +01003234 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003235 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003236 sess_log(s);
3237
willy tarreau0f7af912005-12-17 12:21:26 +01003238 /* the task MUST not be in the run queue anymore */
3239 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003240 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003241 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003242 return -1; /* rest in peace for eternity */
3243}
3244
3245
3246
3247/*
3248 * manages a server health-check. Returns
3249 * the time the task accepts to wait, or -1 for infinity.
3250 */
3251int process_chk(struct task *t) {
3252 struct server *s = t->context;
3253 int fd = s->curfd;
3254 int one = 1;
3255
willy tarreauef900ab2005-12-17 12:52:52 +01003256 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003257
3258 if (fd < 0) { /* no check currently running */
3259 //fprintf(stderr, "process_chk: 2\n");
3260 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3261 task_queue(t); /* restore t to its place in the task list */
3262 return tv_remain(&now, &t->expire);
3263 }
3264
3265 /* we'll initiate a new check */
3266 s->result = 0; /* no result yet */
3267 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003268 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003269 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3270 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3271 //fprintf(stderr, "process_chk: 3\n");
3272
3273 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
3274 /* OK, connection in progress or established */
3275
3276 //fprintf(stderr, "process_chk: 4\n");
3277
3278 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3279 fdtab[fd].owner = t;
3280 fdtab[fd].read = NULL;
3281 fdtab[fd].write = &event_srv_hck;
3282 fdtab[fd].state = FD_STCONN; /* connection in progress */
3283 FD_SET(fd, StaticWriteEvent); /* for connect status */
3284 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003285 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3286 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003287 task_queue(t); /* restore t to its place in the task list */
3288 return tv_remain(&now, &t->expire);
3289 }
3290 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3291 s->result = -1; /* a real error */
3292 }
3293 }
3294 //fprintf(stderr, "process_chk: 5\n");
3295 close(fd);
3296 }
3297
3298 if (!s->result) { /* nothing done */
3299 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003300 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003301 task_queue(t); /* restore t to its place in the task list */
3302 return tv_remain(&now, &t->expire);
3303 }
3304
3305 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003306 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003307 s->health--; /* still good */
3308 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003309 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003310 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003311 Warning("server %s DOWN.\n", s->id);
3312
willy tarreau9fe663a2005-12-17 13:02:59 +01003313 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003314 }
willy tarreauef900ab2005-12-17 12:52:52 +01003315
willy tarreau5cbea6f2005-12-17 12:48:26 +01003316 s->health = 0; /* failure */
3317 s->state &= ~SRV_RUNNING;
3318 }
3319
3320 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003321 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3322 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003323 }
3324 else {
3325 //fprintf(stderr, "process_chk: 8\n");
3326 /* there was a test running */
3327 if (s->result > 0) { /* good server detected */
3328 //fprintf(stderr, "process_chk: 9\n");
3329 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003330 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003331 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003332 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003333 Warning("server %s UP.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003334 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003335 }
willy tarreauef900ab2005-12-17 12:52:52 +01003336
willy tarreaue47c8d72005-12-17 12:55:52 +01003337 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003338 s->state |= SRV_RUNNING;
3339 }
willy tarreauef900ab2005-12-17 12:52:52 +01003340 s->curfd = -1; /* no check running anymore */
3341 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003342 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003343 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344 }
3345 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3346 //fprintf(stderr, "process_chk: 10\n");
3347 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003348 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003349 s->health--; /* still good */
3350 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003351 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003352 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003353 Warning("server %s DOWN.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003354
3355 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003356 }
willy tarreauef900ab2005-12-17 12:52:52 +01003357
willy tarreau5cbea6f2005-12-17 12:48:26 +01003358 s->health = 0; /* failure */
3359 s->state &= ~SRV_RUNNING;
3360 }
3361 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003362 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003363 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003364 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003365 }
3366 /* if result is 0 and there's no timeout, we have to wait again */
3367 }
3368 //fprintf(stderr, "process_chk: 11\n");
3369 s->result = 0;
3370 task_queue(t); /* restore t to its place in the task list */
3371 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003372}
3373
3374
willy tarreau5cbea6f2005-12-17 12:48:26 +01003375
willy tarreau0f7af912005-12-17 12:21:26 +01003376#if STATTIME > 0
3377int stats(void);
3378#endif
3379
3380/*
3381 * Main select() loop.
3382 */
3383
3384void select_loop() {
3385 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003386 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003387 int status;
3388 int fd,i;
3389 struct timeval delta;
3390 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003391 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003392
willy tarreau5cbea6f2005-12-17 12:48:26 +01003393 tv_now(&now);
3394
3395 while (1) {
3396 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003397
willy tarreau5cbea6f2005-12-17 12:48:26 +01003398 /* look for expired tasks and add them to the run queue.
3399 */
3400 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3401 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3402 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003403 if (t->state & TASK_RUNNING)
3404 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003405
3406 /* wakeup expired entries. It doesn't matter if they are
3407 * already running because of a previous event
3408 */
3409 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003410 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003411 task_wakeup(&rq, t);
3412 }
3413 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003414 /* first non-runnable task. Use its expiration date as an upper bound */
3415 int temp_time = tv_remain(&now, &t->expire);
3416 if (temp_time)
3417 next_time = temp_time;
3418 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003419 break;
3420 }
3421 }
3422
3423 /* process each task in the run queue now. Each task may be deleted
3424 * since we only use tnext.
3425 */
3426 tnext = rq;
3427 while ((t = tnext) != NULL) {
3428 int temp_time;
3429
3430 tnext = t->rqnext;
3431 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003432 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003433 temp_time = t->process(t);
3434 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003435 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003436 }
3437
willy tarreauef900ab2005-12-17 12:52:52 +01003438 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003439
3440 /* maintain all proxies in a consistent state. This should quickly become a task */
3441 time2 = maintain_proxies();
3442 next_time = MINTIME(time2, next_time);
3443
3444 /* stop when there's no connection left and we don't allow them anymore */
3445 if (!actconn && listeners == 0)
3446 break;
3447
willy tarreau0f7af912005-12-17 12:21:26 +01003448
3449#if STATTIME > 0
3450 time2 = stats();
3451 // fprintf(stderr," stats = %d\n", time2);
3452 next_time = MINTIME(time2, next_time);
3453#endif
3454
willy tarreau5cbea6f2005-12-17 12:48:26 +01003455 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003456 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003457 /* to avoid eventual select loops due to timer precision */
3458 next_time += SCHEDULER_RESOLUTION;
3459 delta.tv_sec = next_time / 1000;
3460 delta.tv_usec = (next_time % 1000) * 1000;
3461 }
3462 else if (next_time == 0) { /* allow select to return immediately when needed */
3463 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003464 }
3465
3466
3467 /* let's restore fdset state */
3468
3469 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003470 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003471 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3472 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3473 }
3474
3475// /* just a verification code, needs to be removed for performance */
3476// for (i=0; i<maxfd; i++) {
3477// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3478// abort();
3479// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3480// abort();
3481//
3482// }
3483
3484 status=select(maxfd,
3485 readnotnull ? ReadEvent : NULL,
3486 writenotnull ? WriteEvent : NULL,
3487 NULL,
3488 (next_time >= 0) ? &delta : NULL);
3489
willy tarreau5cbea6f2005-12-17 12:48:26 +01003490 /* this is an experiment on the separation of the select work */
3491 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3492 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3493
willy tarreau0f7af912005-12-17 12:21:26 +01003494 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003495
willy tarreau0f7af912005-12-17 12:21:26 +01003496 if (status > 0) { /* must proceed with events */
3497
3498 int fds;
3499 char count;
3500
3501 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3502 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3503 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3504
willy tarreau5cbea6f2005-12-17 12:48:26 +01003505 /* if we specify read first, the accepts and zero reads will be
3506 * seen first. Moreover, system buffers will be flushed faster.
3507 */
willy tarreau0f7af912005-12-17 12:21:26 +01003508 if (fdtab[fd].state == FD_STCLOSE)
3509 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003510
3511 if (FD_ISSET(fd, ReadEvent))
3512 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003513
willy tarreau5cbea6f2005-12-17 12:48:26 +01003514 if (FD_ISSET(fd, WriteEvent))
3515 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003516 }
3517 }
3518 else {
3519 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3520 }
willy tarreau0f7af912005-12-17 12:21:26 +01003521 }
3522}
3523
3524
3525#if STATTIME > 0
3526/*
3527 * Display proxy statistics regularly. It is designed to be called from the
3528 * select_loop().
3529 */
3530int stats(void) {
3531 static int lines;
3532 static struct timeval nextevt;
3533 static struct timeval lastevt;
3534 static struct timeval starttime = {0,0};
3535 unsigned long totaltime, deltatime;
3536 int ret;
3537
willy tarreau750a4722005-12-17 13:21:24 +01003538 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01003539 deltatime = (tv_diff(&lastevt, &now)?:1);
3540 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01003541
willy tarreau9fe663a2005-12-17 13:02:59 +01003542 if (global.mode & MODE_STATS) {
3543 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003544 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003545 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3546 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003547 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003548 actconn, totalconn,
3549 stats_tsk_new, stats_tsk_good,
3550 stats_tsk_left, stats_tsk_right,
3551 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3552 }
3553 }
3554
3555 tv_delayfrom(&nextevt, &now, STATTIME);
3556
3557 lastevt=now;
3558 }
3559 ret = tv_remain(&now, &nextevt);
3560 return ret;
3561}
3562#endif
3563
3564
3565/*
3566 * this function enables proxies when there are enough free sessions,
3567 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003568 * select_loop(). It returns the time left before next expiration event
3569 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003570 */
3571static int maintain_proxies(void) {
3572 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003573 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003574
3575 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003576 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003577
3578 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003579 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003580 while (p) {
3581 if (p->nbconn < p->maxconn) {
3582 if (p->state == PR_STIDLE) {
3583 FD_SET(p->listen_fd, StaticReadEvent);
3584 p->state = PR_STRUN;
3585 }
3586 }
3587 else {
3588 if (p->state == PR_STRUN) {
3589 FD_CLR(p->listen_fd, StaticReadEvent);
3590 p->state = PR_STIDLE;
3591 }
3592 }
3593 p = p->next;
3594 }
3595 }
3596 else { /* block all proxies */
3597 while (p) {
3598 if (p->state == PR_STRUN) {
3599 FD_CLR(p->listen_fd, StaticReadEvent);
3600 p->state = PR_STIDLE;
3601 }
3602 p = p->next;
3603 }
3604 }
3605
willy tarreau5cbea6f2005-12-17 12:48:26 +01003606 if (stopping) {
3607 p = proxy;
3608 while (p) {
3609 if (p->state != PR_STDISABLED) {
3610 int t;
3611 t = tv_remain(&now, &p->stop_time);
3612 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003613 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003614 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003615
willy tarreau5cbea6f2005-12-17 12:48:26 +01003616 fd_delete(p->listen_fd);
3617 p->state = PR_STDISABLED;
3618 listeners--;
3619 }
3620 else {
3621 tleft = MINTIME(t, tleft);
3622 }
3623 }
3624 p = p->next;
3625 }
3626 }
3627 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003628}
3629
3630/*
3631 * this function disables health-check servers so that the process will quickly be ignored
3632 * by load balancers.
3633 */
3634static void soft_stop(void) {
3635 struct proxy *p;
3636
3637 stopping = 1;
3638 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003639 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003640 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003641 if (p->state != PR_STDISABLED) {
3642 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01003643 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01003644 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01003645 }
willy tarreau0f7af912005-12-17 12:21:26 +01003646 p = p->next;
3647 }
3648}
3649
3650/*
3651 * upon SIGUSR1, let's have a soft stop.
3652 */
3653void sig_soft_stop(int sig) {
3654 soft_stop();
3655 signal(sig, SIG_IGN);
3656}
3657
3658
3659void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003660 struct task *t, *tnext;
3661 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003662
willy tarreau5cbea6f2005-12-17 12:48:26 +01003663 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3664 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3665 tnext = t->next;
3666 s = t->context;
3667 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3668 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3669 "req=%d, rep=%d, clifd=%d\n",
3670 s, tv_remain(&now, &t->expire),
3671 s->cli_state,
3672 s->srv_state,
3673 FD_ISSET(s->cli_fd, StaticReadEvent),
3674 FD_ISSET(s->cli_fd, StaticWriteEvent),
3675 FD_ISSET(s->srv_fd, StaticReadEvent),
3676 FD_ISSET(s->srv_fd, StaticWriteEvent),
3677 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3678 );
willy tarreau0f7af912005-12-17 12:21:26 +01003679 }
3680}
3681
willy tarreaue39cd132005-12-17 13:00:18 +01003682void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
3683 struct hdr_exp *exp;
3684
3685 while (*head != NULL)
3686 head = &(*head)->next;
3687
3688 exp = calloc(1, sizeof(struct hdr_exp));
3689
3690 exp->preg = preg;
3691 exp->replace = replace;
3692 exp->action = action;
3693 *head = exp;
3694}
3695
willy tarreau9fe663a2005-12-17 13:02:59 +01003696
willy tarreau0f7af912005-12-17 12:21:26 +01003697/*
willy tarreau9fe663a2005-12-17 13:02:59 +01003698 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01003699 */
willy tarreau9fe663a2005-12-17 13:02:59 +01003700int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01003701
willy tarreau9fe663a2005-12-17 13:02:59 +01003702 if (!strcmp(args[0], "global")) { /* new section */
3703 /* no option, nothing special to do */
3704 return 0;
3705 }
3706 else if (!strcmp(args[0], "daemon")) {
3707 global.mode |= MODE_DAEMON;
3708 }
3709 else if (!strcmp(args[0], "debug")) {
3710 global.mode |= MODE_DEBUG;
3711 }
3712 else if (!strcmp(args[0], "quiet")) {
3713 global.mode |= MODE_QUIET;
3714 }
3715 else if (!strcmp(args[0], "stats")) {
3716 global.mode |= MODE_STATS;
3717 }
3718 else if (!strcmp(args[0], "uid")) {
3719 if (global.uid != 0) {
3720 Alert("parsing [%s:%d] : <uid> already specified. Continuing.\n", file, linenum);
3721 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003722 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003723 if (*(args[1]) == 0) {
3724 Alert("parsing [%s:%d] : <uid> expects an integer argument.\n", file, linenum);
3725 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003726 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003727 global.uid = atol(args[1]);
3728 }
3729 else if (!strcmp(args[0], "gid")) {
3730 if (global.gid != 0) {
3731 Alert("parsing [%s:%d] : <gid> already specified. Continuing.\n", file, linenum);
3732 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003733 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003734 if (*(args[1]) == 0) {
3735 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003736 return -1;
3737 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003738 global.gid = atol(args[1]);
3739 }
3740 else if (!strcmp(args[0], "nbproc")) {
3741 if (global.nbproc != 0) {
3742 Alert("parsing [%s:%d] : <nbproc> already specified. Continuing.\n", file, linenum);
3743 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003744 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003745 if (*(args[1]) == 0) {
3746 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
3747 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003748 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003749 global.nbproc = atol(args[1]);
3750 }
3751 else if (!strcmp(args[0], "maxconn")) {
3752 if (global.maxconn != 0) {
3753 Alert("parsing [%s:%d] : <maxconn> already specified. Continuing.\n", file, linenum);
3754 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003755 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003756 if (*(args[1]) == 0) {
3757 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3758 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003759 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003760 global.maxconn = atol(args[1]);
3761 }
3762 else if (!strcmp(args[0], "chroot")) {
3763 if (global.chroot != NULL) {
3764 Alert("parsing [%s:%d] : <chroot> already specified. Continuing.\n", file, linenum);
3765 return 0;
3766 }
3767 if (*(args[1]) == 0) {
3768 Alert("parsing [%s:%d] : <chroot> expects a directory as an argument.\n", file, linenum);
3769 return -1;
3770 }
3771 global.chroot = strdup(args[1]);
3772 }
3773 else if (!strcmp(args[0], "log")) { /* syslog server address */
3774 struct sockaddr_in *sa;
3775 int facility;
3776
3777 if (*(args[1]) == 0 || *(args[2]) == 0) {
3778 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n", file, linenum);
3779 return -1;
3780 }
3781
3782 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3783 if (!strcmp(log_facilities[facility], args[2]))
3784 break;
3785
3786 if (facility >= NB_LOG_FACILITIES) {
3787 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3788 exit(1);
3789 }
3790
3791 sa = str2sa(args[1]);
3792 if (!sa->sin_port)
3793 sa->sin_port = htons(SYSLOG_PORT);
3794
3795 if (global.logfac1 == -1) {
3796 global.logsrv1 = *sa;
3797 global.logfac1 = facility;
3798 }
3799 else if (global.logfac2 == -1) {
3800 global.logsrv2 = *sa;
3801 global.logfac2 = facility;
3802 }
3803 else {
3804 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3805 return -1;
3806 }
3807
3808 }
3809 else {
3810 Alert("parsing [%s:%d] : unknown keyword <%s> in <global> section\n", file, linenum, args[0]);
3811 return -1;
3812 }
3813 return 0;
3814}
3815
3816
3817/*
3818 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
3819 */
3820int cfg_parse_listen(char *file, int linenum, char **args) {
3821 static struct proxy *curproxy = NULL;
3822 struct server *newsrv = NULL;
3823
3824 if (!strcmp(args[0], "listen")) { /* new proxy */
3825 if (strchr(args[2], ':') == NULL) {
3826 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3827 file, linenum);
3828 return -1;
3829 }
3830
3831 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
3832 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3833 return -1;
3834 }
3835 curproxy->next = proxy;
3836 proxy = curproxy;
3837 curproxy->id = strdup(args[1]);
3838 curproxy->listen_addr = *str2sa(args[2]);
3839 curproxy->state = PR_STNEW;
3840 /* set default values */
3841 curproxy->maxconn = cfg_maxpconn;
3842 curproxy->conn_retries = CONN_RETRIES;
3843 curproxy->options = 0;
3844 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3845 curproxy->mode = PR_MODE_TCP;
3846 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3847 curproxy->to_log = 0;
3848 return 0;
3849 }
3850 else if (curproxy == NULL) {
3851 Alert("parsing [%s:%d] : <listen> expected.\n", file, linenum);
3852 return -1;
3853 }
3854
3855 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3856 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3857 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3858 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3859 else {
3860 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3861 return -1;
3862 }
3863 }
3864 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3865 curproxy->state = PR_STDISABLED;
3866 }
3867 else if (!strcmp(args[0], "cookie")) { /* cookie name */
3868 int cur_arg;
3869 if (curproxy->cookie_name != NULL) {
3870 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3871 file, linenum);
3872 return 0;
3873 }
3874
3875 if (*(args[1]) == 0) {
3876 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3877 file, linenum);
3878 return -1;
3879 }
3880 curproxy->cookie_name = strdup(args[1]);
3881
3882 cur_arg = 2;
3883 while (*(args[cur_arg])) {
3884 if (!strcmp(args[cur_arg], "rewrite")) {
3885 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01003886 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003887 else if (!strcmp(args[cur_arg], "indirect")) {
3888 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01003889 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003890 else if (!strcmp(args[cur_arg], "insert")) {
3891 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01003892 }
willy tarreau240afa62005-12-17 13:14:35 +01003893 else if (!strcmp(args[cur_arg], "nocache")) {
3894 curproxy->options |= PR_O_COOK_NOC;
3895 }
willy tarreaucd878942005-12-17 13:27:43 +01003896 else if (!strcmp(args[cur_arg], "postonly")) {
3897 curproxy->options |= PR_O_COOK_POST;
3898 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003899 else {
willy tarreaucd878942005-12-17 13:27:43 +01003900 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003901 file, linenum);
3902 return -1;
3903 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003904 cur_arg++;
3905 }
3906 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3907 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3908 file, linenum);
3909 return -1;
3910 }
3911 }
3912 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3913 if (curproxy->contimeout != 0) {
3914 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n", file, linenum);
3915 return 0;
3916 }
3917 if (*(args[1]) == 0) {
3918 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3919 file, linenum);
3920 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003921 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003922 curproxy->contimeout = atol(args[1]);
3923 }
3924 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3925 if (curproxy->clitimeout != 0) {
3926 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3927 file, linenum);
3928 return 0;
3929 }
3930 if (*(args[1]) == 0) {
3931 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3932 file, linenum);
3933 return -1;
3934 }
3935 curproxy->clitimeout = atol(args[1]);
3936 }
3937 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3938 if (curproxy->srvtimeout != 0) {
3939 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n", file, linenum);
3940 return 0;
3941 }
3942 if (*(args[1]) == 0) {
3943 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003944 file, linenum);
3945 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003946 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003947 curproxy->srvtimeout = atol(args[1]);
3948 }
3949 else if (!strcmp(args[0], "retries")) { /* connection retries */
3950 if (*(args[1]) == 0) {
3951 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3952 file, linenum);
3953 return -1;
3954 }
3955 curproxy->conn_retries = atol(args[1]);
3956 }
3957 else if (!strcmp(args[0], "option")) {
3958 if (*(args[1]) == 0) {
3959 Alert("parsing [%s:%d] : <option> expects an option name.\n", file, linenum);
3960 return -1;
3961 }
3962 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003963 /* enable reconnections to dispatch */
3964 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01003965#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003966 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003967 /* enable transparent proxy connections */
3968 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01003969#endif
3970 else if (!strcmp(args[1], "keepalive"))
3971 /* enable keep-alive */
3972 curproxy->options |= PR_O_KEEPALIVE;
3973 else if (!strcmp(args[1], "forwardfor"))
3974 /* insert x-forwarded-for field */
3975 curproxy->options |= PR_O_FWDFOR;
3976 else if (!strcmp(args[1], "httplog")) {
3977 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01003978 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
3979 }
3980 else if (!strcmp(args[1], "dontlognull")) {
3981 /* don't log empty requests */
3982 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003983 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003984 else {
3985 Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
3986 return -1;
3987 }
3988 return 0;
3989 }
3990 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3991 /* enable reconnections to dispatch */
3992 curproxy->options |= PR_O_REDISP;
3993 }
willy tarreaua1598082005-12-17 13:08:06 +01003994#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003995 else if (!strcmp(args[0], "transparent")) {
3996 /* enable transparent proxy connections */
3997 curproxy->options |= PR_O_TRANSP;
3998 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003999#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004000 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4001 if (*(args[1]) == 0) {
4002 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
4003 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004004 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004005 curproxy->maxconn = atol(args[1]);
4006 }
4007 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4008 if (*(args[1]) == 0) {
4009 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n", file, linenum);
4010 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004011 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004012 curproxy->grace = atol(args[1]);
4013 }
4014 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
4015 if (strchr(args[1], ':') == NULL) {
4016 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n", file, linenum);
4017 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004018 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004019 curproxy->dispatch_addr = *str2sa(args[1]);
4020 }
4021 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
4022 if (*(args[1])) {
4023 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004024 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004025 }
4026 else {
4027 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n", file, linenum);
4028 return -1;
4029 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004030 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004031 else /* if no option is set, use round-robin by default */
4032 curproxy->options |= PR_O_BALANCE_RR;
4033 }
4034 else if (!strcmp(args[0], "server")) { /* server address */
4035 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004036
willy tarreau9fe663a2005-12-17 13:02:59 +01004037 if (strchr(args[2], ':') == NULL) {
4038 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
4039 file, linenum);
4040 return -1;
4041 }
4042 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4043 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4044 return -1;
4045 }
4046 newsrv->next = curproxy->srv;
4047 curproxy->srv = newsrv;
4048 newsrv->proxy = curproxy;
4049 newsrv->id = strdup(args[1]);
4050 newsrv->addr = *str2sa(args[2]);
4051 newsrv->state = SRV_RUNNING; /* early server setup */
4052 newsrv->curfd = -1; /* no health-check in progress */
4053 newsrv->inter = DEF_CHKINTR;
4054 newsrv->rise = DEF_RISETIME;
4055 newsrv->fall = DEF_FALLTIME;
4056 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4057 cur_arg = 3;
4058 while (*args[cur_arg]) {
4059 if (!strcmp(args[cur_arg], "cookie")) {
4060 newsrv->cookie = strdup(args[cur_arg + 1]);
4061 newsrv->cklen = strlen(args[cur_arg + 1]);
4062 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004063 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004064 else if (!strcmp(args[cur_arg], "rise")) {
4065 newsrv->rise = atol(args[cur_arg + 1]);
4066 newsrv->health = newsrv->rise;
4067 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004068 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004069 else if (!strcmp(args[cur_arg], "fall")) {
4070 newsrv->fall = atol(args[cur_arg + 1]);
4071 cur_arg += 2;
4072 }
4073 else if (!strcmp(args[cur_arg], "inter")) {
4074 newsrv->inter = atol(args[cur_arg + 1]);
4075 cur_arg += 2;
4076 }
4077 else if (!strcmp(args[cur_arg], "check")) {
4078 struct task *t;
4079
4080 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
4081 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004082 return -1;
4083 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004084
4085 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4086 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4087 t->state = TASK_IDLE;
4088 t->process = process_chk;
4089 t->context = newsrv;
4090
4091 if (curproxy->state != PR_STDISABLED) {
4092 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4093 task_queue(t);
4094 task_wakeup(&rq, t);
4095 }
4096
4097 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004098 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004099 else {
4100 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
4101 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004102 return -1;
4103 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004104 }
4105 curproxy->nbservers++;
4106 }
4107 else if (!strcmp(args[0], "log")) { /* syslog server address */
4108 struct sockaddr_in *sa;
4109 int facility;
4110
4111 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4112 curproxy->logfac1 = global.logfac1;
4113 curproxy->logsrv1 = global.logsrv1;
4114 curproxy->logfac2 = global.logfac2;
4115 curproxy->logsrv2 = global.logsrv2;
4116 }
4117 else if (*(args[1]) && *(args[2])) {
willy tarreau0f7af912005-12-17 12:21:26 +01004118 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4119 if (!strcmp(log_facilities[facility], args[2]))
4120 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004121
willy tarreau0f7af912005-12-17 12:21:26 +01004122 if (facility >= NB_LOG_FACILITIES) {
4123 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
4124 exit(1);
4125 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004126
willy tarreau0f7af912005-12-17 12:21:26 +01004127 sa = str2sa(args[1]);
4128 if (!sa->sin_port)
4129 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004130
willy tarreau0f7af912005-12-17 12:21:26 +01004131 if (curproxy->logfac1 == -1) {
4132 curproxy->logsrv1 = *sa;
4133 curproxy->logfac1 = facility;
4134 }
4135 else if (curproxy->logfac2 == -1) {
4136 curproxy->logsrv2 = *sa;
4137 curproxy->logfac2 = facility;
4138 }
4139 else {
4140 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004141 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004142 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004143 }
4144 else {
4145 Alert("parsing [%s:%d] : <log> expects either <address[:port]> and <facility> or 'global' as arguments.\n",
4146 file, linenum);
4147 return -1;
4148 }
4149 }
willy tarreaua1598082005-12-17 13:08:06 +01004150 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
4151 if (strchr(args[1], ':') == NULL) {
4152 Alert("parsing [%s:%d] : <source> expects <addr:port> as argument.\n",
4153 file, linenum);
4154 return -1;
4155 }
4156
4157 curproxy->source_addr = *str2sa(args[1]);
4158 curproxy->options |= PR_O_BIND_SRC;
4159 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004160 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4161 regex_t *preg;
4162
4163 if (*(args[1]) == 0 || *(args[2]) == 0) {
4164 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
4165 file, linenum);
4166 return -1;
4167 }
4168
4169 preg = calloc(1, sizeof(regex_t));
4170 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4171 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4172 return -1;
4173 }
4174
4175 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4176 }
4177 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4178 regex_t *preg;
4179
4180 if (*(args[1]) == 0) {
4181 Alert("parsing [%s:%d] : <reqdel> expects <regex> as an argument.\n", file, linenum);
4182 return -1;
4183 }
4184
4185 preg = calloc(1, sizeof(regex_t));
4186 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4187 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4188 return -1;
4189 }
4190
4191 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4192 }
4193 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
4194 regex_t *preg;
4195
4196 if (*(args[1]) == 0) {
4197 Alert("parsing [%s:%d] : <reqdeny> expects <regex> as an argument.\n", file, linenum);
4198 return -1;
4199 }
4200
4201 preg = calloc(1, sizeof(regex_t));
4202 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4203 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4204 return -1;
4205 }
4206
4207 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4208 }
4209 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4210 regex_t *preg;
4211
4212 if (*(args[1]) == 0) {
4213 Alert("parsing [%s:%d] : <reqallow> expects <regex> as an argument.\n", file, linenum);
4214 return -1;
4215 }
4216
4217 preg = calloc(1, sizeof(regex_t));
4218 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4219 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4220 return -1;
4221 }
4222
4223 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4224 }
4225 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4226 regex_t *preg;
4227
4228 if (*(args[1]) == 0 || *(args[2]) == 0) {
4229 Alert("parsing [%s:%d] : <reqirep> expects <search> and <replace> as arguments.\n",
4230 file, linenum);
4231 return -1;
4232 }
4233
4234 preg = calloc(1, sizeof(regex_t));
4235 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4236 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4237 return -1;
4238 }
4239
4240 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4241 }
4242 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4243 regex_t *preg;
4244
4245 if (*(args[1]) == 0) {
4246 Alert("parsing [%s:%d] : <reqidel> expects <regex> as an argument.\n", file, linenum);
4247 return -1;
4248 }
4249
4250 preg = calloc(1, sizeof(regex_t));
4251 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4252 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4253 return -1;
4254 }
4255
4256 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4257 }
4258 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4259 regex_t *preg;
4260
4261 if (*(args[1]) == 0) {
4262 Alert("parsing [%s:%d] : <reqideny> expects <regex> as an argument.\n", file, linenum);
4263 return -1;
4264 }
4265
4266 preg = calloc(1, sizeof(regex_t));
4267 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4268 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4269 return -1;
4270 }
4271
4272 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4273 }
4274 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4275 regex_t *preg;
4276
4277 if (*(args[1]) == 0) {
4278 Alert("parsing [%s:%d] : <reqiallow> expects <regex> as an argument.\n", file, linenum);
4279 return -1;
4280 }
4281
4282 preg = calloc(1, sizeof(regex_t));
4283 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4284 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4285 return -1;
4286 }
4287
4288 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4289 }
4290 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4291 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
4292 Alert("parsing [%s:%d] : too many `reqadd'. Continuing.\n", file, linenum);
4293 return 0;
4294 }
4295
4296 if (*(args[1]) == 0) {
4297 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n", file, linenum);
4298 return -1;
4299 }
4300
4301 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004302 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004303 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004304 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004305
4306 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004307 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004308 file, linenum);
4309 return -1;
4310 }
4311
4312 preg = calloc(1, sizeof(regex_t));
4313 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4314 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4315 return -1;
4316 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004317
4318 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4319 }
4320 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4321 regex_t *preg;
4322
4323 if (*(args[1]) == 0) {
4324 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n", file, linenum);
4325 return -1;
4326 }
willy tarreaue39cd132005-12-17 13:00:18 +01004327
willy tarreau9fe663a2005-12-17 13:02:59 +01004328 preg = calloc(1, sizeof(regex_t));
4329 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4330 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4331 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004332 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004333
4334 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4335 }
4336 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004337 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004338
willy tarreau9fe663a2005-12-17 13:02:59 +01004339 if (*(args[1]) == 0 || *(args[2]) == 0) {
4340 Alert("parsing [%s:%d] : <rspirep> expects <search> and <replace> as arguments.\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01004341 file, linenum);
willy tarreaue39cd132005-12-17 13:00:18 +01004342 return -1;
4343 }
4344
4345 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004346 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreaue39cd132005-12-17 13:00:18 +01004347 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4348 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004349 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004350
4351 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4352 }
4353 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4354 regex_t *preg;
4355
4356 if (*(args[1]) == 0) {
4357 Alert("parsing [%s:%d] : <rspidel> expects <search> as an argument.\n", file, linenum);
4358 return -1;
4359 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004360
willy tarreau9fe663a2005-12-17 13:02:59 +01004361 preg = calloc(1, sizeof(regex_t));
4362 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4363 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4364 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004365 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004366
4367 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4368 }
4369 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4370 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
4371 Alert("parsing [%s:%d] : too many `rspadd'. Continuing.\n", file, linenum);
4372 return 0;
4373 }
4374
4375 if (*(args[1]) == 0) {
4376 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n", file, linenum);
4377 return -1;
4378 }
4379
4380 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4381 }
4382 else {
4383 Alert("parsing [%s:%d] : unknown keyword <%s> in <listen> section\n", file, linenum, args[0]);
4384 return -1;
4385 }
4386 return 0;
4387}
willy tarreaue39cd132005-12-17 13:00:18 +01004388
willy tarreau5cbea6f2005-12-17 12:48:26 +01004389
willy tarreau9fe663a2005-12-17 13:02:59 +01004390/*
4391 * This function reads and parses the configuration file given in the argument.
4392 * returns 0 if OK, -1 if error.
4393 */
4394int readcfgfile(char *file) {
4395 char thisline[256];
4396 char *line;
4397 FILE *f;
4398 int linenum = 0;
4399 char *end;
4400 char *args[MAX_LINE_ARGS];
4401 int arg;
4402 int cfgerr = 0;
4403 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01004404
willy tarreau9fe663a2005-12-17 13:02:59 +01004405 struct proxy *curproxy = NULL;
4406 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01004407
willy tarreau9fe663a2005-12-17 13:02:59 +01004408 if ((f=fopen(file,"r")) == NULL)
4409 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004410
willy tarreau9fe663a2005-12-17 13:02:59 +01004411 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
4412 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004413
willy tarreau9fe663a2005-12-17 13:02:59 +01004414 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004415
willy tarreau9fe663a2005-12-17 13:02:59 +01004416 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01004417 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01004418 line++;
4419
4420 arg = 0;
4421 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01004422
willy tarreau9fe663a2005-12-17 13:02:59 +01004423 while (*line && arg < MAX_LINE_ARGS) {
4424 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
4425 * C equivalent value. Other combinations left unchanged (eg: \1).
4426 */
4427 if (*line == '\\') {
4428 int skip = 0;
4429 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
4430 *line = line[1];
4431 skip = 1;
4432 }
4433 else if (line[1] == 'r') {
4434 *line = '\r';
4435 skip = 1;
4436 }
4437 else if (line[1] == 'n') {
4438 *line = '\n';
4439 skip = 1;
4440 }
4441 else if (line[1] == 't') {
4442 *line = '\t';
4443 skip = 1;
4444 }
4445 else if (line[1] == 'x' && (line + 3 < end )) {
4446 unsigned char hex1, hex2;
4447 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
4448 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4449 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4450 *line = (hex1<<4) + hex2;
4451 skip = 3;
4452 }
4453 if (skip) {
4454 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
4455 end -= skip;
4456 }
4457 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004458 }
willy tarreaua1598082005-12-17 13:08:06 +01004459 else if (*line == '#' || *line == '\n' || *line == '\r') {
4460 /* end of string, end of loop */
4461 *line = 0;
4462 break;
4463 }
willy tarreauc29948c2005-12-17 13:10:27 +01004464 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004465 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01004466 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01004467 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01004468 line++;
4469 args[++arg] = line;
4470 }
4471 else {
4472 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004473 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004474 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004475
willy tarreau9fe663a2005-12-17 13:02:59 +01004476 /* empty line */
4477 if (!**args)
4478 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01004479
willy tarreau9fe663a2005-12-17 13:02:59 +01004480 /* zero out remaining args */
4481 while (++arg < MAX_LINE_ARGS) {
4482 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004483 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004484
willy tarreau9fe663a2005-12-17 13:02:59 +01004485 if (!strcmp(args[0], "listen")) /* new proxy */
4486 confsect = CFG_LISTEN;
4487 else if (!strcmp(args[0], "global")) /* global config */
4488 confsect = CFG_GLOBAL;
4489 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004490
willy tarreau9fe663a2005-12-17 13:02:59 +01004491 switch (confsect) {
4492 case CFG_LISTEN:
4493 if (cfg_parse_listen(file, linenum, args) < 0)
4494 return -1;
4495 break;
4496 case CFG_GLOBAL:
4497 if (cfg_parse_global(file, linenum, args) < 0)
4498 return -1;
4499 break;
4500 default:
4501 Alert("parsing [%s:%d] : unknown keyword <%s> out of section.\n", file, linenum, args[0]);
4502 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004503 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004504
4505
willy tarreau0f7af912005-12-17 12:21:26 +01004506 }
4507 fclose(f);
4508
4509 /*
4510 * Now, check for the integrity of all that we have collected.
4511 */
4512
4513 if ((curproxy = proxy) == NULL) {
4514 Alert("parsing %s : no <listen> line. Nothing to do !\n",
4515 file);
4516 return -1;
4517 }
4518
4519 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01004520 if (curproxy->state == PR_STDISABLED) {
4521 curproxy = curproxy->next;
4522 continue;
4523 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004524 if ((curproxy->mode != PR_MODE_HEALTH) &&
4525 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01004526 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004527 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
4528 file, curproxy->id);
4529 cfgerr++;
4530 }
4531 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
4532 if (curproxy->options & PR_O_TRANSP) {
4533 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
4534 file, curproxy->id);
4535 cfgerr++;
4536 }
4537 else if (curproxy->srv == NULL) {
4538 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
4539 file, curproxy->id);
4540 cfgerr++;
4541 }
willy tarreaua1598082005-12-17 13:08:06 +01004542 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004543 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
4544 file, curproxy->id);
4545 }
4546 }
4547 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01004548 if (curproxy->cookie_name != NULL) {
4549 Warning("parsing %s : cookie will be ignored for listener %s.\n",
4550 file, curproxy->id);
4551 }
4552 if ((newsrv = curproxy->srv) != NULL) {
4553 Warning("parsing %s : servers will be ignored for listener %s.\n",
4554 file, curproxy->id);
4555 }
willy tarreaue39cd132005-12-17 13:00:18 +01004556 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004557 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
4558 file, curproxy->id);
4559 }
willy tarreaue39cd132005-12-17 13:00:18 +01004560 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004561 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
4562 file, curproxy->id);
4563 }
4564 }
4565 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
4566 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
4567 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
4568 file, curproxy->id);
4569 cfgerr++;
4570 }
4571 else {
4572 while (newsrv != NULL) {
4573 /* nothing to check for now */
4574 newsrv = newsrv->next;
4575 }
4576 }
4577 }
4578 curproxy = curproxy->next;
4579 }
4580 if (cfgerr > 0) {
4581 Alert("Errors found in configuration file, aborting.\n");
4582 return -1;
4583 }
4584 else
4585 return 0;
4586}
4587
4588
4589/*
4590 * This function initializes all the necessary variables. It only returns
4591 * if everything is OK. If something fails, it exits.
4592 */
4593void init(int argc, char **argv) {
4594 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01004595 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004596 char *old_argv = *argv;
4597 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01004598 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01004599
4600 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004601 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004602 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
4603 sizeof(int)*8);
4604 exit(1);
4605 }
4606
4607 pid = getpid();
4608 progname = *argv;
4609 while ((tmp = strchr(progname, '/')) != NULL)
4610 progname = tmp + 1;
4611
4612 argc--; argv++;
4613 while (argc > 0) {
4614 char *flag;
4615
4616 if (**argv == '-') {
4617 flag = *argv+1;
4618
4619 /* 1 arg */
4620 if (*flag == 'v') {
4621 display_version();
4622 exit(0);
4623 }
4624 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01004625 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01004626 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01004627 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004628 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01004629 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01004630#if STATTIME > 0
4631 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01004632 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01004633 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01004634 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01004635#endif
4636 else { /* >=2 args */
4637 argv++; argc--;
4638 if (argc == 0)
4639 usage(old_argv);
4640
4641 switch (*flag) {
4642 case 'n' : cfg_maxconn = atol(*argv); break;
4643 case 'N' : cfg_maxpconn = atol(*argv); break;
4644 case 'f' : cfg_cfgfile = *argv; break;
4645 default: usage(old_argv);
4646 }
4647 }
4648 }
4649 else
4650 usage(old_argv);
4651 argv++; argc--;
4652 }
4653
willy tarreau0f7af912005-12-17 12:21:26 +01004654 if (!cfg_cfgfile)
4655 usage(old_argv);
4656
4657 gethostname(hostname, MAX_HOSTNAME_LEN);
4658
4659 if (readcfgfile(cfg_cfgfile) < 0) {
4660 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
4661 exit(1);
4662 }
4663
willy tarreau9fe663a2005-12-17 13:02:59 +01004664 if (cfg_maxconn > 0)
4665 global.maxconn = cfg_maxconn;
4666
4667 if (global.maxconn == 0)
4668 global.maxconn = DEFAULT_MAXCONN;
4669
4670 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
4671
4672 if (arg_mode & MODE_DEBUG) {
4673 /* command line debug mode inhibits configuration mode */
4674 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4675 }
willy tarreau750a4722005-12-17 13:21:24 +01004676 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01004677
4678 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
4679 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
4680 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4681 }
4682
4683 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
4684 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
4685 global.nbproc = 1;
4686 }
4687
4688 if (global.nbproc < 1)
4689 global.nbproc = 1;
4690
willy tarreau0f7af912005-12-17 12:21:26 +01004691 ReadEvent = (fd_set *)calloc(1,
4692 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004693 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004694 WriteEvent = (fd_set *)calloc(1,
4695 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004696 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004697 StaticReadEvent = (fd_set *)calloc(1,
4698 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004699 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004700 StaticWriteEvent = (fd_set *)calloc(1,
4701 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004702 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004703
4704 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01004705 sizeof(struct fdtab) * (global.maxsock));
4706 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004707 fdtab[i].state = FD_STCLOSE;
4708 }
4709}
4710
4711/*
4712 * this function starts all the proxies. It returns 0 if OK, -1 if not.
4713 */
4714int start_proxies() {
4715 struct proxy *curproxy;
4716 int one = 1;
4717 int fd;
4718
4719 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
4720
4721 if (curproxy->state == PR_STDISABLED)
4722 continue;
4723
4724 if ((fd = curproxy->listen_fd =
4725 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
4726 Alert("cannot create listening socket for proxy %s. Aborting.\n",
4727 curproxy->id);
4728 return -1;
4729 }
4730
willy tarreau9fe663a2005-12-17 13:02:59 +01004731 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004732 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
4733 curproxy->id);
4734 close(fd);
4735 return -1;
4736 }
4737
willy tarreau0f7af912005-12-17 12:21:26 +01004738 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
4739 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
4740 (char *) &one, sizeof(one)) == -1)) {
4741 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
4742 curproxy->id);
4743 close(fd);
4744 return -1;
4745 }
4746
4747 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
4748 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
4749 curproxy->id);
4750 }
4751
4752 if (bind(fd,
4753 (struct sockaddr *)&curproxy->listen_addr,
4754 sizeof(curproxy->listen_addr)) == -1) {
4755 Alert("cannot bind socket for proxy %s. Aborting.\n",
4756 curproxy->id);
4757 close(fd);
4758 return -1;
4759 }
4760
4761 if (listen(fd, curproxy->maxconn) == -1) {
4762 Alert("cannot listen to socket for proxy %s. Aborting.\n",
4763 curproxy->id);
4764 close(fd);
4765 return -1;
4766 }
4767
4768 /* the function for the accept() event */
4769 fdtab[fd].read = &event_accept;
4770 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004771 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01004772 curproxy->state = PR_STRUN;
4773 fdtab[fd].state = FD_STLISTEN;
4774 FD_SET(fd, StaticReadEvent);
4775 fd_insert(fd);
4776 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01004777
willy tarreaua1598082005-12-17 13:08:06 +01004778 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004779
willy tarreau0f7af912005-12-17 12:21:26 +01004780 }
4781 return 0;
4782}
4783
4784
4785int main(int argc, char **argv) {
4786 init(argc, argv);
4787
willy tarreau9fe663a2005-12-17 13:02:59 +01004788 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01004789 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004790 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01004791 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01004792 }
4793
4794 signal(SIGQUIT, dump);
4795 signal(SIGUSR1, sig_soft_stop);
4796
4797 /* on very high loads, a sigpipe sometimes happen just between the
4798 * getsockopt() which tells "it's OK to write", and the following write :-(
4799 */
willy tarreau3242e862005-12-17 12:27:53 +01004800#ifndef MSG_NOSIGNAL
4801 signal(SIGPIPE, SIG_IGN);
4802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004803
4804 if (start_proxies() < 0)
4805 exit(1);
4806
willy tarreau9fe663a2005-12-17 13:02:59 +01004807 /* open log files */
4808
4809 /* chroot if needed */
4810 if (global.chroot != NULL) {
4811 if (chroot(global.chroot) == -1) {
4812 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
4813 exit(1);
4814 }
4815 chdir("/");
4816 }
4817
4818 /* setgid / setuid */
4819 if (global.gid && setregid(global.gid, global.gid) == -1) {
4820 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
4821 exit(1);
4822 }
4823
4824 if (global.uid && setreuid(global.uid, global.uid) == -1) {
4825 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
4826 exit(1);
4827 }
4828
4829 if (global.mode & MODE_DAEMON) {
4830 int ret = 0;
4831 int proc;
4832
4833 /* the father launches the required number of processes */
4834 for (proc = 0; proc < global.nbproc; proc++) {
4835 ret = fork();
4836 if (ret < 0) {
4837 Alert("[%s.main()] Cannot fork.\n", argv[0]);
4838 exit(1); /* there has been an error */
4839 }
4840 else if (ret == 0) /* child breaks here */
4841 break;
4842 }
4843 if (proc == global.nbproc)
4844 exit(0); /* parent must leave */
4845
willy tarreau750a4722005-12-17 13:21:24 +01004846 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
4847 * that we can detach from the TTY. We MUST NOT do it in other cases since
4848 * it would have already be done, and 0-2 would have been affected to listening
4849 * sockets
4850 */
4851 if (!(global.mode & MODE_QUIET)) {
4852 /* detach from the tty */
4853 fclose(stdin); fclose(stdout); fclose(stderr);
4854 close(0); close(1); close(2); /* close all fd's */
4855 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
4856 }
willy tarreaua1598082005-12-17 13:08:06 +01004857 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01004858 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01004859 }
4860
willy tarreau0f7af912005-12-17 12:21:26 +01004861 select_loop();
4862
4863 exit(0);
4864}
willy tarreaua1598082005-12-17 13:08:06 +01004865