blob: 0dfa46e4e72d002f44602e88b4a1a054fd14f435 [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 tarreaubc4e1fb2005-12-17 13:32:07 +010021 * 2002/09/01 : 1.1.16
22 * - implement HTTP health checks when option "httpchk" is specified.
willy tarreaue867b482005-12-17 13:28:43 +010023 * 2002/08/07 : 1.1.15
24 * - replaced setpgid()/setpgrp() with setsid() for better portability, because
25 * setpgrp() doesn't have the same meaning under Solaris, Linux, and OpenBSD.
willy tarreaucd878942005-12-17 13:27:43 +010026 * 2002/07/20 : 1.1.14
27 * - added "postonly" cookie mode
willy tarreau6e682ce2005-12-17 13:26:49 +010028 * 2002/07/15 : 1.1.13
29 * - tv_diff used inverted parameters which led to negative times !
willy tarreaucd878942005-12-17 13:27:43 +010030 * 2002/07/13 : 1.1.12
willy tarreau750a4722005-12-17 13:21:24 +010031 * - fixed stats monitoring, and optimized some tv_* for most common cases.
32 * - replaced temporary 'newhdr' with 'trash' to reduce stack size
33 * - made HTTP errors more HTML-fiendly.
34 * - renamed strlcpy() to strlcpy2() because of a slightly difference between
35 * their behaviour (return value), to avoid confusion.
36 * - restricted HTTP messages to HTTP proxies only
37 * - added a 502 message when the connection has been refused by the server,
38 * to prevent clients from believing this is a zero-byte HTTP 0.9 reply.
39 * - changed 'Cache-control:' from 'no-cache="set-cookie"' to 'private' when
40 * inserting a cookie, because some caches (apache) don't understand it.
41 * - fixed processing of server headers when client is in SHUTR state
42 * 2002/07/04 :
43 * - automatically close fd's 0,1 and 2 when going daemon ; setpgrp() after
44 * setpgid()
willy tarreau240afa62005-12-17 13:14:35 +010045 * 2002/06/04 : 1.1.11
46 * - fixed multi-cookie handling in client request to allow clean deletion
47 * in insert+indirect mode. Now, only the server cookie is deleted and not
48 * all the header. Should now be compliant to RFC2109.
49 * - added a "nocache" option to "cookie" to specify that we explicitly want
50 * to add a "cache-control" header when we add a cookie.
51 * It is also possible to add an "Expires: <old-date>" to keep compatibility
52 * with old/broken caches.
willy tarreau96d40372005-12-17 13:11:56 +010053 * 2002/05/10 : 1.1.10
54 * - if a cookie is used in insert+indirect mode, it's desirable that the
55 * the servers don't see it. It was not possible to remove it correctly
56 * with regexps, so now it's removed automatically.
willy tarreauc29948c2005-12-17 13:10:27 +010057 * 2002/04/19 : 1.1.9
58 * - don't use snprintf()'s return value as an end of message since it may
59 * be larger. This caused bus errors and segfaults in internal libc's
60 * getenv() during localtime() in send_log().
61 * - removed dead insecure send_syslog() function and all references to it.
62 * - fixed warnings on Solaris due to buggy implementation of isXXXX().
willy tarreaua1598082005-12-17 13:08:06 +010063 * 2002/04/18 : 1.1.8
64 * - option "dontlognull"
65 * - fixed "double space" bug in config parser
66 * - fixed an uninitialized server field in case of dispatch
67 * with no existing server which could cause a segfault during
68 * logging.
69 * - the pid logged was always the father's, which was wrong for daemons.
70 * - fixed wrong level "LOG_INFO" for message "proxy started".
71 * 2002/04/13 :
72 * - http logging is now complete :
73 * - ip:port, date, proxy, server
74 * - req_time, conn_time, hdr_time, tot_time
75 * - status, size, request
76 * - source address
willy tarreau9fe663a2005-12-17 13:02:59 +010077 * 2002/04/12 : 1.1.7
78 * - added option forwardfor
79 * - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel
80 * - added "log global" in "listen" section.
81 * 2002/04/09 :
82 * - added a new "global" section :
83 * - logs
84 * - debug, quiet, daemon modes
85 * - uid, gid, chroot, nbproc, maxconn
willy tarreaue39cd132005-12-17 13:00:18 +010086 * 2002/04/08 : 1.1.6
87 * - regex are now chained and not limited anymore.
88 * - unavailable server now returns HTTP/502.
89 * - increased per-line args limit to 40
90 * - added reqallow/reqdeny to block some request on matches
91 * - added HTTP 400/403 responses
92 * 2002/04/03 : 1.1.5
willy tarreau535ae7a2005-12-17 12:58:00 +010093 * - connection logging displayed incorrect source address.
94 * - added proxy start/stop and server up/down log events.
95 * - replaced log message short buffers with larger trash.
96 * - enlarged buffer to 8 kB and replace buffer to 4 kB.
willy tarreaue39cd132005-12-17 13:00:18 +010097 * 2002/03/25 : 1.1.4
willy tarreaue47c8d72005-12-17 12:55:52 +010098 * - made rise/fall/interval time configurable
willy tarreaue39cd132005-12-17 13:00:18 +010099 * 2002/03/22 : 1.1.3
willy tarreaub719f002005-12-17 12:55:07 +0100100 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
101 * which could lead to loops.
willy tarreaue39cd132005-12-17 13:00:18 +0100102 * 2002/03/21 : 1.1.2
willy tarreauef900ab2005-12-17 12:52:52 +0100103 * - fixed a bug in buffer management where we could have a loop
104 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
105 * => implemented an adjustable buffer limit.
106 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
107 * and running tasks are skipped.
108 * - added some debug lines for accept events.
109 * - send warnings for servers up/down.
willy tarreaue39cd132005-12-17 13:00:18 +0100110 * 2002/03/12 : 1.1.1
willy tarreauefae1842005-12-17 12:51:03 +0100111 * - fixed a bug in total failure handling
112 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreaue39cd132005-12-17 13:00:18 +0100113 * 2002/03/10 : 1.1.0
willy tarreau5cbea6f2005-12-17 12:48:26 +0100114 * - fixed a few timeout bugs
115 * - rearranged the task scheduler subsystem to improve performance,
116 * add new tasks, and make it easier to later port to librt ;
117 * - allow multiple accept() for one select() wake up ;
118 * - implemented internal load balancing with basic health-check ;
119 * - cookie insertion and header add/replace/delete, with better strings
120 * support.
121 * 2002/03/08
122 * - reworked buffer handling to fix a few rewrite bugs, and
123 * improve overall performance.
124 * - implement the "purge" option to delete server cookies in direct mode.
125 * 2002/03/07
126 * - fixed some error cases where the maxfd was not decreased.
127 * 2002/02/26
128 * - now supports transparent proxying, at least on linux 2.4.
129 * 2002/02/12
130 * - soft stop works again (fixed select timeout computation).
131 * - it seems that TCP proxies sometimes cannot timeout.
132 * - added a "quiet" mode.
133 * - enforce file descriptor limitation on socket() and accept().
134 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +0100135 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +0100136 * 2001/12/16 : release of version 1.0.0.
137 * 2001/12/16 : added syslog capability for each accepted connection.
138 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
139 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
140 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
141 * with or without cookies (use keyword http for this).
142 * 2001/09/01 : added client/server header replacing with regexps.
143 * eg:
144 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
145 * srvexp ^Server:\ .* Server:\ Apache
146 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
147 * 2000/11/28 : major rewrite
148 * 2000/11/26 : first write
149 *
willy tarreau5cbea6f2005-12-17 12:48:26 +0100150 * TODO:
151 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +0100152 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +0100153 *
154 */
155
156#include <stdio.h>
157#include <stdlib.h>
158#include <unistd.h>
159#include <string.h>
160#include <ctype.h>
161#include <sys/time.h>
162#include <sys/types.h>
163#include <sys/socket.h>
164#include <netinet/tcp.h>
165#include <netinet/in.h>
166#include <arpa/inet.h>
167#include <netdb.h>
168#include <fcntl.h>
169#include <errno.h>
170#include <signal.h>
171#include <stdarg.h>
172#include <sys/resource.h>
173#include <time.h>
174#include <regex.h>
175#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +0100176#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100177#include <linux/netfilter_ipv4.h>
178#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100179
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100180#define HAPROXY_VERSION "1.1.16"
181#define HAPROXY_DATE "2002/09/01"
willy tarreau0f7af912005-12-17 12:21:26 +0100182
183/* this is for libc5 for example */
184#ifndef TCP_NODELAY
185#define TCP_NODELAY 1
186#endif
187
188#ifndef SHUT_RD
189#define SHUT_RD 0
190#endif
191
192#ifndef SHUT_WR
193#define SHUT_WR 1
194#endif
195
willy tarreau535ae7a2005-12-17 12:58:00 +0100196#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +0100197
198// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +0100199#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +0100200#define REQURI_LEN 1024
willy tarreau0f7af912005-12-17 12:21:26 +0100201
willy tarreau5cbea6f2005-12-17 12:48:26 +0100202// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100203#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100204
willy tarreaue39cd132005-12-17 13:00:18 +0100205// max # of added headers per request
206#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100207
208// max # of matches per regexp
209#define MAX_MATCH 10
210
willy tarreau5cbea6f2005-12-17 12:48:26 +0100211/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100212#define COOKIENAME_LEN 16
213#define SERVERID_LEN 16
214#define CONN_RETRIES 3
215
willy tarreau5cbea6f2005-12-17 12:48:26 +0100216#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100217#define DEF_CHKINTR 2000
218#define DEF_FALLTIME 3
219#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100220
willy tarreau9fe663a2005-12-17 13:02:59 +0100221/* default connections limit */
222#define DEFAULT_MAXCONN 2000
223
willy tarreau0f7af912005-12-17 12:21:26 +0100224/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
225#define INTBITS 5
226
227/* show stats this every millisecond, 0 to disable */
228#ifndef STATTIME
229#define STATTIME 2000
230#endif
231
willy tarreau5cbea6f2005-12-17 12:48:26 +0100232/* this reduces the number of calls to select() by choosing appropriate
233 * sheduler precision in milliseconds. It should be near the minimum
234 * time that is needed by select() to collect all events. All timeouts
235 * are rounded up by adding this value prior to pass it to select().
236 */
237#define SCHEDULER_RESOLUTION 9
238
willy tarreau0f7af912005-12-17 12:21:26 +0100239#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
240#define SETNOW(a) (*a=now)
241
willy tarreau9da061b2005-12-17 12:29:56 +0100242/****** string-specific macros and functions ******/
243/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
244#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
245
246/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
247#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
248
willy tarreau9da061b2005-12-17 12:29:56 +0100249/*
250 * copies at most <size-1> chars from <src> to <dst>. Last char is always
251 * set to 0, unless <size> is 0. The number of chars copied is returned
252 * (excluding the terminating zero).
253 * This code has been optimized for size and speed : on x86, it's 45 bytes
254 * long, uses only registers, and consumes only 4 cycles per char.
255 */
willy tarreau750a4722005-12-17 13:21:24 +0100256int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100257 char *orig = dst;
258 if (size) {
259 while (--size && (*dst = *src)) {
260 src++; dst++;
261 }
262 *dst = 0;
263 }
264 return dst - orig;
265}
willy tarreau9da061b2005-12-17 12:29:56 +0100266
willy tarreau0f7af912005-12-17 12:21:26 +0100267#define MEM_OPTIM
268#ifdef MEM_OPTIM
269/*
270 * Returns a pointer to type <type> taken from the
271 * pool <pool_type> or dynamically allocated. In the
272 * first case, <pool_type> is updated to point to the
273 * next element in the list.
274 */
275#define pool_alloc(type) ({ \
276 void *p; \
277 if ((p = pool_##type) == NULL) \
278 p = malloc(sizeof_##type); \
279 else { \
280 pool_##type = *(void **)pool_##type; \
281 } \
282 p; \
283})
284
285/*
286 * Puts a memory area back to the corresponding pool.
287 * Items are chained directly through a pointer that
288 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100289 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100290 * that each memory area is at least as big as one
291 * pointer.
292 */
293#define pool_free(type, ptr) ({ \
294 *(void **)ptr = (void *)pool_##type; \
295 pool_##type = (void *)ptr; \
296})
297
298#else
299#define pool_alloc(type) (calloc(1,sizeof_##type));
300#define pool_free(type, ptr) (free(ptr));
301#endif /* MEM_OPTIM */
302
willy tarreau5cbea6f2005-12-17 12:48:26 +0100303#define sizeof_task sizeof(struct task)
304#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100305#define sizeof_buffer sizeof(struct buffer)
306#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100307#define sizeof_requri REQURI_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100308
willy tarreau5cbea6f2005-12-17 12:48:26 +0100309/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100310#define FD_STCLOSE 0
311#define FD_STLISTEN 1
312#define FD_STCONN 2
313#define FD_STREADY 3
314#define FD_STERROR 4
315
willy tarreau5cbea6f2005-12-17 12:48:26 +0100316/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100317#define TASK_IDLE 0
318#define TASK_RUNNING 1
319
willy tarreau5cbea6f2005-12-17 12:48:26 +0100320/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100321#define PR_STNEW 0
322#define PR_STIDLE 1
323#define PR_STRUN 2
324#define PR_STDISABLED 3
325
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100327#define PR_MODE_TCP 0
328#define PR_MODE_HTTP 1
329#define PR_MODE_HEALTH 2
330
willy tarreau5cbea6f2005-12-17 12:48:26 +0100331/* bits for proxy->options */
332#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
333#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
334#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
335#define PR_O_COOK_IND 8 /* keep only indirect cookies */
336#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
337#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
338#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
339#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100340#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
341#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100342#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
343#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100344#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreaucd878942005-12-17 13:27:43 +0100345#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
willy tarreaubc4e1fb2005-12-17 13:32:07 +0100346#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
willy tarreau9fe663a2005-12-17 13:02:59 +0100347
willy tarreau5cbea6f2005-12-17 12:48:26 +0100348
willy tarreaue39cd132005-12-17 13:00:18 +0100349/* various session flags */
350#define SN_DIRECT 1 /* connection made on the server matching the client cookie */
351#define SN_CLDENY 2 /* a client header matches a deny regex */
352#define SN_CLALLOW 4 /* a client header matches an allow regex */
353#define SN_SVDENY 8 /* a server header matches a deny regex */
354#define SN_SVALLOW 16 /* a server header matches an allow regex */
willy tarreaucd878942005-12-17 13:27:43 +0100355#define SN_POST 32 /* the request was an HTTP POST */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100356
357/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100358#define CL_STHEADERS 0
359#define CL_STDATA 1
360#define CL_STSHUTR 2
361#define CL_STSHUTW 3
362#define CL_STCLOSE 4
363
willy tarreau5cbea6f2005-12-17 12:48:26 +0100364/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100365#define SV_STIDLE 0
366#define SV_STCONN 1
367#define SV_STHEADERS 2
368#define SV_STDATA 3
369#define SV_STSHUTR 4
370#define SV_STSHUTW 5
371#define SV_STCLOSE 6
372
373/* result of an I/O event */
374#define RES_SILENT 0 /* didn't happen */
375#define RES_DATA 1 /* data were sent or received */
376#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
377#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
378
willy tarreau9fe663a2005-12-17 13:02:59 +0100379/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100380#define MODE_DEBUG 1
381#define MODE_STATS 2
382#define MODE_LOG 4
383#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100384#define MODE_QUIET 16
385
386/* server flags */
387#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100388
willy tarreaue39cd132005-12-17 13:00:18 +0100389/* what to do when a header matches a regex */
390#define ACT_ALLOW 0 /* allow the request */
391#define ACT_REPLACE 1 /* replace the matching header */
392#define ACT_REMOVE 2 /* remove the matching header */
393#define ACT_DENY 3 /* deny the request */
394
willy tarreau9fe663a2005-12-17 13:02:59 +0100395/* configuration sections */
396#define CFG_NONE 0
397#define CFG_GLOBAL 1
398#define CFG_LISTEN 2
399
willy tarreaua1598082005-12-17 13:08:06 +0100400/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100401#define LW_DATE 1 /* date */
402#define LW_CLIP 2 /* CLient IP */
403#define LW_SVIP 4 /* SerVer IP */
404#define LW_SVID 8 /* server ID */
405#define LW_REQ 16 /* http REQuest */
406#define LW_RESP 32 /* http RESPonse */
407#define LW_PXIP 64 /* proxy IP */
408#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100409#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100410
willy tarreau0f7af912005-12-17 12:21:26 +0100411/*********************************************************************/
412
413#define LIST_HEAD(a) ((void *)(&(a)))
414
415/*********************************************************************/
416
417struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100418 struct hdr_exp *next;
419 regex_t *preg; /* expression to look for */
420 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
421 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100422};
423
424struct buffer {
425 unsigned int l; /* data length */
426 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100427 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100428 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100429 char data[BUFSIZE];
430};
431
432struct server {
433 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100434 int state; /* server state (SRV_*) */
435 int cklen; /* the len of the cookie, to speed up checks */
436 char *cookie; /* the id set in the cookie */
437 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100438 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100439 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100440 int rise, fall; /* time in iterations */
441 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100442 int result; /* 0 = connect OK, -1 = connect KO */
443 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100444 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100445};
446
willy tarreau5cbea6f2005-12-17 12:48:26 +0100447/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100448struct task {
449 struct task *next, *prev; /* chaining ... */
450 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100451 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100452 int state; /* task state : IDLE or RUNNING */
453 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100454 int (*process)(struct task *t); /* the function which processes the task */
455 void *context; /* the task's context */
456};
457
458/* WARNING: if new fields are added, they must be initialized in event_accept() */
459struct session {
460 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100461 /* application specific below */
462 struct timeval crexpire; /* expiration date for a client read */
463 struct timeval cwexpire; /* expiration date for a client write */
464 struct timeval srexpire; /* expiration date for a server read */
465 struct timeval swexpire; /* expiration date for a server write */
466 struct timeval cnexpire; /* expiration date for a connect */
467 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
468 struct proxy *proxy; /* the proxy this socket belongs to */
469 int cli_fd; /* the client side fd */
470 int srv_fd; /* the server side fd */
471 int cli_state; /* state of the client side */
472 int srv_state; /* state of the server side */
473 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100474 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100475 struct buffer *req; /* request buffer */
476 struct buffer *rep; /* response buffer */
477 struct sockaddr_in cli_addr; /* the client address */
478 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100479 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100480 struct {
481 int logwait; /* log fields waiting to be collected : LW_* */
482 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
483 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
484 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
485 long t_data; /* delay before the first data byte from the server ... */
486 unsigned long t_close; /* total session duration */
487 char *uri; /* first line if log needed, NULL otherwise */
488 int status; /* HTTP status from the server, negative if from proxy */
489 long long bytes; /* number of bytes transferred from the server */
490 } logs;
willy tarreau0f7af912005-12-17 12:21:26 +0100491};
492
493struct proxy {
494 int listen_fd; /* the listen socket */
495 int state; /* proxy state */
496 struct sockaddr_in listen_addr; /* the address we listen to */
497 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100498 struct server *srv, *cursrv; /* known servers, current server */
499 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100500 char *cookie_name; /* name of the cookie to look for */
501 int clitimeout; /* client I/O timeout (in milliseconds) */
502 int srvtimeout; /* server I/O timeout (in milliseconds) */
503 int contimeout; /* connect timeout (in milliseconds) */
504 char *id; /* proxy id */
505 int nbconn; /* # of active sessions */
506 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100507 int conn_retries; /* maximum number of connect retries */
508 int options; /* PR_O_REDISP, PR_O_TRANSP */
509 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100510 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100511 struct proxy *next;
512 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
513 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau9fe663a2005-12-17 13:02:59 +0100514 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100515 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100516 int nb_reqadd, nb_rspadd;
517 struct hdr_exp *req_exp; /* regular expressions for request headers */
518 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
519 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100520 int grace; /* grace time after stop request */
521};
522
523/* info about one given fd */
524struct fdtab {
525 int (*read)(int fd); /* read function */
526 int (*write)(int fd); /* write function */
527 struct task *owner; /* the session (or proxy) associated with this fd */
528 int state; /* the state of this fd */
529};
530
531/*********************************************************************/
532
willy tarreau0f7af912005-12-17 12:21:26 +0100533int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100534char *cfg_cfgfile = NULL; /* configuration file */
535char *progname = NULL; /* program name */
536int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100537
538/* global options */
539static struct {
540 int uid;
541 int gid;
542 int nbproc;
543 int maxconn;
544 int maxsock; /* max # of sockets */
545 int mode;
546 char *chroot;
547 int logfac1, logfac2;
548 struct sockaddr_in logsrv1, logsrv2;
549} global = {
550 logfac1 : -1,
551 logfac2 : -1,
552 /* others NULL OK */
553};
554
willy tarreau0f7af912005-12-17 12:21:26 +0100555/*********************************************************************/
556
557fd_set *ReadEvent,
558 *WriteEvent,
559 *StaticReadEvent,
560 *StaticWriteEvent;
561
562void **pool_session = NULL,
563 **pool_buffer = NULL,
564 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100565 **pool_requri = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100566 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100567
568struct proxy *proxy = NULL; /* list of all existing proxies */
569struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100570struct task *rq = NULL; /* global run queue */
571struct task wait_queue = { /* global wait queue */
572 prev:LIST_HEAD(wait_queue),
573 next:LIST_HEAD(wait_queue)
574};
willy tarreau0f7af912005-12-17 12:21:26 +0100575
willy tarreau0f7af912005-12-17 12:21:26 +0100576static int totalconn = 0; /* total # of terminated sessions */
577static int actconn = 0; /* # of active sessions */
578static int maxfd = 0; /* # of the highest fd + 1 */
579static int listeners = 0; /* # of listeners */
580static int stopping = 0; /* non zero means stopping in progress */
581static struct timeval now = {0,0}; /* the current date at any moment */
582
583static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100584/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100585static char trash[BUFSIZE];
586
587/*
588 * Syslog facilities and levels
589 */
590
591#define MAX_SYSLOG_LEN 1024
592#define NB_LOG_FACILITIES 24
593const char *log_facilities[NB_LOG_FACILITIES] = {
594 "kern", "user", "mail", "daemon",
595 "auth", "syslog", "lpr", "news",
596 "uucp", "cron", "auth2", "ftp",
597 "ntp", "audit", "alert", "cron2",
598 "local0", "local1", "local2", "local3",
599 "local4", "local5", "local6", "local7"
600};
601
602
603#define NB_LOG_LEVELS 8
604const char *log_levels[NB_LOG_LEVELS] = {
605 "emerg", "alert", "crit", "err",
606 "warning", "notice", "info", "debug"
607};
608
609#define SYSLOG_PORT 514
610
611const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
612 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
613#define MAX_HOSTNAME_LEN 32
614static char hostname[MAX_HOSTNAME_LEN] = "";
615
willy tarreaua1598082005-12-17 13:08:06 +0100616const char *HTTP_400 =
617 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100618 "Cache-Control: no-cache\r\n"
619 "Connection: close\r\n"
620 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100621 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100622
willy tarreaua1598082005-12-17 13:08:06 +0100623const char *HTTP_403 =
624 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100625 "Cache-Control: no-cache\r\n"
626 "Connection: close\r\n"
627 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100628 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
629
630const char *HTTP_500 =
631 "HTTP/1.0 500 Server Error\r\n"
632 "Cache-Control: no-cache\r\n"
633 "Connection: close\r\n"
634 "\r\n"
635 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100636
637const char *HTTP_502 =
638 "HTTP/1.0 502 Proxy Error\r\n"
639 "Cache-Control: no-cache\r\n"
640 "Connection: close\r\n"
641 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100642 "<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 +0100643
willy tarreau0f7af912005-12-17 12:21:26 +0100644/*********************************************************************/
645/* statistics ******************************************************/
646/*********************************************************************/
647
willy tarreau750a4722005-12-17 13:21:24 +0100648#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100649static int stats_tsk_lsrch, stats_tsk_rsrch,
650 stats_tsk_good, stats_tsk_right, stats_tsk_left,
651 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100652#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100653
654
655/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100656/* debugging *******************************************************/
657/*********************************************************************/
658#ifdef DEBUG_FULL
659static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
660static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
661#endif
662
663/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100664/* function prototypes *********************************************/
665/*********************************************************************/
666
667int event_accept(int fd);
668int event_cli_read(int fd);
669int event_cli_write(int fd);
670int event_srv_read(int fd);
671int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100672int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100673
674/*********************************************************************/
675/* general purpose functions ***************************************/
676/*********************************************************************/
677
678void display_version() {
679 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100680 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100681}
682
683/*
684 * This function prints the command line usage and exits
685 */
686void usage(char *name) {
687 display_version();
688 fprintf(stderr,
689 "Usage : %s -f <cfgfile> [ -vd"
690#if STATTIME > 0
691 "sl"
692#endif
693 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
694 " -v displays version\n"
695 " -d enters debug mode\n"
696#if STATTIME > 0
697 " -s enables statistics output\n"
698 " -l enables long statistics format\n"
699#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100700 " -D goes daemon ; implies -q\n"
701 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100702 " -n sets the maximum total # of connections (%d)\n"
703 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100704 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100705 exit(1);
706}
707
708
709/*
710 * Displays the message on stderr with the date and pid.
711 */
712void Alert(char *fmt, ...) {
713 va_list argp;
714 struct timeval tv;
715 struct tm *tm;
716
willy tarreau9fe663a2005-12-17 13:02:59 +0100717 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100718 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100719
willy tarreau5cbea6f2005-12-17 12:48:26 +0100720 gettimeofday(&tv, NULL);
721 tm=localtime(&tv.tv_sec);
722 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100723 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100724 vfprintf(stderr, fmt, argp);
725 fflush(stderr);
726 va_end(argp);
727 }
willy tarreau0f7af912005-12-17 12:21:26 +0100728}
729
730
731/*
732 * Displays the message on stderr with the date and pid.
733 */
734void Warning(char *fmt, ...) {
735 va_list argp;
736 struct timeval tv;
737 struct tm *tm;
738
willy tarreau9fe663a2005-12-17 13:02:59 +0100739 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100740 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100741
willy tarreau5cbea6f2005-12-17 12:48:26 +0100742 gettimeofday(&tv, NULL);
743 tm=localtime(&tv.tv_sec);
744 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100745 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100746 vfprintf(stderr, fmt, argp);
747 fflush(stderr);
748 va_end(argp);
749 }
750}
751
752/*
753 * Displays the message on <out> only if quiet mode is not set.
754 */
755void qfprintf(FILE *out, char *fmt, ...) {
756 va_list argp;
757
willy tarreau9fe663a2005-12-17 13:02:59 +0100758 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100759 va_start(argp, fmt);
760 vfprintf(out, fmt, argp);
761 fflush(out);
762 va_end(argp);
763 }
willy tarreau0f7af912005-12-17 12:21:26 +0100764}
765
766
767/*
768 * converts <str> to a struct sockaddr_in* which is locally allocated.
769 * The format is "addr:port", where "addr" can be empty or "*" to indicate
770 * INADDR_ANY.
771 */
772struct sockaddr_in *str2sa(char *str) {
773 static struct sockaddr_in sa;
774 char *c;
775 int port;
776
willy tarreaua1598082005-12-17 13:08:06 +0100777 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100778 str=strdup(str);
779
780 if ((c=strrchr(str,':')) != NULL) {
781 *c++=0;
782 port=atol(c);
783 }
784 else
785 port=0;
786
787 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
788 sa.sin_addr.s_addr = INADDR_ANY;
789 }
790 else if (
791#ifndef SOLARIS
792 !inet_aton(str, &sa.sin_addr)
793#else
794 !inet_pton(AF_INET, str, &sa.sin_addr)
795#endif
796 ) {
797 struct hostent *he;
798
799 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100800 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100801 }
802 else
803 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
804 }
805 sa.sin_port=htons(port);
806 sa.sin_family=AF_INET;
807
808 free(str);
809 return &sa;
810}
811
willy tarreau9fe663a2005-12-17 13:02:59 +0100812
813/*
814 * This function sends a syslog message to both log servers of a proxy,
815 * or to global log servers if the proxy is NULL.
816 * It also tries not to waste too much time computing the message header.
817 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100818 */
819void send_log(struct proxy *p, int level, char *message, ...) {
820 static int logfd = -1; /* syslog UDP socket */
821 static long tvsec = -1; /* to force the string to be initialized */
822 struct timeval tv;
823 va_list argp;
824 static char logmsg[MAX_SYSLOG_LEN];
825 static char *dataptr = NULL;
826 int fac_level;
827 int hdr_len, data_len;
828 struct sockaddr_in *sa[2];
829 int facilities[2];
830 int nbloggers = 0;
831 char *log_ptr;
832
833 if (logfd < 0) {
834 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
835 return;
836 }
837
838 if (level < 0 || progname == NULL || message == NULL)
839 return;
840
841 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100842 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100843 /* this string is rebuild only once a second */
844 struct tm *tm = localtime(&tv.tv_sec);
845 tvsec = tv.tv_sec;
846
willy tarreauc29948c2005-12-17 13:10:27 +0100847 hdr_len = snprintf(logmsg, sizeof(logmsg),
848 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
849 monthname[tm->tm_mon],
850 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
851 progname, pid);
852 /* WARNING: depending upon implementations, snprintf may return
853 * either -1 or the number of bytes that would be needed to store
854 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100855 */
willy tarreauc29948c2005-12-17 13:10:27 +0100856 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
857 hdr_len = sizeof(logmsg);
858
859 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100860 }
861
862 va_start(argp, message);
863 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100864 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
865 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100866 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100867 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100868
869 if (p == NULL) {
870 if (global.logfac1 >= 0) {
871 sa[nbloggers] = &global.logsrv1;
872 facilities[nbloggers] = global.logfac1;
873 nbloggers++;
874 }
875 if (global.logfac2 >= 0) {
876 sa[nbloggers] = &global.logsrv2;
877 facilities[nbloggers] = global.logfac2;
878 nbloggers++;
879 }
880 } else {
881 if (p->logfac1 >= 0) {
882 sa[nbloggers] = &p->logsrv1;
883 facilities[nbloggers] = p->logfac1;
884 nbloggers++;
885 }
886 if (p->logfac2 >= 0) {
887 sa[nbloggers] = &p->logsrv2;
888 facilities[nbloggers] = p->logfac2;
889 nbloggers++;
890 }
891 }
892
893 while (nbloggers-- > 0) {
willy tarreauc29948c2005-12-17 13:10:27 +0100894 /* For each target, we may have a different facility.
895 * We can also have a different log level for each message.
896 * This induces variations in the message header length.
897 * Since we don't want to recompute it each time, nor copy it every
898 * time, we only change the facility in the pre-computed header,
899 * and we change the pointer to the header accordingly.
900 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100901 fac_level = (facilities[nbloggers] << 3) + level;
902 log_ptr = logmsg + 3; /* last digit of the log level */
903 do {
904 *log_ptr = '0' + fac_level % 10;
905 fac_level /= 10;
906 log_ptr--;
907 } while (fac_level && log_ptr > logmsg);
908 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100909
willy tarreauc29948c2005-12-17 13:10:27 +0100910 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100911
912#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100913 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100914 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
915#else
willy tarreauc29948c2005-12-17 13:10:27 +0100916 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100917 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
918#endif
919 }
willy tarreau0f7af912005-12-17 12:21:26 +0100920}
921
922
923/* sets <tv> to the current time */
924static inline struct timeval *tv_now(struct timeval *tv) {
925 if (tv)
926 gettimeofday(tv, NULL);
927 return tv;
928}
929
930/*
931 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
932 */
933static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
934 if (!tv || !from)
935 return NULL;
936 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
937 tv->tv_sec = from->tv_sec + (ms/1000);
938 while (tv->tv_usec >= 1000000) {
939 tv->tv_usec -= 1000000;
940 tv->tv_sec++;
941 }
942 return tv;
943}
944
945/*
946 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
947 */
948static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +0100949 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100950 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100951 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100952 return 1;
953 else if (tv1->tv_usec < tv2->tv_usec)
954 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100955 else if (tv1->tv_usec > tv2->tv_usec)
956 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +0100957 else
958 return 0;
959}
960
961/*
962 * returns the absolute difference, in ms, between tv1 and tv2
963 */
964unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
965 int cmp;
966 unsigned long ret;
967
968
willy tarreauef900ab2005-12-17 12:52:52 +0100969 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100970 if (!cmp)
971 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +0100972 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100973 struct timeval *tmp = tv1;
974 tv1 = tv2;
975 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100976 }
willy tarreauef900ab2005-12-17 12:52:52 +0100977 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100978 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100979 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100980 else
willy tarreauef900ab2005-12-17 12:52:52 +0100981 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100982 return (unsigned long) ret;
983}
984
985/*
willy tarreau750a4722005-12-17 13:21:24 +0100986 * returns the difference, in ms, between tv1 and tv2
987 */
988static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
989 unsigned long ret;
990
willy tarreau6e682ce2005-12-17 13:26:49 +0100991 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
992 if (tv2->tv_usec > tv1->tv_usec)
993 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100994 else
willy tarreau6e682ce2005-12-17 13:26:49 +0100995 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100996 return (unsigned long) ret;
997}
998
999/*
willy tarreau0f7af912005-12-17 12:21:26 +01001000 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1001 */
1002static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001003 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001004 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001005 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001006 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1007 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001008 else
1009 return 0;
1010 }
willy tarreau0f7af912005-12-17 12:21:26 +01001011 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001012 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001013 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001014 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1015 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1016 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001017 else
1018 return 0;
1019}
1020
1021/*
1022 * returns the remaining time between tv1=now and event=tv2
1023 * if tv2 is passed, 0 is returned.
1024 */
1025static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1026 unsigned long ret;
1027
willy tarreau0f7af912005-12-17 12:21:26 +01001028 if (tv_cmp_ms(tv1, tv2) >= 0)
1029 return 0; /* event elapsed */
1030
willy tarreauef900ab2005-12-17 12:52:52 +01001031 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001032 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001033 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001034 else
willy tarreauef900ab2005-12-17 12:52:52 +01001035 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001036 return (unsigned long) ret;
1037}
1038
1039
1040/*
1041 * zeroes a struct timeval
1042 */
1043
1044static inline struct timeval *tv_eternity(struct timeval *tv) {
1045 tv->tv_sec = tv->tv_usec = 0;
1046 return tv;
1047}
1048
1049/*
1050 * returns 1 if tv is null, else 0
1051 */
1052static inline int tv_iseternity(struct timeval *tv) {
1053 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1054 return 1;
1055 else
1056 return 0;
1057}
1058
1059/*
1060 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1061 * considering that 0 is the eternity.
1062 */
1063static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1064 if (tv_iseternity(tv1))
1065 if (tv_iseternity(tv2))
1066 return 0; /* same */
1067 else
1068 return 1; /* tv1 later than tv2 */
1069 else if (tv_iseternity(tv2))
1070 return -1; /* tv2 later than tv1 */
1071
1072 if (tv1->tv_sec > tv2->tv_sec)
1073 return 1;
1074 else if (tv1->tv_sec < tv2->tv_sec)
1075 return -1;
1076 else if (tv1->tv_usec > tv2->tv_usec)
1077 return 1;
1078 else if (tv1->tv_usec < tv2->tv_usec)
1079 return -1;
1080 else
1081 return 0;
1082}
1083
1084/*
1085 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1086 * considering that 0 is the eternity.
1087 */
1088static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1089 if (tv_iseternity(tv1))
1090 if (tv_iseternity(tv2))
1091 return 0; /* same */
1092 else
1093 return 1; /* tv1 later than tv2 */
1094 else if (tv_iseternity(tv2))
1095 return -1; /* tv2 later than tv1 */
1096
willy tarreauefae1842005-12-17 12:51:03 +01001097 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001098 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001099 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001100 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001101 return -1;
1102 else
1103 return 0;
1104 }
1105 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001106 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001107 return 1;
1108 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001109 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001110 return -1;
1111 else
1112 return 0;
1113}
1114
1115/*
1116 * returns the first event between tv1 and tv2 into tvmin.
1117 * a zero tv is ignored. tvmin is returned.
1118 */
1119static inline struct timeval *tv_min(struct timeval *tvmin,
1120 struct timeval *tv1, struct timeval *tv2) {
1121
1122 if (tv_cmp2(tv1, tv2) <= 0)
1123 *tvmin = *tv1;
1124 else
1125 *tvmin = *tv2;
1126
1127 return tvmin;
1128}
1129
1130
1131
1132/***********************************************************/
1133/* fd management ***************************************/
1134/***********************************************************/
1135
1136
1137
willy tarreau5cbea6f2005-12-17 12:48:26 +01001138/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1139 * The file descriptor is also closed.
1140 */
willy tarreau0f7af912005-12-17 12:21:26 +01001141static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001142 FD_CLR(fd, StaticReadEvent);
1143 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001144 close(fd);
1145 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001146
1147 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1148 maxfd--;
1149}
1150
1151/* recomputes the maxfd limit from the fd */
1152static inline void fd_insert(int fd) {
1153 if (fd+1 > maxfd)
1154 maxfd = fd+1;
1155}
1156
1157/*************************************************************/
1158/* task management ***************************************/
1159/*************************************************************/
1160
willy tarreau5cbea6f2005-12-17 12:48:26 +01001161/* puts the task <t> in run queue <q>, and returns <t> */
1162static inline struct task *task_wakeup(struct task **q, struct task *t) {
1163 if (t->state == TASK_RUNNING)
1164 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001165 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001166 t->rqnext = *q;
1167 t->state = TASK_RUNNING;
1168 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001169 }
1170}
1171
willy tarreau5cbea6f2005-12-17 12:48:26 +01001172/* removes the task <t> from the queue <q>
1173 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001174 * set the run queue to point to the next one, and return it
1175 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001176static inline struct task *task_sleep(struct task **q, struct task *t) {
1177 if (t->state == TASK_RUNNING) {
1178 *q = t->rqnext;
1179 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001180 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001181 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001182}
1183
1184/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001185 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001186 * from the run queue. A pointer to the task itself is returned.
1187 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001188static inline struct task *task_delete(struct task *t) {
1189 t->prev->next = t->next;
1190 t->next->prev = t->prev;
1191 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001192}
1193
1194/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001195 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001196 */
1197static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001198 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001199}
1200
willy tarreau5cbea6f2005-12-17 12:48:26 +01001201/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001202 * may be only moved or left where it was, depending on its timing requirements.
1203 * <task> is returned.
1204 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001205struct task *task_queue(struct task *task) {
1206 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001207 struct task *start_from;
1208
1209 /* first, test if the task was already in a list */
1210 if (task->prev == NULL) {
1211 // start_from = list;
1212 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001213#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001214 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001215#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001216 /* insert the unlinked <task> into the list, searching back from the last entry */
1217 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1218 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001219#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001220 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001221#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001222 }
1223
1224 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1225 // start_from = start_from->next;
1226 // stats_tsk_nsrch++;
1227 // }
1228 }
1229 else if (task->prev == list ||
1230 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1231 start_from = task->next;
1232 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001233#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001234 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001235#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001236 return task; /* it's already in the right place */
1237 }
1238
willy tarreau750a4722005-12-17 13:21:24 +01001239#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001240 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001241#endif
1242
1243 /* if the task is not at the right place, there's little chance that
1244 * it has only shifted a bit, and it will nearly always be queued
1245 * at the end of the list because of constant timeouts
1246 * (observed in real case).
1247 */
1248#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1249 start_from = list->prev; /* assume we'll queue to the end of the list */
1250 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1251 start_from = start_from->prev;
1252#if STATTIME > 0
1253 stats_tsk_lsrch++;
1254#endif
1255 }
1256#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001257 /* insert the unlinked <task> into the list, searching after position <start_from> */
1258 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1259 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001260#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001261 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001262#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001263 }
willy tarreau750a4722005-12-17 13:21:24 +01001264#endif /* WE_REALLY_... */
1265
willy tarreau0f7af912005-12-17 12:21:26 +01001266 /* we need to unlink it now */
1267 task_delete(task);
1268 }
1269 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001270#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001271 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001272#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001273#ifdef LEFT_TO_TOP /* not very good */
1274 start_from = list;
1275 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1276 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001277#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001278 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001279#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001280 }
1281#else
1282 start_from = task->prev->prev; /* valid because of the previous test above */
1283 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1284 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001285#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001286 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001287#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001288 }
1289#endif
1290 /* we need to unlink it now */
1291 task_delete(task);
1292 }
1293 task->prev = start_from;
1294 task->next = start_from->next;
1295 task->next->prev = task;
1296 start_from->next = task;
1297 return task;
1298}
1299
1300
1301/*********************************************************************/
1302/* more specific functions ***************************************/
1303/*********************************************************************/
1304
1305/* some prototypes */
1306static int maintain_proxies(void);
1307
willy tarreau5cbea6f2005-12-17 12:48:26 +01001308/* this either returns the sockname or the original destination address. Code
1309 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1310 */
1311static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001312#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001313 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1314#else
willy tarreaua1598082005-12-17 13:08:06 +01001315#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001316 return getsockname(fd, (struct sockaddr *)sa, salen);
1317#else
1318 return -1;
1319#endif
1320#endif
1321}
1322
1323/*
1324 * frees the context associated to a session. It must have been removed first.
1325 */
1326static inline void session_free(struct session *s) {
1327 if (s->req)
1328 pool_free(buffer, s->req);
1329 if (s->rep)
1330 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001331 if (s->logs.uri)
1332 pool_free(requri, s->logs.uri);
willy tarreau9fe663a2005-12-17 13:02:59 +01001333
willy tarreau5cbea6f2005-12-17 12:48:26 +01001334 pool_free(session, s);
1335}
1336
willy tarreau0f7af912005-12-17 12:21:26 +01001337
1338/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001339 * This function initiates a connection to the current server (s->srv) if (s->direct)
1340 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001341 * it's OK, -1 if it's impossible.
1342 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001343int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001344 int one = 1;
1345 int fd;
1346
1347 // fprintf(stderr,"connect_server : s=%p\n",s);
1348
willy tarreaue39cd132005-12-17 13:00:18 +01001349 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001350 s->srv_addr = s->srv->addr;
1351 }
1352 else if (s->proxy->options & PR_O_BALANCE) {
1353 if (s->proxy->options & PR_O_BALANCE_RR) {
1354 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001355 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001356 if (s->proxy->cursrv == NULL)
1357 s->proxy->cursrv = s->proxy->srv;
1358 if (s->proxy->cursrv->state & SRV_RUNNING)
1359 break;
1360 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001361 retry--;
1362 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001363
1364 if (retry == 0) /* no server left */
1365 return -1;
1366
1367 s->srv = s->proxy->cursrv;
1368 s->srv_addr = s->srv->addr;
1369 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001370 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001371 else /* unknown balancing algorithm */
1372 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001373 }
willy tarreaua1598082005-12-17 13:08:06 +01001374 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001375 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001376 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001377 }
1378 else if (s->proxy->options & PR_O_TRANSP) {
1379 /* in transparent mode, use the original dest addr if no dispatch specified */
1380 int salen = sizeof(struct sockaddr_in);
1381 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1382 qfprintf(stderr, "Cannot get original server address.\n");
1383 return -1;
1384 }
1385 }
willy tarreau0f7af912005-12-17 12:21:26 +01001386
1387 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001388 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001389 return -1;
1390 }
1391
willy tarreau9fe663a2005-12-17 13:02:59 +01001392 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001393 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1394 close(fd);
1395 return -1;
1396 }
1397
willy tarreau0f7af912005-12-17 12:21:26 +01001398 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1399 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001400 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001401 close(fd);
1402 return -1;
1403 }
1404
willy tarreaua1598082005-12-17 13:08:06 +01001405 /* allow specific binding */
1406 if (s->proxy->options & PR_O_BIND_SRC &&
1407 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1408 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1409 close(fd);
1410 return -1;
1411 }
1412
willy tarreau0f7af912005-12-17 12:21:26 +01001413 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1414 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001415 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001416 close(fd);
1417 return -1;
1418 }
1419 else if (errno != EALREADY && errno != EISCONN) {
1420 close(fd);
1421 return -1;
1422 }
1423 }
1424
willy tarreau5cbea6f2005-12-17 12:48:26 +01001425 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001426 fdtab[fd].read = &event_srv_read;
1427 fdtab[fd].write = &event_srv_write;
1428 fdtab[fd].state = FD_STCONN; /* connection in progress */
1429
1430 FD_SET(fd, StaticWriteEvent); /* for connect status */
1431
1432 fd_insert(fd);
1433
1434 if (s->proxy->contimeout)
1435 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1436 else
1437 tv_eternity(&s->cnexpire);
1438 return 0;
1439}
1440
1441/*
1442 * this function is called on a read event from a client socket.
1443 * It returns 0.
1444 */
1445int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001446 struct task *t = fdtab[fd].owner;
1447 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001448 struct buffer *b = s->req;
1449 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001450
1451 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1452
willy tarreau0f7af912005-12-17 12:21:26 +01001453 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001454 while (1) {
1455 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1456 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001457 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001458 }
1459 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001460 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001461 }
1462 else {
1463 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001464 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1465 * since it means that the rewrite protection has been removed. This
1466 * implies that the if statement can be removed.
1467 */
1468 if (max > b->rlim - b->data)
1469 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001470 }
1471
1472 if (max == 0) { /* not anymore room to store data */
1473 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001474 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001475 }
1476
willy tarreau3242e862005-12-17 12:27:53 +01001477#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001478 {
1479 int skerr, lskerr;
1480
1481 lskerr = sizeof(skerr);
1482 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1483 if (skerr)
1484 ret = -1;
1485 else
1486 ret = recv(fd, b->r, max, 0);
1487 }
willy tarreau3242e862005-12-17 12:27:53 +01001488#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001489 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001490#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001491 if (ret > 0) {
1492 b->r += ret;
1493 b->l += ret;
1494 s->res_cr = RES_DATA;
1495
1496 if (b->r == b->data + BUFSIZE) {
1497 b->r = b->data; /* wrap around the buffer */
1498 }
willy tarreaua1598082005-12-17 13:08:06 +01001499
1500 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001501 /* we hope to read more data or to get a close on next round */
1502 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001503 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001504 else if (ret == 0) {
1505 s->res_cr = RES_NULL;
1506 break;
1507 }
1508 else if (errno == EAGAIN) {/* ignore EAGAIN */
1509 break;
1510 }
1511 else {
1512 s->res_cr = RES_ERROR;
1513 fdtab[fd].state = FD_STERROR;
1514 break;
1515 }
1516 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001517 }
1518 else {
1519 s->res_cr = RES_ERROR;
1520 fdtab[fd].state = FD_STERROR;
1521 }
1522
willy tarreau5cbea6f2005-12-17 12:48:26 +01001523 if (s->res_cr != RES_SILENT) {
1524 if (s->proxy->clitimeout)
1525 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1526 else
1527 tv_eternity(&s->crexpire);
1528
1529 task_wakeup(&rq, t);
1530 }
willy tarreau0f7af912005-12-17 12:21:26 +01001531
willy tarreau0f7af912005-12-17 12:21:26 +01001532 return 0;
1533}
1534
1535
1536/*
1537 * this function is called on a read event from a server socket.
1538 * It returns 0.
1539 */
1540int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001541 struct task *t = fdtab[fd].owner;
1542 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001543 struct buffer *b = s->rep;
1544 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001545
1546 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1547
willy tarreau0f7af912005-12-17 12:21:26 +01001548 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001549 while (1) {
1550 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1551 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001552 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001553 }
1554 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001555 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001556 }
1557 else {
1558 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001559 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1560 * since it means that the rewrite protection has been removed. This
1561 * implies that the if statement can be removed.
1562 */
1563 if (max > b->rlim - b->data)
1564 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001565 }
1566
1567 if (max == 0) { /* not anymore room to store data */
1568 FD_CLR(fd, StaticReadEvent);
1569 break;
1570 }
1571
willy tarreau3242e862005-12-17 12:27:53 +01001572#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001573 {
1574 int skerr, lskerr;
1575
1576 lskerr = sizeof(skerr);
1577 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1578 if (skerr)
1579 ret = -1;
1580 else
1581 ret = recv(fd, b->r, max, 0);
1582 }
willy tarreau3242e862005-12-17 12:27:53 +01001583#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001584 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001585#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001586 if (ret > 0) {
1587 b->r += ret;
1588 b->l += ret;
1589 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001590
willy tarreau5cbea6f2005-12-17 12:48:26 +01001591 if (b->r == b->data + BUFSIZE) {
1592 b->r = b->data; /* wrap around the buffer */
1593 }
willy tarreaua1598082005-12-17 13:08:06 +01001594
1595 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001596 /* we hope to read more data or to get a close on next round */
1597 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001598 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001599 else if (ret == 0) {
1600 s->res_sr = RES_NULL;
1601 break;
1602 }
1603 else if (errno == EAGAIN) {/* ignore EAGAIN */
1604 break;
1605 }
1606 else {
1607 s->res_sr = RES_ERROR;
1608 fdtab[fd].state = FD_STERROR;
1609 break;
1610 }
1611 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001612 }
1613 else {
1614 s->res_sr = RES_ERROR;
1615 fdtab[fd].state = FD_STERROR;
1616 }
1617
willy tarreau5cbea6f2005-12-17 12:48:26 +01001618 if (s->res_sr != RES_SILENT) {
1619 if (s->proxy->srvtimeout)
1620 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1621 else
1622 tv_eternity(&s->srexpire);
1623
1624 task_wakeup(&rq, t);
1625 }
willy tarreau0f7af912005-12-17 12:21:26 +01001626
willy tarreau0f7af912005-12-17 12:21:26 +01001627 return 0;
1628}
1629
1630/*
1631 * this function is called on a write event from a client socket.
1632 * It returns 0.
1633 */
1634int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001635 struct task *t = fdtab[fd].owner;
1636 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001637 struct buffer *b = s->rep;
1638 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001639
1640 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1641
1642 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001643 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001644 // max = BUFSIZE; BUG !!!!
1645 max = 0;
1646 }
1647 else if (b->r > b->w) {
1648 max = b->r - b->w;
1649 }
1650 else
1651 max = b->data + BUFSIZE - b->w;
1652
willy tarreau0f7af912005-12-17 12:21:26 +01001653 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001654#ifndef MSG_NOSIGNAL
1655 int skerr, lskerr;
1656#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001657
1658 if (max == 0) {
1659 s->res_cw = RES_NULL;
1660 task_wakeup(&rq, t);
1661 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001662 }
1663
willy tarreau3242e862005-12-17 12:27:53 +01001664#ifndef MSG_NOSIGNAL
1665 lskerr=sizeof(skerr);
1666 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1667 if (skerr)
1668 ret = -1;
1669 else
1670 ret = send(fd, b->w, max, MSG_DONTWAIT);
1671#else
willy tarreau0f7af912005-12-17 12:21:26 +01001672 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001673#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001674
1675 if (ret > 0) {
1676 b->l -= ret;
1677 b->w += ret;
1678
1679 s->res_cw = RES_DATA;
1680
1681 if (b->w == b->data + BUFSIZE) {
1682 b->w = b->data; /* wrap around the buffer */
1683 }
1684 }
1685 else if (ret == 0) {
1686 /* nothing written, just make as if we were never called */
1687// s->res_cw = RES_NULL;
1688 return 0;
1689 }
1690 else if (errno == EAGAIN) /* ignore EAGAIN */
1691 return 0;
1692 else {
1693 s->res_cw = RES_ERROR;
1694 fdtab[fd].state = FD_STERROR;
1695 }
1696 }
1697 else {
1698 s->res_cw = RES_ERROR;
1699 fdtab[fd].state = FD_STERROR;
1700 }
1701
1702 if (s->proxy->clitimeout)
1703 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1704 else
1705 tv_eternity(&s->cwexpire);
1706
willy tarreau5cbea6f2005-12-17 12:48:26 +01001707 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001708 return 0;
1709}
1710
1711
1712/*
1713 * this function is called on a write event from a server socket.
1714 * It returns 0.
1715 */
1716int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001717 struct task *t = fdtab[fd].owner;
1718 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001719 struct buffer *b = s->req;
1720 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001721
1722 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1723
1724 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001725 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001726 // max = BUFSIZE; BUG !!!!
1727 max = 0;
1728 }
1729 else if (b->r > b->w) {
1730 max = b->r - b->w;
1731 }
1732 else
1733 max = b->data + BUFSIZE - b->w;
1734
willy tarreau0f7af912005-12-17 12:21:26 +01001735 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001736#ifndef MSG_NOSIGNAL
1737 int skerr, lskerr;
1738#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001739 if (max == 0) {
1740 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001741 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001742 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001743 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001744 return 0;
1745 }
1746
willy tarreauef900ab2005-12-17 12:52:52 +01001747
willy tarreau3242e862005-12-17 12:27:53 +01001748#ifndef MSG_NOSIGNAL
1749 lskerr=sizeof(skerr);
1750 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1751 if (skerr)
1752 ret = -1;
1753 else
1754 ret = send(fd, b->w, max, MSG_DONTWAIT);
1755#else
willy tarreau0f7af912005-12-17 12:21:26 +01001756 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001757#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001758 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001759 if (ret > 0) {
1760 b->l -= ret;
1761 b->w += ret;
1762
1763 s->res_sw = RES_DATA;
1764
1765 if (b->w == b->data + BUFSIZE) {
1766 b->w = b->data; /* wrap around the buffer */
1767 }
1768 }
1769 else if (ret == 0) {
1770 /* nothing written, just make as if we were never called */
1771 // s->res_sw = RES_NULL;
1772 return 0;
1773 }
1774 else if (errno == EAGAIN) /* ignore EAGAIN */
1775 return 0;
1776 else {
1777 s->res_sw = RES_ERROR;
1778 fdtab[fd].state = FD_STERROR;
1779 }
1780 }
1781 else {
1782 s->res_sw = RES_ERROR;
1783 fdtab[fd].state = FD_STERROR;
1784 }
1785
1786 if (s->proxy->srvtimeout)
1787 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1788 else
1789 tv_eternity(&s->swexpire);
1790
willy tarreau5cbea6f2005-12-17 12:48:26 +01001791 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001792 return 0;
1793}
1794
1795
1796/*
willy tarreaue39cd132005-12-17 13:00:18 +01001797 * returns a message to the client ; the connection is shut down for read,
1798 * and the request is cleared so that no server connection can be initiated.
1799 * The client must be in a valid state for this (HEADER, DATA ...).
1800 * Nothing is performed on the server side.
1801 * The reply buffer must be empty before this.
1802 */
1803void client_retnclose(struct session *s, int len, const char *msg) {
1804 FD_CLR(s->cli_fd, StaticReadEvent);
1805 FD_SET(s->cli_fd, StaticWriteEvent);
1806 tv_eternity(&s->crexpire);
1807 shutdown(s->cli_fd, SHUT_RD);
1808 s->cli_state = CL_STSHUTR;
1809 strcpy(s->rep->data, msg);
1810 s->rep->l = len;
1811 s->rep->r += len;
1812 s->req->l = 0;
1813}
1814
1815
1816/*
1817 * returns a message into the rep buffer, and flushes the req buffer.
1818 * The reply buffer must be empty before this.
1819 */
1820void client_return(struct session *s, int len, const char *msg) {
1821 strcpy(s->rep->data, msg);
1822 s->rep->l = len;
1823 s->rep->r += len;
1824 s->req->l = 0;
1825}
1826
willy tarreau9fe663a2005-12-17 13:02:59 +01001827/*
1828 * send a log for the session when we have enough info about it
1829 */
1830void sess_log(struct session *s) {
1831 unsigned char *pn;
1832 struct proxy *p = s->proxy;
1833 int log;
1834 char *uri;
1835 char *pxid;
1836 char *srv;
1837
1838 /* This is a first attempt at a better logging system.
1839 * For now, we rely on send_log() to provide the date, although it obviously
1840 * is the date of the log and not of the request, and most fields are not
1841 * computed.
1842 */
1843
willy tarreaua1598082005-12-17 13:08:06 +01001844 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001845
1846 pn = (log & LW_CLIP) ?
1847 (unsigned char *)&s->cli_addr.sin_addr :
1848 (unsigned char *)"\0\0\0\0";
1849
willy tarreaua1598082005-12-17 13:08:06 +01001850 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001851 pxid = p->id;
1852 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001853 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1854
1855 if (p->to_log & LW_DATE) {
1856 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1857
1858 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",
1859 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1860 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1861 tm->tm_hour, tm->tm_min, tm->tm_sec,
1862 pxid, srv,
1863 s->logs.t_request,
1864 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1865 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1866 s->logs.t_close,
1867 s->logs.status, s->logs.bytes,
1868 uri);
1869 }
1870 else {
1871 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld \"%s\"\n",
1872 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1873 pxid, srv,
1874 s->logs.t_request,
1875 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1876 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1877 s->logs.t_close,
1878 s->logs.status, s->logs.bytes,
1879 uri);
1880 }
1881
1882 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001883}
1884
willy tarreaue39cd132005-12-17 13:00:18 +01001885
1886/*
willy tarreau0f7af912005-12-17 12:21:26 +01001887 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001888 * to an accept. It tries to accept as many connections as possible.
1889 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001890 */
1891int event_accept(int fd) {
1892 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001893 struct session *s;
1894 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001895 int cfd;
1896 int one = 1;
1897
willy tarreau5cbea6f2005-12-17 12:48:26 +01001898 while (p->nbconn < p->maxconn) {
1899 struct sockaddr_in addr;
1900 int laddr = sizeof(addr);
1901 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1902 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001903
willy tarreau5cbea6f2005-12-17 12:48:26 +01001904 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1905 Alert("out of memory in event_accept().\n");
1906 FD_CLR(fd, StaticReadEvent);
1907 p->state = PR_STIDLE;
1908 close(cfd);
1909 return 0;
1910 }
willy tarreau0f7af912005-12-17 12:21:26 +01001911
willy tarreau5cbea6f2005-12-17 12:48:26 +01001912 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1913 Alert("out of memory in event_accept().\n");
1914 FD_CLR(fd, StaticReadEvent);
1915 p->state = PR_STIDLE;
1916 close(cfd);
1917 pool_free(session, s);
1918 return 0;
1919 }
willy tarreau0f7af912005-12-17 12:21:26 +01001920
willy tarreau5cbea6f2005-12-17 12:48:26 +01001921 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001922 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001923 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1924 close(cfd);
1925 pool_free(task, t);
1926 pool_free(session, s);
1927 return 0;
1928 }
willy tarreau0f7af912005-12-17 12:21:26 +01001929
willy tarreau5cbea6f2005-12-17 12:48:26 +01001930 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1931 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1932 (char *) &one, sizeof(one)) == -1)) {
1933 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1934 close(cfd);
1935 pool_free(task, t);
1936 pool_free(session, s);
1937 return 0;
1938 }
willy tarreau0f7af912005-12-17 12:21:26 +01001939
willy tarreau9fe663a2005-12-17 13:02:59 +01001940 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1941 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1942 t->state = TASK_IDLE;
1943 t->process = process_session;
1944 t->context = s;
1945
1946 s->task = t;
1947 s->proxy = p;
1948 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1949 s->srv_state = SV_STIDLE;
1950 s->req = s->rep = NULL; /* will be allocated later */
1951 s->flags = 0;
1952 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1953 s->cli_fd = cfd;
1954 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01001955 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01001956 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01001957
1958 s->logs.logwait = p->to_log;
1959 s->logs.tv_accept = now;
1960 s->logs.t_request = -1;
1961 s->logs.t_connect = -1;
1962 s->logs.t_data = -1;
1963 s->logs.t_close = 0;
1964 s->logs.uri = NULL;
1965 s->logs.status = -1;
1966 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001967
willy tarreau5cbea6f2005-12-17 12:48:26 +01001968 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1969 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01001970 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001971 unsigned char *pn, *sn;
1972 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01001973
willy tarreau5cbea6f2005-12-17 12:48:26 +01001974 namelen = sizeof(sockname);
1975 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1976 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1977 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01001978 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001979
willy tarreau9fe663a2005-12-17 13:02:59 +01001980 if (p->to_log) {
1981 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01001982 if (s->logs.logwait & LW_CLIP)
1983 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01001984 sess_log(s);
1985 }
1986 else
1987 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1988 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1989 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1990 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01001991 }
willy tarreau0f7af912005-12-17 12:21:26 +01001992
willy tarreau9fe663a2005-12-17 13:02:59 +01001993 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreauef900ab2005-12-17 12:52:52 +01001994 int len;
1995 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1996 write(1, trash, len);
1997 }
willy tarreau0f7af912005-12-17 12:21:26 +01001998
willy tarreau5cbea6f2005-12-17 12:48:26 +01001999 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
2000 close(cfd); /* nothing can be done for this fd without memory */
2001 pool_free(task, t);
2002 pool_free(session, s);
2003 return 0;
2004 }
2005 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002006 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002007 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2008 s->req->rlim = s->req->data + BUFSIZE;
2009 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
2010 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002011
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2013 pool_free(buffer, s->req);
2014 close(cfd); /* nothing can be done for this fd without memory */
2015 pool_free(task, t);
2016 pool_free(session, s);
2017 return 0;
2018 }
2019 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002020 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002021 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 +01002022
willy tarreau5cbea6f2005-12-17 12:48:26 +01002023 fdtab[cfd].read = &event_cli_read;
2024 fdtab[cfd].write = &event_cli_write;
2025 fdtab[cfd].owner = t;
2026 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002027
willy tarreau5cbea6f2005-12-17 12:48:26 +01002028 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01002029 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002030 }
2031 else {
2032 FD_SET(cfd, StaticReadEvent);
2033 }
2034
2035 fd_insert(cfd);
2036
2037 tv_eternity(&s->cnexpire);
2038 tv_eternity(&s->srexpire);
2039 tv_eternity(&s->swexpire);
2040 tv_eternity(&s->cwexpire);
2041
2042 if (s->proxy->clitimeout)
2043 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2044 else
2045 tv_eternity(&s->crexpire);
2046
2047 t->expire = s->crexpire;
2048
2049 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002050
2051 if (p->mode != PR_MODE_HEALTH)
2052 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002053
2054 p->nbconn++;
2055 actconn++;
2056 totalconn++;
2057
2058 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2059 } /* end of while (p->nbconn < p->maxconn) */
2060 return 0;
2061}
willy tarreau0f7af912005-12-17 12:21:26 +01002062
willy tarreau0f7af912005-12-17 12:21:26 +01002063
willy tarreau5cbea6f2005-12-17 12:48:26 +01002064/*
2065 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002066 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2067 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002068 * or -1 if an error occured.
2069 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002070int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002071 struct task *t = fdtab[fd].owner;
2072 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002073
willy tarreau5cbea6f2005-12-17 12:48:26 +01002074 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002075 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002076 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2077 if (skerr)
2078 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002079 else {
2080 if (s->proxy->options & PR_O_HTTP_CHK) {
2081 int ret;
2082 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
2083 * so we'll send the request, and won't wake the checker up now.
2084 */
2085#ifndef MSG_NOSIGNAL
2086 ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT);
2087#else
2088 ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT | MSG_NOSIGNAL);
2089#endif
2090 if (ret == 22) {
2091 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2092 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2093 return 0;
2094 }
2095 else
2096 s->result = -1;
2097 }
2098 else {
2099 /* good TCP connection is enough */
2100 s->result = 1;
2101 }
2102 }
2103
2104 task_wakeup(&rq, t);
2105 return 0;
2106}
2107
willy tarreau0f7af912005-12-17 12:21:26 +01002108
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002109/*
2110 * This function is used only for server health-checks. It handles
2111 * the server's reply to an HTTP request. It returns 1 if the server replies
2112 * 2xx or 3xx (valid responses), or -1 in other cases.
2113 */
2114int event_srv_chk_r(int fd) {
2115 char reply[64];
2116 int len;
2117 struct task *t = fdtab[fd].owner;
2118 struct server *s = t->context;
2119
2120 int skerr, lskerr;
2121 lskerr = sizeof(skerr);
2122 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2123 s->result = -1;
2124 if (!skerr) {
2125#ifndef MSG_NOSIGNAL
2126 len = recv(fd, reply, sizeof(reply), 0);
2127#else
2128 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
2129#endif
2130 if ((len >= sizeof("HTTP/1.0 000")) &&
2131 !memcmp(reply, "HTTP/1.", 7) &&
2132 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2133 s->result = 1;
2134 }
2135
2136 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002137 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002138 return 0;
2139}
2140
2141
2142/*
2143 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2144 * and moves <end> just after the end of <str>.
2145 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2146 * the shift value (positive or negative) is returned.
2147 * If there's no space left, the move is not done.
2148 *
2149 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002150int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002151 int delta;
2152 int len;
2153
2154 len = strlen(str);
2155 delta = len - (end - pos);
2156
2157 if (delta + b->r >= b->data + BUFSIZE)
2158 return 0; /* no space left */
2159
2160 /* first, protect the end of the buffer */
2161 memmove(end + delta, end, b->data + b->l - end);
2162
2163 /* now, copy str over pos */
2164 memcpy(pos, str,len);
2165
willy tarreau5cbea6f2005-12-17 12:48:26 +01002166 /* we only move data after the displaced zone */
2167 if (b->r > pos) b->r += delta;
2168 if (b->w > pos) b->w += delta;
2169 if (b->h > pos) b->h += delta;
2170 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002171 b->l += delta;
2172
2173 return delta;
2174}
2175
willy tarreau240afa62005-12-17 13:14:35 +01002176/* same except that the string len is given, which allows str to be NULL if
2177 * len is 0.
2178 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002179int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002180 int delta;
2181
2182 delta = len - (end - pos);
2183
2184 if (delta + b->r >= b->data + BUFSIZE)
2185 return 0; /* no space left */
2186
2187 /* first, protect the end of the buffer */
2188 memmove(end + delta, end, b->data + b->l - end);
2189
2190 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002191 if (len)
2192 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002193
willy tarreau5cbea6f2005-12-17 12:48:26 +01002194 /* we only move data after the displaced zone */
2195 if (b->r > pos) b->r += delta;
2196 if (b->w > pos) b->w += delta;
2197 if (b->h > pos) b->h += delta;
2198 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002199 b->l += delta;
2200
2201 return delta;
2202}
2203
2204
2205int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2206 char *old_dst = dst;
2207
2208 while (*str) {
2209 if (*str == '\\') {
2210 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002211 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002212 int len, num;
2213
2214 num = *str - '0';
2215 str++;
2216
2217 if (matches[num].rm_so > -1) {
2218 len = matches[num].rm_eo - matches[num].rm_so;
2219 memcpy(dst, src + matches[num].rm_so, len);
2220 dst += len;
2221 }
2222
2223 }
2224 else if (*str == 'x') {
2225 unsigned char hex1, hex2;
2226 str++;
2227
2228 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2229
2230 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2231 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2232 *dst++ = (hex1<<4) + hex2;
2233 }
2234 else
2235 *dst++ = *str++;
2236 }
2237 else
2238 *dst++ = *str++;
2239 }
2240 *dst = 0;
2241 return dst - old_dst;
2242}
2243
willy tarreau9fe663a2005-12-17 13:02:59 +01002244
willy tarreau0f7af912005-12-17 12:21:26 +01002245/*
2246 * manages the client FSM and its socket. BTW, it also tries to handle the
2247 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2248 * 0 else.
2249 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002250int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002251 int s = t->srv_state;
2252 int c = t->cli_state;
2253 struct buffer *req = t->req;
2254 struct buffer *rep = t->rep;
2255
willy tarreau750a4722005-12-17 13:21:24 +01002256#ifdef DEBUG_FULL
2257 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2258#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002259 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2260 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2261 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2262 //);
2263 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002264 /* now parse the partial (or complete) headers */
2265 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2266 char *ptr;
2267 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002268
willy tarreau5cbea6f2005-12-17 12:48:26 +01002269 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002270
willy tarreau0f7af912005-12-17 12:21:26 +01002271 /* look for the end of the current header */
2272 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2273 ptr++;
2274
willy tarreau5cbea6f2005-12-17 12:48:26 +01002275 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002276 int line, len;
2277 /* we can only get here after an end of headers */
2278 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002279
willy tarreaue39cd132005-12-17 13:00:18 +01002280 if (t->flags & SN_CLDENY) {
2281 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002282 t->logs.status = 403;
willy tarreau750a4722005-12-17 13:21:24 +01002283 if (t->proxy->mode == PR_MODE_HTTP)
2284 client_retnclose(t, strlen(HTTP_403), HTTP_403);
willy tarreaue39cd132005-12-17 13:00:18 +01002285 return 1;
2286 }
2287
willy tarreau5cbea6f2005-12-17 12:48:26 +01002288 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002289 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2290 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002291 }
willy tarreau0f7af912005-12-17 12:21:26 +01002292
willy tarreau9fe663a2005-12-17 13:02:59 +01002293 if (t->proxy->options & PR_O_FWDFOR) {
2294 /* insert an X-Forwarded-For header */
2295 unsigned char *pn;
2296 pn = (unsigned char *)&t->cli_addr.sin_addr;
willy tarreau750a4722005-12-17 13:21:24 +01002297 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01002298 pn[0], pn[1], pn[2], pn[3]);
willy tarreau750a4722005-12-17 13:21:24 +01002299 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau9fe663a2005-12-17 13:02:59 +01002300 }
2301
willy tarreaucd878942005-12-17 13:27:43 +01002302 if (!memcmp(req->data, "POST ", 5))
2303 t->flags |= SN_POST; /* this is a POST request */
2304
willy tarreau5cbea6f2005-12-17 12:48:26 +01002305 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002306 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002307
willy tarreau750a4722005-12-17 13:21:24 +01002308 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002309 /* FIXME: we'll set the client in a wait state while we try to
2310 * connect to the server. Is this really needed ? wouldn't it be
2311 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002312 //FD_CLR(t->cli_fd, StaticReadEvent);
2313 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002314 break;
2315 }
willy tarreau0f7af912005-12-17 12:21:26 +01002316
willy tarreau5cbea6f2005-12-17 12:48:26 +01002317 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2318 if (ptr > req->r - 2) {
2319 /* this is a partial header, let's wait for more to come */
2320 req->lr = ptr;
2321 break;
2322 }
willy tarreau0f7af912005-12-17 12:21:26 +01002323
willy tarreau5cbea6f2005-12-17 12:48:26 +01002324 /* now we know that *ptr is either \r or \n,
2325 * and that there are at least 1 char after it.
2326 */
2327 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2328 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2329 else
2330 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002331
willy tarreau5cbea6f2005-12-17 12:48:26 +01002332 /*
2333 * now we know that we have a full header ; we can do whatever
2334 * we want with these pointers :
2335 * req->h = beginning of header
2336 * ptr = end of header (first \r or \n)
2337 * req->lr = beginning of next line (next rep->h)
2338 * req->r = end of data (not used at this stage)
2339 */
willy tarreau0f7af912005-12-17 12:21:26 +01002340
willy tarreaua1598082005-12-17 13:08:06 +01002341 if (t->logs.logwait & LW_REQ &&
2342 t->proxy->mode & PR_MODE_HTTP) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002343 /* we have a complete HTTP request that we must log */
2344 int urilen;
2345
willy tarreaua1598082005-12-17 13:08:06 +01002346 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002347 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002348 t->logs.status = 500;
2349 if (t->proxy->mode == PR_MODE_HTTP)
2350 client_retnclose(t, strlen(HTTP_500), HTTP_500);
willy tarreau9fe663a2005-12-17 13:02:59 +01002351 return 1;
2352 }
2353
2354 urilen = ptr - req->h;
2355 if (urilen >= REQURI_LEN)
2356 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002357 memcpy(t->logs.uri, req->h, urilen);
2358 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002359
willy tarreaua1598082005-12-17 13:08:06 +01002360 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002361 sess_log(t);
2362 }
2363
willy tarreau5cbea6f2005-12-17 12:48:26 +01002364 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002365
willy tarreau9fe663a2005-12-17 13:02:59 +01002366 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002367 int len, max;
2368 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2369 max = ptr - req->h;
2370 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002371 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002372 trash[len++] = '\n';
2373 write(1, trash, len);
2374 }
willy tarreau0f7af912005-12-17 12:21:26 +01002375
willy tarreau5cbea6f2005-12-17 12:48:26 +01002376 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002377 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2378 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002379 char term;
2380
2381 term = *ptr;
2382 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002383 exp = t->proxy->req_exp;
2384 do {
2385 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2386 switch (exp->action) {
2387 case ACT_ALLOW:
2388 if (!(t->flags & SN_CLDENY))
2389 t->flags |= SN_CLALLOW;
2390 break;
2391 case ACT_REPLACE:
2392 if (!(t->flags & SN_CLDENY)) {
2393 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2394 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2395 }
2396 break;
2397 case ACT_REMOVE:
2398 if (!(t->flags & SN_CLDENY))
2399 delete_header = 1;
2400 break;
2401 case ACT_DENY:
2402 if (!(t->flags & SN_CLALLOW))
2403 t->flags |= SN_CLDENY;
2404 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002405 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002406 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002407 }
willy tarreaue39cd132005-12-17 13:00:18 +01002408 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002409 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002410 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002411
willy tarreau240afa62005-12-17 13:14:35 +01002412 /* Now look for cookies. Conforming to RFC2109, we have to support
2413 * attributes whose name begin with a '$', and associate them with
2414 * the right cookie, if we want to delete this cookie.
2415 * So there are 3 cases for each cookie read :
2416 * 1) it's a special attribute, beginning with a '$' : ignore it.
2417 * 2) it's a server id cookie that we *MAY* want to delete : save
2418 * some pointers on it (last semi-colon, beginning of cookie...)
2419 * 3) it's an application cookie : we *MAY* have to delete a previous
2420 * "special" cookie.
2421 * At the end of loop, if a "special" cookie remains, we may have to
2422 * remove it. If no application cookie persists in the header, we
2423 * *MUST* delete it
2424 */
2425 if (!delete_header && (t->proxy->cookie_name != NULL)
2426 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002427 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
2428 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002429 char *del_colon, *del_cookie, *colon;
2430 int app_cookies;
2431
willy tarreau5cbea6f2005-12-17 12:48:26 +01002432 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002433 colon = p1;
2434 /* del_cookie == NULL => nothing to be deleted */
2435 del_colon = del_cookie = NULL;
2436 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002437
2438 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002439 /* skip spaces and colons, but keep an eye on these ones */
2440 while (p1 < ptr) {
2441 if (*p1 == ';' || *p1 == ',')
2442 colon = p1;
2443 else if (!isspace((int)*p1))
2444 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002445 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002446 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002447
2448 if (p1 == ptr)
2449 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002450
2451 /* p1 is at the beginning of the cookie name */
2452 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002453 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002454 p2++;
2455
2456 if (p2 == ptr)
2457 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002458
2459 p3 = p2 + 1; /* skips the '=' sign */
2460 if (p3 == ptr)
2461 break;
2462
willy tarreau240afa62005-12-17 13:14:35 +01002463 p4 = p3;
2464 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002465 p4++;
2466
2467 /* here, we have the cookie name between p1 and p2,
2468 * and its value between p3 and p4.
2469 * we can process it.
2470 */
2471
willy tarreau240afa62005-12-17 13:14:35 +01002472 if (*p1 == '$') {
2473 /* skip this one */
2474 }
2475 else if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2476 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002477 /* Cool... it's the right one */
2478 struct server *srv = t->proxy->srv;
2479
2480 while (srv &&
2481 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2482 srv = srv->next;
2483 }
2484
2485 if (srv) { /* we found the server */
willy tarreaue39cd132005-12-17 13:00:18 +01002486 t->flags |= SN_DIRECT;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002487 t->srv = srv;
2488 }
willy tarreau240afa62005-12-17 13:14:35 +01002489 /* if this cookie was set in insert+indirect mode, then it's better that the
2490 * server never sees it.
2491 */
2492 if (del_cookie == NULL &&
2493 (t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
2494 del_cookie = p1;
2495 del_colon = colon;
2496 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002497 }
2498 else {
willy tarreau240afa62005-12-17 13:14:35 +01002499 /* now we know that we must keep this cookie since it's
2500 * not ours. But if we wanted to delete our cookie
2501 * earlier, we cannot remove the complete header, but we
2502 * can remove the previous block itself.
2503 */
2504 app_cookies++;
2505
2506 if (del_cookie != NULL) {
2507 buffer_replace2(req, del_cookie, p1, NULL, 0);
2508 p4 -= (p1 - del_cookie);
2509 ptr -= (p1 - del_cookie);
2510 del_cookie = del_colon = NULL;
2511 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002512 }
willy tarreau240afa62005-12-17 13:14:35 +01002513
willy tarreau5cbea6f2005-12-17 12:48:26 +01002514 /* we'll have to look for another cookie ... */
2515 p1 = p4;
2516 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002517
2518 /* There's no more cookie on this line.
2519 * We may have marked the last one(s) for deletion.
2520 * We must do this now in two ways :
2521 * - if there is no app cookie, we simply delete the header ;
2522 * - if there are app cookies, we must delete the end of the
2523 * string properly, including the colon/semi-colon before
2524 * the cookie name.
2525 */
2526 if (del_cookie != NULL) {
2527 if (app_cookies) {
2528 buffer_replace2(req, del_colon, ptr, NULL, 0);
2529 /* WARNING! <ptr> becomes invalid for now. If some code
2530 * below needs to rely on it before the end of the global
2531 * header loop, we need to correct it with this code :
2532 * ptr = del_colon;
2533 */
2534 }
2535 else
2536 delete_header = 1;
2537 }
2538 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002539
2540 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002541 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002542 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002543 }
willy tarreau240afa62005-12-17 13:14:35 +01002544 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2545
willy tarreau5cbea6f2005-12-17 12:48:26 +01002546 req->h = req->lr;
2547 } /* while (req->lr < req->r) */
2548
2549 /* end of header processing (even if incomplete) */
2550
willy tarreauef900ab2005-12-17 12:52:52 +01002551 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2552 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2553 * full. We cannot loop here since event_cli_read will disable it only if
2554 * req->l == rlim-data
2555 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002556 FD_SET(t->cli_fd, StaticReadEvent);
2557 if (t->proxy->clitimeout)
2558 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2559 else
2560 tv_eternity(&t->crexpire);
2561 }
2562
willy tarreaue39cd132005-12-17 13:00:18 +01002563 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002564 * won't be able to free more later, so the session will never terminate.
2565 */
willy tarreaue39cd132005-12-17 13:00:18 +01002566 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002567 t->logs.status = 400;
willy tarreau750a4722005-12-17 13:21:24 +01002568 if (t->proxy->mode == PR_MODE_HTTP)
2569 client_retnclose(t, strlen(HTTP_400), HTTP_400);
willy tarreaue39cd132005-12-17 13:00:18 +01002570 return 1;
2571 }
2572 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2573 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2574
2575 /* read timeout, read error, or last read : give up.
2576 * since we are in header mode, if there's no space left for headers, we
2577 * won't be able to free more later, so the session will never terminate.
2578 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002579 tv_eternity(&t->crexpire);
2580 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002581 t->cli_state = CL_STCLOSE;
2582 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002583 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002584
2585 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002586 }
2587 else if (c == CL_STDATA) {
2588 /* read or write error */
2589 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002590 tv_eternity(&t->crexpire);
2591 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002592 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002593 t->cli_state = CL_STCLOSE;
2594 return 1;
2595 }
2596 /* read timeout, last read, or end of server write */
2597 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2598 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002599 FD_CLR(t->cli_fd, StaticReadEvent);
2600 // if (req->l == 0) /* nothing to write on the server side */
2601 // FD_CLR(t->srv_fd, StaticWriteEvent);
2602 tv_eternity(&t->crexpire);
2603 shutdown(t->cli_fd, SHUT_RD);
2604 t->cli_state = CL_STSHUTR;
2605 return 1;
2606 }
2607 /* write timeout, or last server read and buffer empty */
2608 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2609 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002610 FD_CLR(t->cli_fd, StaticWriteEvent);
2611 tv_eternity(&t->cwexpire);
2612 shutdown(t->cli_fd, SHUT_WR);
2613 t->cli_state = CL_STSHUTW;
2614 return 1;
2615 }
2616
willy tarreauef900ab2005-12-17 12:52:52 +01002617 if (req->l >= req->rlim - req->data) {
2618 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002619 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002620 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002621 FD_CLR(t->cli_fd, StaticReadEvent);
2622 tv_eternity(&t->crexpire);
2623 }
2624 }
2625 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002626 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002627 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2628 FD_SET(t->cli_fd, StaticReadEvent);
2629 if (t->proxy->clitimeout)
2630 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2631 else
2632 tv_eternity(&t->crexpire);
2633 }
2634 }
2635
2636 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002637 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002638 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2639 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2640 tv_eternity(&t->cwexpire);
2641 }
2642 }
2643 else { /* buffer not empty */
2644 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2645 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2646 if (t->proxy->clitimeout)
2647 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2648 else
2649 tv_eternity(&t->cwexpire);
2650 }
2651 }
2652 return 0; /* other cases change nothing */
2653 }
2654 else if (c == CL_STSHUTR) {
2655 if ((t->res_cw == RES_ERROR) ||
2656 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002657 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002658 tv_eternity(&t->cwexpire);
2659 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002660 t->cli_state = CL_STCLOSE;
2661 return 1;
2662 }
2663 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002664 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002665 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2666 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2667 tv_eternity(&t->cwexpire);
2668 }
2669 }
2670 else { /* buffer not empty */
2671 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2672 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2673 if (t->proxy->clitimeout)
2674 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2675 else
2676 tv_eternity(&t->cwexpire);
2677 }
2678 }
2679 return 0;
2680 }
2681 else if (c == CL_STSHUTW) {
2682 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002683 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002684 tv_eternity(&t->crexpire);
2685 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002686 t->cli_state = CL_STCLOSE;
2687 return 1;
2688 }
willy tarreauef900ab2005-12-17 12:52:52 +01002689 else if (req->l >= req->rlim - req->data) {
2690 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002691 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002692 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002693 FD_CLR(t->cli_fd, StaticReadEvent);
2694 tv_eternity(&t->crexpire);
2695 }
2696 }
2697 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002698 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002699 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2700 FD_SET(t->cli_fd, StaticReadEvent);
2701 if (t->proxy->clitimeout)
2702 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2703 else
2704 tv_eternity(&t->crexpire);
2705 }
2706 }
2707 return 0;
2708 }
2709 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002710 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002711 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002712 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002713 write(1, trash, len);
2714 }
2715 return 0;
2716 }
2717 return 0;
2718}
2719
2720
2721/*
2722 * manages the server FSM and its socket. It returns 1 if a state has changed
2723 * (and a resync may be needed), 0 else.
2724 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002725int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002726 int s = t->srv_state;
2727 int c = t->cli_state;
2728 struct buffer *req = t->req;
2729 struct buffer *rep = t->rep;
2730
willy tarreau750a4722005-12-17 13:21:24 +01002731#ifdef DEBUG_FULL
2732 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2733#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002734 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2735 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2736 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2737 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002738 if (s == SV_STIDLE) {
2739 if (c == CL_STHEADERS)
2740 return 0; /* stay in idle, waiting for data to reach the client side */
2741 else if (c == CL_STCLOSE ||
2742 c == CL_STSHUTW ||
2743 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2744 tv_eternity(&t->cnexpire);
2745 t->srv_state = SV_STCLOSE;
2746 return 1;
2747 }
2748 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002749 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002750 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2751 t->srv_state = SV_STCONN;
2752 }
2753 else { /* try again */
2754 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002755 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002756 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002757 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2758 }
2759
2760 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002761 t->srv_state = SV_STCONN;
2762 break;
2763 }
2764 }
2765 if (t->conn_retries < 0) {
2766 /* if conn_retries < 0 or other error, let's abort */
2767 tv_eternity(&t->cnexpire);
2768 t->srv_state = SV_STCLOSE;
willy tarreaua1598082005-12-17 13:08:06 +01002769 t->logs.status = 502;
willy tarreau750a4722005-12-17 13:21:24 +01002770 if (t->proxy->mode == PR_MODE_HTTP)
2771 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002772 }
2773 }
2774 return 1;
2775 }
2776 }
2777 else if (s == SV_STCONN) { /* connection in progress */
2778 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2779 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2780 return 0; /* nothing changed */
2781 }
2782 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2783 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2784 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002785 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002786 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002787 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002788 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002789 if (t->conn_retries >= 0) {
2790 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002791 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002792 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2793 }
2794 if (connect_server(t) == 0)
2795 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002796 }
2797 /* if conn_retries < 0 or other error, let's abort */
2798 tv_eternity(&t->cnexpire);
2799 t->srv_state = SV_STCLOSE;
willy tarreau750a4722005-12-17 13:21:24 +01002800 t->logs.status = 502;
2801 if (t->proxy->mode == PR_MODE_HTTP)
2802 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002803 return 1;
2804 }
2805 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01002806 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01002807
willy tarreau0f7af912005-12-17 12:21:26 +01002808 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2809 if (req->l == 0) /* nothing to write */
2810 FD_CLR(t->srv_fd, StaticWriteEvent);
2811 else /* need the right to write */
2812 FD_SET(t->srv_fd, StaticWriteEvent);
2813
2814 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2815 FD_SET(t->srv_fd, StaticReadEvent);
2816 if (t->proxy->srvtimeout)
2817 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2818 else
2819 tv_eternity(&t->srexpire);
2820
2821 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002822 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002823 }
willy tarreauef900ab2005-12-17 12:52:52 +01002824 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002825 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002826 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2827 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002828 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002829 return 1;
2830 }
2831 }
2832 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002833
2834 /* now parse the partial (or complete) headers */
2835 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2836 char *ptr;
2837 int delete_header;
2838
2839 ptr = rep->lr;
2840
2841 /* look for the end of the current header */
2842 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2843 ptr++;
2844
2845 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002846 int line, len;
2847
2848 /* we can only get here after an end of headers */
2849 /* we'll have something else to do here : add new headers ... */
2850
willy tarreaucd878942005-12-17 13:27:43 +01002851 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
2852 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002853 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01002854 * insert a set-cookie here, except if we want to insert only on POST
2855 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01002856 */
willy tarreau750a4722005-12-17 13:21:24 +01002857 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01002858 t->proxy->cookie_name, t->srv->cookie);
willy tarreau750a4722005-12-17 13:21:24 +01002859
2860 /* Here, we will tell an eventual cache on the client side that we don't
2861 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
2862 * Some caches understand the correct form: 'no-cache="set-cookie"', but
2863 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
2864 */
willy tarreau240afa62005-12-17 13:14:35 +01002865 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01002866 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
2867 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01002868
willy tarreau750a4722005-12-17 13:21:24 +01002869 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002870 }
2871
2872 /* headers to be added */
2873 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002874 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
2875 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002876 }
2877
2878 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002879 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01002880 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002881 break;
2882 }
2883
2884 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2885 if (ptr > rep->r - 2) {
2886 /* this is a partial header, let's wait for more to come */
2887 rep->lr = ptr;
2888 break;
2889 }
2890
2891 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2892 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2893
2894 /* now we know that *ptr is either \r or \n,
2895 * and that there are at least 1 char after it.
2896 */
2897 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2898 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2899 else
2900 rep->lr = ptr + 2; /* \r\n or \n\r */
2901
2902 /*
2903 * now we know that we have a full header ; we can do whatever
2904 * we want with these pointers :
2905 * rep->h = beginning of header
2906 * ptr = end of header (first \r or \n)
2907 * rep->lr = beginning of next line (next rep->h)
2908 * rep->r = end of data (not used at this stage)
2909 */
2910
willy tarreaua1598082005-12-17 13:08:06 +01002911
2912 if (t->logs.logwait & LW_RESP) {
2913 t->logs.logwait &= ~LW_RESP;
2914 t->logs.status = atoi(rep->h + 9);
2915 }
2916
willy tarreau5cbea6f2005-12-17 12:48:26 +01002917 delete_header = 0;
2918
willy tarreau9fe663a2005-12-17 13:02:59 +01002919 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002920 int len, max;
2921 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2922 max = ptr - rep->h;
2923 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002924 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002925 trash[len++] = '\n';
2926 write(1, trash, len);
2927 }
2928
2929 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002930 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
2931 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002932 char term;
2933
2934 term = *ptr;
2935 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002936 exp = t->proxy->rsp_exp;
2937 do {
2938 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2939 switch (exp->action) {
2940 case ACT_ALLOW:
2941 if (!(t->flags & SN_SVDENY))
2942 t->flags |= SN_SVALLOW;
2943 break;
2944 case ACT_REPLACE:
2945 if (!(t->flags & SN_SVDENY)) {
2946 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2947 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2948 }
2949 break;
2950 case ACT_REMOVE:
2951 if (!(t->flags & SN_SVDENY))
2952 delete_header = 1;
2953 break;
2954 case ACT_DENY:
2955 if (!(t->flags & SN_SVALLOW))
2956 t->flags |= SN_SVDENY;
2957 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002958 }
2959 break;
2960 }
willy tarreaue39cd132005-12-17 13:00:18 +01002961 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002962 *ptr = term; /* restore the string terminator */
2963 }
2964
2965 /* check for server cookies */
willy tarreau240afa62005-12-17 13:14:35 +01002966 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY)
2967 && (t->proxy->cookie_name != NULL) && (ptr >= rep->h + 12)
2968 && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002969 char *p1, *p2, *p3, *p4;
2970
2971 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2972
2973 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01002974 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002975 p1++;
2976
2977 if (p1 == ptr || *p1 == ';') /* end of cookie */
2978 break;
2979
2980 /* p1 is at the beginning of the cookie name */
2981 p2 = p1;
2982
2983 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2984 p2++;
2985
2986 if (p2 == ptr || *p2 == ';') /* next cookie */
2987 break;
2988
2989 p3 = p2 + 1; /* skips the '=' sign */
2990 if (p3 == ptr)
2991 break;
2992
2993 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01002994 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002995 p4++;
2996
2997 /* here, we have the cookie name between p1 and p2,
2998 * and its value between p3 and p4.
2999 * we can process it.
3000 */
3001
3002 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
3003 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3004 /* Cool... it's the right one */
3005
3006 /* If the cookie is in insert mode on a known server, we'll delete
3007 * this occurrence because we'll insert another one later.
3008 * We'll delete it too if the "indirect" option is set and we're in
3009 * a direct access. */
3010 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01003011 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003012 /* this header must be deleted */
3013 delete_header = 1;
3014 }
3015 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
3016 /* replace bytes p3->p4 with the cookie name associated
3017 * with this server since we know it.
3018 */
3019 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
3020 }
3021 break;
3022 }
3023 else {
3024 // fprintf(stderr,"Ignoring unknown cookie : ");
3025 // write(2, p1, p2-p1);
3026 // fprintf(stderr," = ");
3027 // write(2, p3, p4-p3);
3028 // fprintf(stderr,"\n");
3029 }
3030 break; /* we don't want to loop again since there cannot be another cookie on the same line */
3031 } /* we're now at the end of the cookie value */
3032 } /* end of cookie processing */
3033
3034 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003035 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003036 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01003037
willy tarreau5cbea6f2005-12-17 12:48:26 +01003038 rep->h = rep->lr;
3039 } /* while (rep->lr < rep->r) */
3040
3041 /* end of header processing (even if incomplete) */
3042
willy tarreauef900ab2005-12-17 12:52:52 +01003043 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3044 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3045 * full. We cannot loop here since event_srv_read will disable it only if
3046 * rep->l == rlim-data
3047 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003048 FD_SET(t->srv_fd, StaticReadEvent);
3049 if (t->proxy->srvtimeout)
3050 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3051 else
3052 tv_eternity(&t->srexpire);
3053 }
willy tarreau0f7af912005-12-17 12:21:26 +01003054
3055 /* read or write error */
3056 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003057 tv_eternity(&t->srexpire);
3058 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003059 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003060 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01003061 t->logs.status = 502;
3062 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01003063 return 1;
3064 }
willy tarreauef900ab2005-12-17 12:52:52 +01003065 /* read timeout, last read, or end of client write
3066 * since we are in header mode, if there's no space left for headers, we
3067 * won't be able to free more later, so the session will never terminate.
3068 */
3069 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
3070 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003071 FD_CLR(t->srv_fd, StaticReadEvent);
3072 tv_eternity(&t->srexpire);
3073 shutdown(t->srv_fd, SHUT_RD);
3074 t->srv_state = SV_STSHUTR;
3075 return 1;
3076
3077 }
3078 /* write timeout, or last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003079 /* FIXME!!! here, we don't want to switch to SHUTW if the
3080 * client shuts read too early, because we may still have
3081 * some work to do on the headers.
3082 */
3083 else if (((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) ||
willy tarreau0f7af912005-12-17 12:21:26 +01003084 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
3085 FD_CLR(t->srv_fd, StaticWriteEvent);
3086 tv_eternity(&t->swexpire);
3087 shutdown(t->srv_fd, SHUT_WR);
3088 t->srv_state = SV_STSHUTW;
3089 return 1;
3090 }
3091
3092 if (req->l == 0) {
3093 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3094 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3095 tv_eternity(&t->swexpire);
3096 }
3097 }
3098 else { /* client buffer not empty */
3099 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3100 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3101 if (t->proxy->srvtimeout)
3102 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3103 else
3104 tv_eternity(&t->swexpire);
3105 }
3106 }
3107
willy tarreau5cbea6f2005-12-17 12:48:26 +01003108 /* be nice with the client side which would like to send a complete header
3109 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3110 * would read all remaining data at once ! The client should not write past rep->lr
3111 * when the server is in header state.
3112 */
3113 //return header_processed;
3114 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003115 }
3116 else if (s == SV_STDATA) {
3117 /* read or write error */
3118 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003119 tv_eternity(&t->srexpire);
3120 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003121 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003122 t->srv_state = SV_STCLOSE;
3123 return 1;
3124 }
3125 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01003126 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
3127 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003128 FD_CLR(t->srv_fd, StaticReadEvent);
3129 tv_eternity(&t->srexpire);
3130 shutdown(t->srv_fd, SHUT_RD);
3131 t->srv_state = SV_STSHUTR;
3132 return 1;
3133
3134 }
3135 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01003136 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
3137 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003138 FD_CLR(t->srv_fd, StaticWriteEvent);
3139 tv_eternity(&t->swexpire);
3140 shutdown(t->srv_fd, SHUT_WR);
3141 t->srv_state = SV_STSHUTW;
3142 return 1;
3143 }
3144 else if (req->l == 0) {
3145 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3146 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3147 tv_eternity(&t->swexpire);
3148 }
3149 }
3150 else { /* buffer not empty */
3151 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3152 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3153 if (t->proxy->srvtimeout)
3154 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3155 else
3156 tv_eternity(&t->swexpire);
3157 }
3158 }
3159
3160 if (rep->l == BUFSIZE) { /* no room to read more data */
3161 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3162 FD_CLR(t->srv_fd, StaticReadEvent);
3163 tv_eternity(&t->srexpire);
3164 }
3165 }
3166 else {
3167 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3168 FD_SET(t->srv_fd, StaticReadEvent);
3169 if (t->proxy->srvtimeout)
3170 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3171 else
3172 tv_eternity(&t->srexpire);
3173 }
3174 }
3175
3176 return 0; /* other cases change nothing */
3177 }
3178 else if (s == SV_STSHUTR) {
3179 if ((t->res_sw == RES_ERROR) ||
3180 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
3181 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003182 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003183 tv_eternity(&t->swexpire);
3184 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003185 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003186 t->srv_state = SV_STCLOSE;
3187 return 1;
3188 }
3189 else if (req->l == 0) {
3190 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3191 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3192 tv_eternity(&t->swexpire);
3193 }
3194 }
3195 else { /* buffer not empty */
3196 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3197 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3198 if (t->proxy->srvtimeout)
3199 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3200 else
3201 tv_eternity(&t->swexpire);
3202 }
3203 }
3204 return 0;
3205 }
3206 else if (s == SV_STSHUTW) {
3207 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
3208 c == CL_STSHUTW || c == CL_STCLOSE ||
3209 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003210 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003211 tv_eternity(&t->srexpire);
3212 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003213 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003214 t->srv_state = SV_STCLOSE;
3215 return 1;
3216 }
3217 else if (rep->l == BUFSIZE) { /* no room to read more data */
3218 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3219 FD_CLR(t->srv_fd, StaticReadEvent);
3220 tv_eternity(&t->srexpire);
3221 }
3222 }
3223 else {
3224 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3225 FD_SET(t->srv_fd, StaticReadEvent);
3226 if (t->proxy->srvtimeout)
3227 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3228 else
3229 tv_eternity(&t->srexpire);
3230 }
3231 }
3232 return 0;
3233 }
3234 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003235 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003236 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003237 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003238 write(1, trash, len);
3239 }
3240 return 0;
3241 }
3242 return 0;
3243}
3244
3245
willy tarreau5cbea6f2005-12-17 12:48:26 +01003246/* Processes the client and server jobs of a session task, then
3247 * puts it back to the wait queue in a clean state, or
3248 * cleans up its resources if it must be deleted. Returns
3249 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003250 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003251int process_session(struct task *t) {
3252 struct session *s = t->context;
3253 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003254
willy tarreau5cbea6f2005-12-17 12:48:26 +01003255 do {
3256 fsm_resync = 0;
3257 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3258 fsm_resync |= process_cli(s);
3259 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3260 fsm_resync |= process_srv(s);
3261 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3262 } while (fsm_resync);
3263
3264 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003265 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003266 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003267
willy tarreau5cbea6f2005-12-17 12:48:26 +01003268 tv_min(&min1, &s->crexpire, &s->cwexpire);
3269 tv_min(&min2, &s->srexpire, &s->swexpire);
3270 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003271 tv_min(&t->expire, &min1, &min2);
3272
3273 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003274 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003275
willy tarreau5cbea6f2005-12-17 12:48:26 +01003276 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003277 }
3278
willy tarreau5cbea6f2005-12-17 12:48:26 +01003279 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003280 actconn--;
3281
willy tarreau9fe663a2005-12-17 13:02:59 +01003282 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003283 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003284 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003285 write(1, trash, len);
3286 }
3287
willy tarreau750a4722005-12-17 13:21:24 +01003288 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003289 if (s->rep != NULL)
3290 s->logs.bytes = s->rep->total;
3291
willy tarreau9fe663a2005-12-17 13:02:59 +01003292 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003293 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003294 sess_log(s);
3295
willy tarreau0f7af912005-12-17 12:21:26 +01003296 /* the task MUST not be in the run queue anymore */
3297 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003298 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003299 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003300 return -1; /* rest in peace for eternity */
3301}
3302
3303
3304
3305/*
3306 * manages a server health-check. Returns
3307 * the time the task accepts to wait, or -1 for infinity.
3308 */
3309int process_chk(struct task *t) {
3310 struct server *s = t->context;
3311 int fd = s->curfd;
3312 int one = 1;
3313
willy tarreauef900ab2005-12-17 12:52:52 +01003314 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003315
3316 if (fd < 0) { /* no check currently running */
3317 //fprintf(stderr, "process_chk: 2\n");
3318 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3319 task_queue(t); /* restore t to its place in the task list */
3320 return tv_remain(&now, &t->expire);
3321 }
3322
3323 /* we'll initiate a new check */
3324 s->result = 0; /* no result yet */
3325 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003326 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003327 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3328 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3329 //fprintf(stderr, "process_chk: 3\n");
3330
3331 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
3332 /* OK, connection in progress or established */
3333
3334 //fprintf(stderr, "process_chk: 4\n");
3335
3336 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3337 fdtab[fd].owner = t;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003338 fdtab[fd].read = &event_srv_chk_r;
3339 fdtab[fd].write = &event_srv_chk_w;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003340 fdtab[fd].state = FD_STCONN; /* connection in progress */
3341 FD_SET(fd, StaticWriteEvent); /* for connect status */
3342 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003343 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3344 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003345 task_queue(t); /* restore t to its place in the task list */
3346 return tv_remain(&now, &t->expire);
3347 }
3348 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3349 s->result = -1; /* a real error */
3350 }
3351 }
3352 //fprintf(stderr, "process_chk: 5\n");
3353 close(fd);
3354 }
3355
3356 if (!s->result) { /* nothing done */
3357 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003358 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003359 task_queue(t); /* restore t to its place in the task list */
3360 return tv_remain(&now, &t->expire);
3361 }
3362
3363 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003364 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003365 s->health--; /* still good */
3366 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003367 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003368 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003369 Warning("server %s DOWN.\n", s->id);
3370
willy tarreau9fe663a2005-12-17 13:02:59 +01003371 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003372 }
willy tarreauef900ab2005-12-17 12:52:52 +01003373
willy tarreau5cbea6f2005-12-17 12:48:26 +01003374 s->health = 0; /* failure */
3375 s->state &= ~SRV_RUNNING;
3376 }
3377
3378 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003379 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3380 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003381 }
3382 else {
3383 //fprintf(stderr, "process_chk: 8\n");
3384 /* there was a test running */
3385 if (s->result > 0) { /* good server detected */
3386 //fprintf(stderr, "process_chk: 9\n");
3387 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003388 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003389 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003390 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003391 Warning("server %s UP.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003392 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003393 }
willy tarreauef900ab2005-12-17 12:52:52 +01003394
willy tarreaue47c8d72005-12-17 12:55:52 +01003395 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003396 s->state |= SRV_RUNNING;
3397 }
willy tarreauef900ab2005-12-17 12:52:52 +01003398 s->curfd = -1; /* no check running anymore */
3399 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003400 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003401 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003402 }
3403 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3404 //fprintf(stderr, "process_chk: 10\n");
3405 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003406 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003407 s->health--; /* still good */
3408 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003409 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003410 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003411 Warning("server %s DOWN.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003412
3413 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003414 }
willy tarreauef900ab2005-12-17 12:52:52 +01003415
willy tarreau5cbea6f2005-12-17 12:48:26 +01003416 s->health = 0; /* failure */
3417 s->state &= ~SRV_RUNNING;
3418 }
3419 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003420 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003421 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003422 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003423 }
3424 /* if result is 0 and there's no timeout, we have to wait again */
3425 }
3426 //fprintf(stderr, "process_chk: 11\n");
3427 s->result = 0;
3428 task_queue(t); /* restore t to its place in the task list */
3429 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003430}
3431
3432
willy tarreau5cbea6f2005-12-17 12:48:26 +01003433
willy tarreau0f7af912005-12-17 12:21:26 +01003434#if STATTIME > 0
3435int stats(void);
3436#endif
3437
3438/*
3439 * Main select() loop.
3440 */
3441
3442void select_loop() {
3443 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003444 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003445 int status;
3446 int fd,i;
3447 struct timeval delta;
3448 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003449 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003450
willy tarreau5cbea6f2005-12-17 12:48:26 +01003451 tv_now(&now);
3452
3453 while (1) {
3454 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003455
willy tarreau5cbea6f2005-12-17 12:48:26 +01003456 /* look for expired tasks and add them to the run queue.
3457 */
3458 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3459 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3460 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003461 if (t->state & TASK_RUNNING)
3462 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003463
3464 /* wakeup expired entries. It doesn't matter if they are
3465 * already running because of a previous event
3466 */
3467 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003468 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003469 task_wakeup(&rq, t);
3470 }
3471 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003472 /* first non-runnable task. Use its expiration date as an upper bound */
3473 int temp_time = tv_remain(&now, &t->expire);
3474 if (temp_time)
3475 next_time = temp_time;
3476 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003477 break;
3478 }
3479 }
3480
3481 /* process each task in the run queue now. Each task may be deleted
3482 * since we only use tnext.
3483 */
3484 tnext = rq;
3485 while ((t = tnext) != NULL) {
3486 int temp_time;
3487
3488 tnext = t->rqnext;
3489 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003490 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003491 temp_time = t->process(t);
3492 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003493 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003494 }
3495
willy tarreauef900ab2005-12-17 12:52:52 +01003496 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003497
3498 /* maintain all proxies in a consistent state. This should quickly become a task */
3499 time2 = maintain_proxies();
3500 next_time = MINTIME(time2, next_time);
3501
3502 /* stop when there's no connection left and we don't allow them anymore */
3503 if (!actconn && listeners == 0)
3504 break;
3505
willy tarreau0f7af912005-12-17 12:21:26 +01003506
3507#if STATTIME > 0
3508 time2 = stats();
3509 // fprintf(stderr," stats = %d\n", time2);
3510 next_time = MINTIME(time2, next_time);
3511#endif
3512
willy tarreau5cbea6f2005-12-17 12:48:26 +01003513 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003514 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003515 /* to avoid eventual select loops due to timer precision */
3516 next_time += SCHEDULER_RESOLUTION;
3517 delta.tv_sec = next_time / 1000;
3518 delta.tv_usec = (next_time % 1000) * 1000;
3519 }
3520 else if (next_time == 0) { /* allow select to return immediately when needed */
3521 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003522 }
3523
3524
3525 /* let's restore fdset state */
3526
3527 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003528 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003529 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3530 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3531 }
3532
3533// /* just a verification code, needs to be removed for performance */
3534// for (i=0; i<maxfd; i++) {
3535// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3536// abort();
3537// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3538// abort();
3539//
3540// }
3541
3542 status=select(maxfd,
3543 readnotnull ? ReadEvent : NULL,
3544 writenotnull ? WriteEvent : NULL,
3545 NULL,
3546 (next_time >= 0) ? &delta : NULL);
3547
willy tarreau5cbea6f2005-12-17 12:48:26 +01003548 /* this is an experiment on the separation of the select work */
3549 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3550 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3551
willy tarreau0f7af912005-12-17 12:21:26 +01003552 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003553
willy tarreau0f7af912005-12-17 12:21:26 +01003554 if (status > 0) { /* must proceed with events */
3555
3556 int fds;
3557 char count;
3558
3559 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3560 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3561 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3562
willy tarreau5cbea6f2005-12-17 12:48:26 +01003563 /* if we specify read first, the accepts and zero reads will be
3564 * seen first. Moreover, system buffers will be flushed faster.
3565 */
willy tarreau0f7af912005-12-17 12:21:26 +01003566 if (fdtab[fd].state == FD_STCLOSE)
3567 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003568
3569 if (FD_ISSET(fd, ReadEvent))
3570 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003571
willy tarreau5cbea6f2005-12-17 12:48:26 +01003572 if (FD_ISSET(fd, WriteEvent))
3573 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003574 }
3575 }
3576 else {
3577 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3578 }
willy tarreau0f7af912005-12-17 12:21:26 +01003579 }
3580}
3581
3582
3583#if STATTIME > 0
3584/*
3585 * Display proxy statistics regularly. It is designed to be called from the
3586 * select_loop().
3587 */
3588int stats(void) {
3589 static int lines;
3590 static struct timeval nextevt;
3591 static struct timeval lastevt;
3592 static struct timeval starttime = {0,0};
3593 unsigned long totaltime, deltatime;
3594 int ret;
3595
willy tarreau750a4722005-12-17 13:21:24 +01003596 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01003597 deltatime = (tv_diff(&lastevt, &now)?:1);
3598 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01003599
willy tarreau9fe663a2005-12-17 13:02:59 +01003600 if (global.mode & MODE_STATS) {
3601 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003602 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003603 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3604 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003605 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003606 actconn, totalconn,
3607 stats_tsk_new, stats_tsk_good,
3608 stats_tsk_left, stats_tsk_right,
3609 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3610 }
3611 }
3612
3613 tv_delayfrom(&nextevt, &now, STATTIME);
3614
3615 lastevt=now;
3616 }
3617 ret = tv_remain(&now, &nextevt);
3618 return ret;
3619}
3620#endif
3621
3622
3623/*
3624 * this function enables proxies when there are enough free sessions,
3625 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003626 * select_loop(). It returns the time left before next expiration event
3627 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003628 */
3629static int maintain_proxies(void) {
3630 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003631 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003632
3633 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003634 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003635
3636 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003637 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003638 while (p) {
3639 if (p->nbconn < p->maxconn) {
3640 if (p->state == PR_STIDLE) {
3641 FD_SET(p->listen_fd, StaticReadEvent);
3642 p->state = PR_STRUN;
3643 }
3644 }
3645 else {
3646 if (p->state == PR_STRUN) {
3647 FD_CLR(p->listen_fd, StaticReadEvent);
3648 p->state = PR_STIDLE;
3649 }
3650 }
3651 p = p->next;
3652 }
3653 }
3654 else { /* block all proxies */
3655 while (p) {
3656 if (p->state == PR_STRUN) {
3657 FD_CLR(p->listen_fd, StaticReadEvent);
3658 p->state = PR_STIDLE;
3659 }
3660 p = p->next;
3661 }
3662 }
3663
willy tarreau5cbea6f2005-12-17 12:48:26 +01003664 if (stopping) {
3665 p = proxy;
3666 while (p) {
3667 if (p->state != PR_STDISABLED) {
3668 int t;
3669 t = tv_remain(&now, &p->stop_time);
3670 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003671 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003672 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003673
willy tarreau5cbea6f2005-12-17 12:48:26 +01003674 fd_delete(p->listen_fd);
3675 p->state = PR_STDISABLED;
3676 listeners--;
3677 }
3678 else {
3679 tleft = MINTIME(t, tleft);
3680 }
3681 }
3682 p = p->next;
3683 }
3684 }
3685 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003686}
3687
3688/*
3689 * this function disables health-check servers so that the process will quickly be ignored
3690 * by load balancers.
3691 */
3692static void soft_stop(void) {
3693 struct proxy *p;
3694
3695 stopping = 1;
3696 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003697 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003698 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003699 if (p->state != PR_STDISABLED) {
3700 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01003701 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01003702 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01003703 }
willy tarreau0f7af912005-12-17 12:21:26 +01003704 p = p->next;
3705 }
3706}
3707
3708/*
3709 * upon SIGUSR1, let's have a soft stop.
3710 */
3711void sig_soft_stop(int sig) {
3712 soft_stop();
3713 signal(sig, SIG_IGN);
3714}
3715
3716
3717void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003718 struct task *t, *tnext;
3719 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003720
willy tarreau5cbea6f2005-12-17 12:48:26 +01003721 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3722 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3723 tnext = t->next;
3724 s = t->context;
3725 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3726 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3727 "req=%d, rep=%d, clifd=%d\n",
3728 s, tv_remain(&now, &t->expire),
3729 s->cli_state,
3730 s->srv_state,
3731 FD_ISSET(s->cli_fd, StaticReadEvent),
3732 FD_ISSET(s->cli_fd, StaticWriteEvent),
3733 FD_ISSET(s->srv_fd, StaticReadEvent),
3734 FD_ISSET(s->srv_fd, StaticWriteEvent),
3735 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3736 );
willy tarreau0f7af912005-12-17 12:21:26 +01003737 }
3738}
3739
willy tarreaue39cd132005-12-17 13:00:18 +01003740void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
3741 struct hdr_exp *exp;
3742
3743 while (*head != NULL)
3744 head = &(*head)->next;
3745
3746 exp = calloc(1, sizeof(struct hdr_exp));
3747
3748 exp->preg = preg;
3749 exp->replace = replace;
3750 exp->action = action;
3751 *head = exp;
3752}
3753
willy tarreau9fe663a2005-12-17 13:02:59 +01003754
willy tarreau0f7af912005-12-17 12:21:26 +01003755/*
willy tarreau9fe663a2005-12-17 13:02:59 +01003756 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01003757 */
willy tarreau9fe663a2005-12-17 13:02:59 +01003758int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01003759
willy tarreau9fe663a2005-12-17 13:02:59 +01003760 if (!strcmp(args[0], "global")) { /* new section */
3761 /* no option, nothing special to do */
3762 return 0;
3763 }
3764 else if (!strcmp(args[0], "daemon")) {
3765 global.mode |= MODE_DAEMON;
3766 }
3767 else if (!strcmp(args[0], "debug")) {
3768 global.mode |= MODE_DEBUG;
3769 }
3770 else if (!strcmp(args[0], "quiet")) {
3771 global.mode |= MODE_QUIET;
3772 }
3773 else if (!strcmp(args[0], "stats")) {
3774 global.mode |= MODE_STATS;
3775 }
3776 else if (!strcmp(args[0], "uid")) {
3777 if (global.uid != 0) {
3778 Alert("parsing [%s:%d] : <uid> already specified. Continuing.\n", file, linenum);
3779 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003781 if (*(args[1]) == 0) {
3782 Alert("parsing [%s:%d] : <uid> expects an integer argument.\n", file, linenum);
3783 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003784 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003785 global.uid = atol(args[1]);
3786 }
3787 else if (!strcmp(args[0], "gid")) {
3788 if (global.gid != 0) {
3789 Alert("parsing [%s:%d] : <gid> already specified. Continuing.\n", file, linenum);
3790 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003791 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003792 if (*(args[1]) == 0) {
3793 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003794 return -1;
3795 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003796 global.gid = atol(args[1]);
3797 }
3798 else if (!strcmp(args[0], "nbproc")) {
3799 if (global.nbproc != 0) {
3800 Alert("parsing [%s:%d] : <nbproc> already specified. Continuing.\n", file, linenum);
3801 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003802 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003803 if (*(args[1]) == 0) {
3804 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
3805 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003806 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003807 global.nbproc = atol(args[1]);
3808 }
3809 else if (!strcmp(args[0], "maxconn")) {
3810 if (global.maxconn != 0) {
3811 Alert("parsing [%s:%d] : <maxconn> already specified. Continuing.\n", file, linenum);
3812 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003813 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003814 if (*(args[1]) == 0) {
3815 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3816 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003817 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003818 global.maxconn = atol(args[1]);
3819 }
3820 else if (!strcmp(args[0], "chroot")) {
3821 if (global.chroot != NULL) {
3822 Alert("parsing [%s:%d] : <chroot> already specified. Continuing.\n", file, linenum);
3823 return 0;
3824 }
3825 if (*(args[1]) == 0) {
3826 Alert("parsing [%s:%d] : <chroot> expects a directory as an argument.\n", file, linenum);
3827 return -1;
3828 }
3829 global.chroot = strdup(args[1]);
3830 }
3831 else if (!strcmp(args[0], "log")) { /* syslog server address */
3832 struct sockaddr_in *sa;
3833 int facility;
3834
3835 if (*(args[1]) == 0 || *(args[2]) == 0) {
3836 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n", file, linenum);
3837 return -1;
3838 }
3839
3840 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3841 if (!strcmp(log_facilities[facility], args[2]))
3842 break;
3843
3844 if (facility >= NB_LOG_FACILITIES) {
3845 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3846 exit(1);
3847 }
3848
3849 sa = str2sa(args[1]);
3850 if (!sa->sin_port)
3851 sa->sin_port = htons(SYSLOG_PORT);
3852
3853 if (global.logfac1 == -1) {
3854 global.logsrv1 = *sa;
3855 global.logfac1 = facility;
3856 }
3857 else if (global.logfac2 == -1) {
3858 global.logsrv2 = *sa;
3859 global.logfac2 = facility;
3860 }
3861 else {
3862 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3863 return -1;
3864 }
3865
3866 }
3867 else {
3868 Alert("parsing [%s:%d] : unknown keyword <%s> in <global> section\n", file, linenum, args[0]);
3869 return -1;
3870 }
3871 return 0;
3872}
3873
3874
3875/*
3876 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
3877 */
3878int cfg_parse_listen(char *file, int linenum, char **args) {
3879 static struct proxy *curproxy = NULL;
3880 struct server *newsrv = NULL;
3881
3882 if (!strcmp(args[0], "listen")) { /* new proxy */
3883 if (strchr(args[2], ':') == NULL) {
3884 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3885 file, linenum);
3886 return -1;
3887 }
3888
3889 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
3890 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3891 return -1;
3892 }
3893 curproxy->next = proxy;
3894 proxy = curproxy;
3895 curproxy->id = strdup(args[1]);
3896 curproxy->listen_addr = *str2sa(args[2]);
3897 curproxy->state = PR_STNEW;
3898 /* set default values */
3899 curproxy->maxconn = cfg_maxpconn;
3900 curproxy->conn_retries = CONN_RETRIES;
3901 curproxy->options = 0;
3902 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3903 curproxy->mode = PR_MODE_TCP;
3904 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3905 curproxy->to_log = 0;
3906 return 0;
3907 }
3908 else if (curproxy == NULL) {
3909 Alert("parsing [%s:%d] : <listen> expected.\n", file, linenum);
3910 return -1;
3911 }
3912
3913 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3914 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3915 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3916 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3917 else {
3918 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3919 return -1;
3920 }
3921 }
3922 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3923 curproxy->state = PR_STDISABLED;
3924 }
3925 else if (!strcmp(args[0], "cookie")) { /* cookie name */
3926 int cur_arg;
3927 if (curproxy->cookie_name != NULL) {
3928 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3929 file, linenum);
3930 return 0;
3931 }
3932
3933 if (*(args[1]) == 0) {
3934 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3935 file, linenum);
3936 return -1;
3937 }
3938 curproxy->cookie_name = strdup(args[1]);
3939
3940 cur_arg = 2;
3941 while (*(args[cur_arg])) {
3942 if (!strcmp(args[cur_arg], "rewrite")) {
3943 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01003944 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003945 else if (!strcmp(args[cur_arg], "indirect")) {
3946 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01003947 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003948 else if (!strcmp(args[cur_arg], "insert")) {
3949 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01003950 }
willy tarreau240afa62005-12-17 13:14:35 +01003951 else if (!strcmp(args[cur_arg], "nocache")) {
3952 curproxy->options |= PR_O_COOK_NOC;
3953 }
willy tarreaucd878942005-12-17 13:27:43 +01003954 else if (!strcmp(args[cur_arg], "postonly")) {
3955 curproxy->options |= PR_O_COOK_POST;
3956 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003957 else {
willy tarreaucd878942005-12-17 13:27:43 +01003958 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003959 file, linenum);
3960 return -1;
3961 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003962 cur_arg++;
3963 }
3964 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3965 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3966 file, linenum);
3967 return -1;
3968 }
3969 }
3970 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3971 if (curproxy->contimeout != 0) {
3972 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n", file, linenum);
3973 return 0;
3974 }
3975 if (*(args[1]) == 0) {
3976 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3977 file, linenum);
3978 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003979 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003980 curproxy->contimeout = atol(args[1]);
3981 }
3982 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3983 if (curproxy->clitimeout != 0) {
3984 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3985 file, linenum);
3986 return 0;
3987 }
3988 if (*(args[1]) == 0) {
3989 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3990 file, linenum);
3991 return -1;
3992 }
3993 curproxy->clitimeout = atol(args[1]);
3994 }
3995 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3996 if (curproxy->srvtimeout != 0) {
3997 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n", file, linenum);
3998 return 0;
3999 }
4000 if (*(args[1]) == 0) {
4001 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004002 file, linenum);
4003 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004004 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004005 curproxy->srvtimeout = atol(args[1]);
4006 }
4007 else if (!strcmp(args[0], "retries")) { /* connection retries */
4008 if (*(args[1]) == 0) {
4009 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
4010 file, linenum);
4011 return -1;
4012 }
4013 curproxy->conn_retries = atol(args[1]);
4014 }
4015 else if (!strcmp(args[0], "option")) {
4016 if (*(args[1]) == 0) {
4017 Alert("parsing [%s:%d] : <option> expects an option name.\n", file, linenum);
4018 return -1;
4019 }
4020 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004021 /* enable reconnections to dispatch */
4022 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01004023#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004024 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004025 /* enable transparent proxy connections */
4026 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01004027#endif
4028 else if (!strcmp(args[1], "keepalive"))
4029 /* enable keep-alive */
4030 curproxy->options |= PR_O_KEEPALIVE;
4031 else if (!strcmp(args[1], "forwardfor"))
4032 /* insert x-forwarded-for field */
4033 curproxy->options |= PR_O_FWDFOR;
4034 else if (!strcmp(args[1], "httplog")) {
4035 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01004036 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
4037 }
4038 else if (!strcmp(args[1], "dontlognull")) {
4039 /* don't log empty requests */
4040 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004041 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01004042 else if (!strcmp(args[1], "httpchk")) {
4043 /* use HTTP request to check servers' health */
4044 curproxy->options |= PR_O_HTTP_CHK;
4045 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004046 else {
4047 Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
4048 return -1;
4049 }
4050 return 0;
4051 }
4052 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
4053 /* enable reconnections to dispatch */
4054 curproxy->options |= PR_O_REDISP;
4055 }
willy tarreaua1598082005-12-17 13:08:06 +01004056#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01004057 else if (!strcmp(args[0], "transparent")) {
4058 /* enable transparent proxy connections */
4059 curproxy->options |= PR_O_TRANSP;
4060 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004061#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01004062 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
4063 if (*(args[1]) == 0) {
4064 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
4065 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004066 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004067 curproxy->maxconn = atol(args[1]);
4068 }
4069 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
4070 if (*(args[1]) == 0) {
4071 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n", file, linenum);
4072 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004073 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004074 curproxy->grace = atol(args[1]);
4075 }
4076 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
4077 if (strchr(args[1], ':') == NULL) {
4078 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n", file, linenum);
4079 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004080 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004081 curproxy->dispatch_addr = *str2sa(args[1]);
4082 }
4083 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
4084 if (*(args[1])) {
4085 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004086 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004087 }
4088 else {
4089 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n", file, linenum);
4090 return -1;
4091 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004092 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004093 else /* if no option is set, use round-robin by default */
4094 curproxy->options |= PR_O_BALANCE_RR;
4095 }
4096 else if (!strcmp(args[0], "server")) { /* server address */
4097 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004098
willy tarreau9fe663a2005-12-17 13:02:59 +01004099 if (strchr(args[2], ':') == NULL) {
4100 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
4101 file, linenum);
4102 return -1;
4103 }
4104 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4105 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4106 return -1;
4107 }
4108 newsrv->next = curproxy->srv;
4109 curproxy->srv = newsrv;
4110 newsrv->proxy = curproxy;
4111 newsrv->id = strdup(args[1]);
4112 newsrv->addr = *str2sa(args[2]);
4113 newsrv->state = SRV_RUNNING; /* early server setup */
4114 newsrv->curfd = -1; /* no health-check in progress */
4115 newsrv->inter = DEF_CHKINTR;
4116 newsrv->rise = DEF_RISETIME;
4117 newsrv->fall = DEF_FALLTIME;
4118 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4119 cur_arg = 3;
4120 while (*args[cur_arg]) {
4121 if (!strcmp(args[cur_arg], "cookie")) {
4122 newsrv->cookie = strdup(args[cur_arg + 1]);
4123 newsrv->cklen = strlen(args[cur_arg + 1]);
4124 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004125 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004126 else if (!strcmp(args[cur_arg], "rise")) {
4127 newsrv->rise = atol(args[cur_arg + 1]);
4128 newsrv->health = newsrv->rise;
4129 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004130 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004131 else if (!strcmp(args[cur_arg], "fall")) {
4132 newsrv->fall = atol(args[cur_arg + 1]);
4133 cur_arg += 2;
4134 }
4135 else if (!strcmp(args[cur_arg], "inter")) {
4136 newsrv->inter = atol(args[cur_arg + 1]);
4137 cur_arg += 2;
4138 }
4139 else if (!strcmp(args[cur_arg], "check")) {
4140 struct task *t;
4141
4142 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
4143 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004144 return -1;
4145 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004146
4147 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4148 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4149 t->state = TASK_IDLE;
4150 t->process = process_chk;
4151 t->context = newsrv;
4152
4153 if (curproxy->state != PR_STDISABLED) {
4154 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4155 task_queue(t);
4156 task_wakeup(&rq, t);
4157 }
4158
4159 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004160 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004161 else {
4162 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
4163 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004164 return -1;
4165 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004166 }
4167 curproxy->nbservers++;
4168 }
4169 else if (!strcmp(args[0], "log")) { /* syslog server address */
4170 struct sockaddr_in *sa;
4171 int facility;
4172
4173 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4174 curproxy->logfac1 = global.logfac1;
4175 curproxy->logsrv1 = global.logsrv1;
4176 curproxy->logfac2 = global.logfac2;
4177 curproxy->logsrv2 = global.logsrv2;
4178 }
4179 else if (*(args[1]) && *(args[2])) {
willy tarreau0f7af912005-12-17 12:21:26 +01004180 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4181 if (!strcmp(log_facilities[facility], args[2]))
4182 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004183
willy tarreau0f7af912005-12-17 12:21:26 +01004184 if (facility >= NB_LOG_FACILITIES) {
4185 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
4186 exit(1);
4187 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004188
willy tarreau0f7af912005-12-17 12:21:26 +01004189 sa = str2sa(args[1]);
4190 if (!sa->sin_port)
4191 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004192
willy tarreau0f7af912005-12-17 12:21:26 +01004193 if (curproxy->logfac1 == -1) {
4194 curproxy->logsrv1 = *sa;
4195 curproxy->logfac1 = facility;
4196 }
4197 else if (curproxy->logfac2 == -1) {
4198 curproxy->logsrv2 = *sa;
4199 curproxy->logfac2 = facility;
4200 }
4201 else {
4202 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004203 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004204 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004205 }
4206 else {
4207 Alert("parsing [%s:%d] : <log> expects either <address[:port]> and <facility> or 'global' as arguments.\n",
4208 file, linenum);
4209 return -1;
4210 }
4211 }
willy tarreaua1598082005-12-17 13:08:06 +01004212 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
4213 if (strchr(args[1], ':') == NULL) {
4214 Alert("parsing [%s:%d] : <source> expects <addr:port> as argument.\n",
4215 file, linenum);
4216 return -1;
4217 }
4218
4219 curproxy->source_addr = *str2sa(args[1]);
4220 curproxy->options |= PR_O_BIND_SRC;
4221 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004222 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4223 regex_t *preg;
4224
4225 if (*(args[1]) == 0 || *(args[2]) == 0) {
4226 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
4227 file, linenum);
4228 return -1;
4229 }
4230
4231 preg = calloc(1, sizeof(regex_t));
4232 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4233 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4234 return -1;
4235 }
4236
4237 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4238 }
4239 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4240 regex_t *preg;
4241
4242 if (*(args[1]) == 0) {
4243 Alert("parsing [%s:%d] : <reqdel> expects <regex> as an argument.\n", file, linenum);
4244 return -1;
4245 }
4246
4247 preg = calloc(1, sizeof(regex_t));
4248 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4249 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4250 return -1;
4251 }
4252
4253 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4254 }
4255 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
4256 regex_t *preg;
4257
4258 if (*(args[1]) == 0) {
4259 Alert("parsing [%s:%d] : <reqdeny> expects <regex> as an argument.\n", file, linenum);
4260 return -1;
4261 }
4262
4263 preg = calloc(1, sizeof(regex_t));
4264 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4265 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4266 return -1;
4267 }
4268
4269 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4270 }
4271 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4272 regex_t *preg;
4273
4274 if (*(args[1]) == 0) {
4275 Alert("parsing [%s:%d] : <reqallow> expects <regex> as an argument.\n", file, linenum);
4276 return -1;
4277 }
4278
4279 preg = calloc(1, sizeof(regex_t));
4280 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4281 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4282 return -1;
4283 }
4284
4285 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4286 }
4287 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4288 regex_t *preg;
4289
4290 if (*(args[1]) == 0 || *(args[2]) == 0) {
4291 Alert("parsing [%s:%d] : <reqirep> expects <search> and <replace> as arguments.\n",
4292 file, linenum);
4293 return -1;
4294 }
4295
4296 preg = calloc(1, sizeof(regex_t));
4297 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4298 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4299 return -1;
4300 }
4301
4302 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4303 }
4304 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4305 regex_t *preg;
4306
4307 if (*(args[1]) == 0) {
4308 Alert("parsing [%s:%d] : <reqidel> expects <regex> as an argument.\n", file, linenum);
4309 return -1;
4310 }
4311
4312 preg = calloc(1, sizeof(regex_t));
4313 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4314 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4315 return -1;
4316 }
4317
4318 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4319 }
4320 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4321 regex_t *preg;
4322
4323 if (*(args[1]) == 0) {
4324 Alert("parsing [%s:%d] : <reqideny> expects <regex> as an argument.\n", file, linenum);
4325 return -1;
4326 }
4327
4328 preg = calloc(1, sizeof(regex_t));
4329 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4330 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4331 return -1;
4332 }
4333
4334 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4335 }
4336 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4337 regex_t *preg;
4338
4339 if (*(args[1]) == 0) {
4340 Alert("parsing [%s:%d] : <reqiallow> expects <regex> as an argument.\n", file, linenum);
4341 return -1;
4342 }
4343
4344 preg = calloc(1, sizeof(regex_t));
4345 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4346 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4347 return -1;
4348 }
4349
4350 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4351 }
4352 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4353 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
4354 Alert("parsing [%s:%d] : too many `reqadd'. Continuing.\n", file, linenum);
4355 return 0;
4356 }
4357
4358 if (*(args[1]) == 0) {
4359 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n", file, linenum);
4360 return -1;
4361 }
4362
4363 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004364 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004365 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004366 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004367
4368 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004369 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004370 file, linenum);
4371 return -1;
4372 }
4373
4374 preg = calloc(1, sizeof(regex_t));
4375 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4376 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4377 return -1;
4378 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004379
4380 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4381 }
4382 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4383 regex_t *preg;
4384
4385 if (*(args[1]) == 0) {
4386 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n", file, linenum);
4387 return -1;
4388 }
willy tarreaue39cd132005-12-17 13:00:18 +01004389
willy tarreau9fe663a2005-12-17 13:02:59 +01004390 preg = calloc(1, sizeof(regex_t));
4391 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4392 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4393 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004394 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004395
4396 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4397 }
4398 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004399 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004400
willy tarreau9fe663a2005-12-17 13:02:59 +01004401 if (*(args[1]) == 0 || *(args[2]) == 0) {
4402 Alert("parsing [%s:%d] : <rspirep> expects <search> and <replace> as arguments.\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01004403 file, linenum);
willy tarreaue39cd132005-12-17 13:00:18 +01004404 return -1;
4405 }
4406
4407 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004408 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreaue39cd132005-12-17 13:00:18 +01004409 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4410 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004411 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004412
4413 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4414 }
4415 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4416 regex_t *preg;
4417
4418 if (*(args[1]) == 0) {
4419 Alert("parsing [%s:%d] : <rspidel> expects <search> as an argument.\n", file, linenum);
4420 return -1;
4421 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004422
willy tarreau9fe663a2005-12-17 13:02:59 +01004423 preg = calloc(1, sizeof(regex_t));
4424 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4425 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4426 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004427 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004428
4429 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4430 }
4431 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4432 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
4433 Alert("parsing [%s:%d] : too many `rspadd'. Continuing.\n", file, linenum);
4434 return 0;
4435 }
4436
4437 if (*(args[1]) == 0) {
4438 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n", file, linenum);
4439 return -1;
4440 }
4441
4442 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4443 }
4444 else {
4445 Alert("parsing [%s:%d] : unknown keyword <%s> in <listen> section\n", file, linenum, args[0]);
4446 return -1;
4447 }
4448 return 0;
4449}
willy tarreaue39cd132005-12-17 13:00:18 +01004450
willy tarreau5cbea6f2005-12-17 12:48:26 +01004451
willy tarreau9fe663a2005-12-17 13:02:59 +01004452/*
4453 * This function reads and parses the configuration file given in the argument.
4454 * returns 0 if OK, -1 if error.
4455 */
4456int readcfgfile(char *file) {
4457 char thisline[256];
4458 char *line;
4459 FILE *f;
4460 int linenum = 0;
4461 char *end;
4462 char *args[MAX_LINE_ARGS];
4463 int arg;
4464 int cfgerr = 0;
4465 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01004466
willy tarreau9fe663a2005-12-17 13:02:59 +01004467 struct proxy *curproxy = NULL;
4468 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01004469
willy tarreau9fe663a2005-12-17 13:02:59 +01004470 if ((f=fopen(file,"r")) == NULL)
4471 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004472
willy tarreau9fe663a2005-12-17 13:02:59 +01004473 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
4474 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004475
willy tarreau9fe663a2005-12-17 13:02:59 +01004476 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004477
willy tarreau9fe663a2005-12-17 13:02:59 +01004478 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01004479 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01004480 line++;
4481
4482 arg = 0;
4483 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01004484
willy tarreau9fe663a2005-12-17 13:02:59 +01004485 while (*line && arg < MAX_LINE_ARGS) {
4486 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
4487 * C equivalent value. Other combinations left unchanged (eg: \1).
4488 */
4489 if (*line == '\\') {
4490 int skip = 0;
4491 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
4492 *line = line[1];
4493 skip = 1;
4494 }
4495 else if (line[1] == 'r') {
4496 *line = '\r';
4497 skip = 1;
4498 }
4499 else if (line[1] == 'n') {
4500 *line = '\n';
4501 skip = 1;
4502 }
4503 else if (line[1] == 't') {
4504 *line = '\t';
4505 skip = 1;
4506 }
4507 else if (line[1] == 'x' && (line + 3 < end )) {
4508 unsigned char hex1, hex2;
4509 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
4510 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4511 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4512 *line = (hex1<<4) + hex2;
4513 skip = 3;
4514 }
4515 if (skip) {
4516 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
4517 end -= skip;
4518 }
4519 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004520 }
willy tarreaua1598082005-12-17 13:08:06 +01004521 else if (*line == '#' || *line == '\n' || *line == '\r') {
4522 /* end of string, end of loop */
4523 *line = 0;
4524 break;
4525 }
willy tarreauc29948c2005-12-17 13:10:27 +01004526 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004527 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01004528 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01004529 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01004530 line++;
4531 args[++arg] = line;
4532 }
4533 else {
4534 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004535 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004536 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004537
willy tarreau9fe663a2005-12-17 13:02:59 +01004538 /* empty line */
4539 if (!**args)
4540 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01004541
willy tarreau9fe663a2005-12-17 13:02:59 +01004542 /* zero out remaining args */
4543 while (++arg < MAX_LINE_ARGS) {
4544 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004545 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004546
willy tarreau9fe663a2005-12-17 13:02:59 +01004547 if (!strcmp(args[0], "listen")) /* new proxy */
4548 confsect = CFG_LISTEN;
4549 else if (!strcmp(args[0], "global")) /* global config */
4550 confsect = CFG_GLOBAL;
4551 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004552
willy tarreau9fe663a2005-12-17 13:02:59 +01004553 switch (confsect) {
4554 case CFG_LISTEN:
4555 if (cfg_parse_listen(file, linenum, args) < 0)
4556 return -1;
4557 break;
4558 case CFG_GLOBAL:
4559 if (cfg_parse_global(file, linenum, args) < 0)
4560 return -1;
4561 break;
4562 default:
4563 Alert("parsing [%s:%d] : unknown keyword <%s> out of section.\n", file, linenum, args[0]);
4564 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004565 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004566
4567
willy tarreau0f7af912005-12-17 12:21:26 +01004568 }
4569 fclose(f);
4570
4571 /*
4572 * Now, check for the integrity of all that we have collected.
4573 */
4574
4575 if ((curproxy = proxy) == NULL) {
4576 Alert("parsing %s : no <listen> line. Nothing to do !\n",
4577 file);
4578 return -1;
4579 }
4580
4581 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01004582 if (curproxy->state == PR_STDISABLED) {
4583 curproxy = curproxy->next;
4584 continue;
4585 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004586 if ((curproxy->mode != PR_MODE_HEALTH) &&
4587 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01004588 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004589 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
4590 file, curproxy->id);
4591 cfgerr++;
4592 }
4593 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
4594 if (curproxy->options & PR_O_TRANSP) {
4595 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
4596 file, curproxy->id);
4597 cfgerr++;
4598 }
4599 else if (curproxy->srv == NULL) {
4600 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
4601 file, curproxy->id);
4602 cfgerr++;
4603 }
willy tarreaua1598082005-12-17 13:08:06 +01004604 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004605 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
4606 file, curproxy->id);
4607 }
4608 }
4609 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01004610 if (curproxy->cookie_name != NULL) {
4611 Warning("parsing %s : cookie will be ignored for listener %s.\n",
4612 file, curproxy->id);
4613 }
4614 if ((newsrv = curproxy->srv) != NULL) {
4615 Warning("parsing %s : servers will be ignored for listener %s.\n",
4616 file, curproxy->id);
4617 }
willy tarreaue39cd132005-12-17 13:00:18 +01004618 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004619 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
4620 file, curproxy->id);
4621 }
willy tarreaue39cd132005-12-17 13:00:18 +01004622 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004623 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
4624 file, curproxy->id);
4625 }
4626 }
4627 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
4628 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
4629 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
4630 file, curproxy->id);
4631 cfgerr++;
4632 }
4633 else {
4634 while (newsrv != NULL) {
4635 /* nothing to check for now */
4636 newsrv = newsrv->next;
4637 }
4638 }
4639 }
4640 curproxy = curproxy->next;
4641 }
4642 if (cfgerr > 0) {
4643 Alert("Errors found in configuration file, aborting.\n");
4644 return -1;
4645 }
4646 else
4647 return 0;
4648}
4649
4650
4651/*
4652 * This function initializes all the necessary variables. It only returns
4653 * if everything is OK. If something fails, it exits.
4654 */
4655void init(int argc, char **argv) {
4656 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01004657 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004658 char *old_argv = *argv;
4659 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01004660 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01004661
4662 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004663 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004664 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
4665 sizeof(int)*8);
4666 exit(1);
4667 }
4668
4669 pid = getpid();
4670 progname = *argv;
4671 while ((tmp = strchr(progname, '/')) != NULL)
4672 progname = tmp + 1;
4673
4674 argc--; argv++;
4675 while (argc > 0) {
4676 char *flag;
4677
4678 if (**argv == '-') {
4679 flag = *argv+1;
4680
4681 /* 1 arg */
4682 if (*flag == 'v') {
4683 display_version();
4684 exit(0);
4685 }
4686 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01004687 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01004688 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01004689 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004690 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01004691 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01004692#if STATTIME > 0
4693 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01004694 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01004695 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01004696 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01004697#endif
4698 else { /* >=2 args */
4699 argv++; argc--;
4700 if (argc == 0)
4701 usage(old_argv);
4702
4703 switch (*flag) {
4704 case 'n' : cfg_maxconn = atol(*argv); break;
4705 case 'N' : cfg_maxpconn = atol(*argv); break;
4706 case 'f' : cfg_cfgfile = *argv; break;
4707 default: usage(old_argv);
4708 }
4709 }
4710 }
4711 else
4712 usage(old_argv);
4713 argv++; argc--;
4714 }
4715
willy tarreau0f7af912005-12-17 12:21:26 +01004716 if (!cfg_cfgfile)
4717 usage(old_argv);
4718
4719 gethostname(hostname, MAX_HOSTNAME_LEN);
4720
4721 if (readcfgfile(cfg_cfgfile) < 0) {
4722 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
4723 exit(1);
4724 }
4725
willy tarreau9fe663a2005-12-17 13:02:59 +01004726 if (cfg_maxconn > 0)
4727 global.maxconn = cfg_maxconn;
4728
4729 if (global.maxconn == 0)
4730 global.maxconn = DEFAULT_MAXCONN;
4731
4732 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
4733
4734 if (arg_mode & MODE_DEBUG) {
4735 /* command line debug mode inhibits configuration mode */
4736 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4737 }
willy tarreau750a4722005-12-17 13:21:24 +01004738 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01004739
4740 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
4741 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
4742 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4743 }
4744
4745 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
4746 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
4747 global.nbproc = 1;
4748 }
4749
4750 if (global.nbproc < 1)
4751 global.nbproc = 1;
4752
willy tarreau0f7af912005-12-17 12:21:26 +01004753 ReadEvent = (fd_set *)calloc(1,
4754 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004755 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004756 WriteEvent = (fd_set *)calloc(1,
4757 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004758 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004759 StaticReadEvent = (fd_set *)calloc(1,
4760 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004761 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004762 StaticWriteEvent = (fd_set *)calloc(1,
4763 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004764 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004765
4766 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01004767 sizeof(struct fdtab) * (global.maxsock));
4768 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004769 fdtab[i].state = FD_STCLOSE;
4770 }
4771}
4772
4773/*
4774 * this function starts all the proxies. It returns 0 if OK, -1 if not.
4775 */
4776int start_proxies() {
4777 struct proxy *curproxy;
4778 int one = 1;
4779 int fd;
4780
4781 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
4782
4783 if (curproxy->state == PR_STDISABLED)
4784 continue;
4785
4786 if ((fd = curproxy->listen_fd =
4787 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
4788 Alert("cannot create listening socket for proxy %s. Aborting.\n",
4789 curproxy->id);
4790 return -1;
4791 }
4792
willy tarreau9fe663a2005-12-17 13:02:59 +01004793 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004794 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
4795 curproxy->id);
4796 close(fd);
4797 return -1;
4798 }
4799
willy tarreau0f7af912005-12-17 12:21:26 +01004800 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
4801 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
4802 (char *) &one, sizeof(one)) == -1)) {
4803 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
4804 curproxy->id);
4805 close(fd);
4806 return -1;
4807 }
4808
4809 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
4810 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
4811 curproxy->id);
4812 }
4813
4814 if (bind(fd,
4815 (struct sockaddr *)&curproxy->listen_addr,
4816 sizeof(curproxy->listen_addr)) == -1) {
4817 Alert("cannot bind socket for proxy %s. Aborting.\n",
4818 curproxy->id);
4819 close(fd);
4820 return -1;
4821 }
4822
4823 if (listen(fd, curproxy->maxconn) == -1) {
4824 Alert("cannot listen to socket for proxy %s. Aborting.\n",
4825 curproxy->id);
4826 close(fd);
4827 return -1;
4828 }
4829
4830 /* the function for the accept() event */
4831 fdtab[fd].read = &event_accept;
4832 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004833 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01004834 curproxy->state = PR_STRUN;
4835 fdtab[fd].state = FD_STLISTEN;
4836 FD_SET(fd, StaticReadEvent);
4837 fd_insert(fd);
4838 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01004839
willy tarreaua1598082005-12-17 13:08:06 +01004840 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004841
willy tarreau0f7af912005-12-17 12:21:26 +01004842 }
4843 return 0;
4844}
4845
4846
4847int main(int argc, char **argv) {
4848 init(argc, argv);
4849
willy tarreau9fe663a2005-12-17 13:02:59 +01004850 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01004851 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004852 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01004853 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01004854 }
4855
4856 signal(SIGQUIT, dump);
4857 signal(SIGUSR1, sig_soft_stop);
4858
4859 /* on very high loads, a sigpipe sometimes happen just between the
4860 * getsockopt() which tells "it's OK to write", and the following write :-(
4861 */
willy tarreau3242e862005-12-17 12:27:53 +01004862#ifndef MSG_NOSIGNAL
4863 signal(SIGPIPE, SIG_IGN);
4864#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004865
4866 if (start_proxies() < 0)
4867 exit(1);
4868
willy tarreau9fe663a2005-12-17 13:02:59 +01004869 /* open log files */
4870
4871 /* chroot if needed */
4872 if (global.chroot != NULL) {
4873 if (chroot(global.chroot) == -1) {
4874 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
4875 exit(1);
4876 }
4877 chdir("/");
4878 }
4879
4880 /* setgid / setuid */
4881 if (global.gid && setregid(global.gid, global.gid) == -1) {
4882 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
4883 exit(1);
4884 }
4885
4886 if (global.uid && setreuid(global.uid, global.uid) == -1) {
4887 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
4888 exit(1);
4889 }
4890
4891 if (global.mode & MODE_DAEMON) {
4892 int ret = 0;
4893 int proc;
4894
4895 /* the father launches the required number of processes */
4896 for (proc = 0; proc < global.nbproc; proc++) {
4897 ret = fork();
4898 if (ret < 0) {
4899 Alert("[%s.main()] Cannot fork.\n", argv[0]);
4900 exit(1); /* there has been an error */
4901 }
4902 else if (ret == 0) /* child breaks here */
4903 break;
4904 }
4905 if (proc == global.nbproc)
4906 exit(0); /* parent must leave */
4907
willy tarreau750a4722005-12-17 13:21:24 +01004908 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
4909 * that we can detach from the TTY. We MUST NOT do it in other cases since
4910 * it would have already be done, and 0-2 would have been affected to listening
4911 * sockets
4912 */
4913 if (!(global.mode & MODE_QUIET)) {
4914 /* detach from the tty */
4915 fclose(stdin); fclose(stdout); fclose(stderr);
4916 close(0); close(1); close(2); /* close all fd's */
4917 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
4918 }
willy tarreaua1598082005-12-17 13:08:06 +01004919 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01004920 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01004921 }
4922
willy tarreau0f7af912005-12-17 12:21:26 +01004923 select_loop();
4924
4925 exit(0);
4926}
willy tarreaua1598082005-12-17 13:08:06 +01004927