blob: 58916614c791ca14ebca2f276ea381b2e1e17627 [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.
17 *
willy tarreau0f7af912005-12-17 12:21:26 +010018 * ChangeLog :
19 *
willy tarreau6e682ce2005-12-17 13:26:49 +010020 * 2002/07/15 : 1.1.13
21 * - tv_diff used inverted parameters which led to negative times !
22 * 2002/07/13 : 1.1.12
willy tarreau750a4722005-12-17 13:21:24 +010023 * - fixed stats monitoring, and optimized some tv_* for most common cases.
24 * - replaced temporary 'newhdr' with 'trash' to reduce stack size
25 * - made HTTP errors more HTML-fiendly.
26 * - renamed strlcpy() to strlcpy2() because of a slightly difference between
27 * their behaviour (return value), to avoid confusion.
28 * - restricted HTTP messages to HTTP proxies only
29 * - added a 502 message when the connection has been refused by the server,
30 * to prevent clients from believing this is a zero-byte HTTP 0.9 reply.
31 * - changed 'Cache-control:' from 'no-cache="set-cookie"' to 'private' when
32 * inserting a cookie, because some caches (apache) don't understand it.
33 * - fixed processing of server headers when client is in SHUTR state
34 * 2002/07/04 :
35 * - automatically close fd's 0,1 and 2 when going daemon ; setpgrp() after
36 * setpgid()
willy tarreau240afa62005-12-17 13:14:35 +010037 * 2002/06/04 : 1.1.11
38 * - fixed multi-cookie handling in client request to allow clean deletion
39 * in insert+indirect mode. Now, only the server cookie is deleted and not
40 * all the header. Should now be compliant to RFC2109.
41 * - added a "nocache" option to "cookie" to specify that we explicitly want
42 * to add a "cache-control" header when we add a cookie.
43 * It is also possible to add an "Expires: <old-date>" to keep compatibility
44 * with old/broken caches.
willy tarreau96d40372005-12-17 13:11:56 +010045 * 2002/05/10 : 1.1.10
46 * - if a cookie is used in insert+indirect mode, it's desirable that the
47 * the servers don't see it. It was not possible to remove it correctly
48 * with regexps, so now it's removed automatically.
willy tarreauc29948c2005-12-17 13:10:27 +010049 * 2002/04/19 : 1.1.9
50 * - don't use snprintf()'s return value as an end of message since it may
51 * be larger. This caused bus errors and segfaults in internal libc's
52 * getenv() during localtime() in send_log().
53 * - removed dead insecure send_syslog() function and all references to it.
54 * - fixed warnings on Solaris due to buggy implementation of isXXXX().
willy tarreaua1598082005-12-17 13:08:06 +010055 * 2002/04/18 : 1.1.8
56 * - option "dontlognull"
57 * - fixed "double space" bug in config parser
58 * - fixed an uninitialized server field in case of dispatch
59 * with no existing server which could cause a segfault during
60 * logging.
61 * - the pid logged was always the father's, which was wrong for daemons.
62 * - fixed wrong level "LOG_INFO" for message "proxy started".
63 * 2002/04/13 :
64 * - http logging is now complete :
65 * - ip:port, date, proxy, server
66 * - req_time, conn_time, hdr_time, tot_time
67 * - status, size, request
68 * - source address
willy tarreau9fe663a2005-12-17 13:02:59 +010069 * 2002/04/12 : 1.1.7
70 * - added option forwardfor
71 * - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel
72 * - added "log global" in "listen" section.
73 * 2002/04/09 :
74 * - added a new "global" section :
75 * - logs
76 * - debug, quiet, daemon modes
77 * - uid, gid, chroot, nbproc, maxconn
willy tarreaue39cd132005-12-17 13:00:18 +010078 * 2002/04/08 : 1.1.6
79 * - regex are now chained and not limited anymore.
80 * - unavailable server now returns HTTP/502.
81 * - increased per-line args limit to 40
82 * - added reqallow/reqdeny to block some request on matches
83 * - added HTTP 400/403 responses
84 * 2002/04/03 : 1.1.5
willy tarreau535ae7a2005-12-17 12:58:00 +010085 * - connection logging displayed incorrect source address.
86 * - added proxy start/stop and server up/down log events.
87 * - replaced log message short buffers with larger trash.
88 * - enlarged buffer to 8 kB and replace buffer to 4 kB.
willy tarreaue39cd132005-12-17 13:00:18 +010089 * 2002/03/25 : 1.1.4
willy tarreaue47c8d72005-12-17 12:55:52 +010090 * - made rise/fall/interval time configurable
willy tarreaue39cd132005-12-17 13:00:18 +010091 * 2002/03/22 : 1.1.3
willy tarreaub719f002005-12-17 12:55:07 +010092 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
93 * which could lead to loops.
willy tarreaue39cd132005-12-17 13:00:18 +010094 * 2002/03/21 : 1.1.2
willy tarreauef900ab2005-12-17 12:52:52 +010095 * - fixed a bug in buffer management where we could have a loop
96 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
97 * => implemented an adjustable buffer limit.
98 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
99 * and running tasks are skipped.
100 * - added some debug lines for accept events.
101 * - send warnings for servers up/down.
willy tarreaue39cd132005-12-17 13:00:18 +0100102 * 2002/03/12 : 1.1.1
willy tarreauefae1842005-12-17 12:51:03 +0100103 * - fixed a bug in total failure handling
104 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreaue39cd132005-12-17 13:00:18 +0100105 * 2002/03/10 : 1.1.0
willy tarreau5cbea6f2005-12-17 12:48:26 +0100106 * - fixed a few timeout bugs
107 * - rearranged the task scheduler subsystem to improve performance,
108 * add new tasks, and make it easier to later port to librt ;
109 * - allow multiple accept() for one select() wake up ;
110 * - implemented internal load balancing with basic health-check ;
111 * - cookie insertion and header add/replace/delete, with better strings
112 * support.
113 * 2002/03/08
114 * - reworked buffer handling to fix a few rewrite bugs, and
115 * improve overall performance.
116 * - implement the "purge" option to delete server cookies in direct mode.
117 * 2002/03/07
118 * - fixed some error cases where the maxfd was not decreased.
119 * 2002/02/26
120 * - now supports transparent proxying, at least on linux 2.4.
121 * 2002/02/12
122 * - soft stop works again (fixed select timeout computation).
123 * - it seems that TCP proxies sometimes cannot timeout.
124 * - added a "quiet" mode.
125 * - enforce file descriptor limitation on socket() and accept().
126 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +0100127 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +0100128 * 2001/12/16 : release of version 1.0.0.
129 * 2001/12/16 : added syslog capability for each accepted connection.
130 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
131 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
132 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
133 * with or without cookies (use keyword http for this).
134 * 2001/09/01 : added client/server header replacing with regexps.
135 * eg:
136 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
137 * srvexp ^Server:\ .* Server:\ Apache
138 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
139 * 2000/11/28 : major rewrite
140 * 2000/11/26 : first write
141 *
willy tarreau5cbea6f2005-12-17 12:48:26 +0100142 * TODO:
143 * - handle properly intermediate incomplete server headers. Done ?
144 * - log proxies start/stop
145 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +0100146 *
147 */
148
149#include <stdio.h>
150#include <stdlib.h>
151#include <unistd.h>
152#include <string.h>
153#include <ctype.h>
154#include <sys/time.h>
155#include <sys/types.h>
156#include <sys/socket.h>
157#include <netinet/tcp.h>
158#include <netinet/in.h>
159#include <arpa/inet.h>
160#include <netdb.h>
161#include <fcntl.h>
162#include <errno.h>
163#include <signal.h>
164#include <stdarg.h>
165#include <sys/resource.h>
166#include <time.h>
167#include <regex.h>
168#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +0100169#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100170#include <linux/netfilter_ipv4.h>
171#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100172
willy tarreau6e682ce2005-12-17 13:26:49 +0100173#define HAPROXY_VERSION "1.1.13"
174#define HAPROXY_DATE "2002/07/15"
willy tarreau0f7af912005-12-17 12:21:26 +0100175
176/* this is for libc5 for example */
177#ifndef TCP_NODELAY
178#define TCP_NODELAY 1
179#endif
180
181#ifndef SHUT_RD
182#define SHUT_RD 0
183#endif
184
185#ifndef SHUT_WR
186#define SHUT_WR 1
187#endif
188
willy tarreau535ae7a2005-12-17 12:58:00 +0100189#define BUFSIZE 8192
willy tarreau0f7af912005-12-17 12:21:26 +0100190
191// reserved buffer space for header rewriting
willy tarreau535ae7a2005-12-17 12:58:00 +0100192#define MAXREWRITE 4096
willy tarreau9fe663a2005-12-17 13:02:59 +0100193#define REQURI_LEN 1024
willy tarreau0f7af912005-12-17 12:21:26 +0100194
willy tarreau5cbea6f2005-12-17 12:48:26 +0100195// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100196#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100197
willy tarreaue39cd132005-12-17 13:00:18 +0100198// max # of added headers per request
199#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100200
201// max # of matches per regexp
202#define MAX_MATCH 10
203
willy tarreau5cbea6f2005-12-17 12:48:26 +0100204/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100205#define COOKIENAME_LEN 16
206#define SERVERID_LEN 16
207#define CONN_RETRIES 3
208
willy tarreau5cbea6f2005-12-17 12:48:26 +0100209#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100210#define DEF_CHKINTR 2000
211#define DEF_FALLTIME 3
212#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100213
willy tarreau9fe663a2005-12-17 13:02:59 +0100214/* default connections limit */
215#define DEFAULT_MAXCONN 2000
216
willy tarreau0f7af912005-12-17 12:21:26 +0100217/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
218#define INTBITS 5
219
220/* show stats this every millisecond, 0 to disable */
221#ifndef STATTIME
222#define STATTIME 2000
223#endif
224
willy tarreau5cbea6f2005-12-17 12:48:26 +0100225/* this reduces the number of calls to select() by choosing appropriate
226 * sheduler precision in milliseconds. It should be near the minimum
227 * time that is needed by select() to collect all events. All timeouts
228 * are rounded up by adding this value prior to pass it to select().
229 */
230#define SCHEDULER_RESOLUTION 9
231
willy tarreau0f7af912005-12-17 12:21:26 +0100232#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
233#define SETNOW(a) (*a=now)
234
willy tarreau9da061b2005-12-17 12:29:56 +0100235/****** string-specific macros and functions ******/
236/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
237#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
238
239/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
240#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
241
willy tarreau9da061b2005-12-17 12:29:56 +0100242/*
243 * copies at most <size-1> chars from <src> to <dst>. Last char is always
244 * set to 0, unless <size> is 0. The number of chars copied is returned
245 * (excluding the terminating zero).
246 * This code has been optimized for size and speed : on x86, it's 45 bytes
247 * long, uses only registers, and consumes only 4 cycles per char.
248 */
willy tarreau750a4722005-12-17 13:21:24 +0100249int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100250 char *orig = dst;
251 if (size) {
252 while (--size && (*dst = *src)) {
253 src++; dst++;
254 }
255 *dst = 0;
256 }
257 return dst - orig;
258}
willy tarreau9da061b2005-12-17 12:29:56 +0100259
willy tarreau0f7af912005-12-17 12:21:26 +0100260#define MEM_OPTIM
261#ifdef MEM_OPTIM
262/*
263 * Returns a pointer to type <type> taken from the
264 * pool <pool_type> or dynamically allocated. In the
265 * first case, <pool_type> is updated to point to the
266 * next element in the list.
267 */
268#define pool_alloc(type) ({ \
269 void *p; \
270 if ((p = pool_##type) == NULL) \
271 p = malloc(sizeof_##type); \
272 else { \
273 pool_##type = *(void **)pool_##type; \
274 } \
275 p; \
276})
277
278/*
279 * Puts a memory area back to the corresponding pool.
280 * Items are chained directly through a pointer that
281 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100282 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100283 * that each memory area is at least as big as one
284 * pointer.
285 */
286#define pool_free(type, ptr) ({ \
287 *(void **)ptr = (void *)pool_##type; \
288 pool_##type = (void *)ptr; \
289})
290
291#else
292#define pool_alloc(type) (calloc(1,sizeof_##type));
293#define pool_free(type, ptr) (free(ptr));
294#endif /* MEM_OPTIM */
295
willy tarreau5cbea6f2005-12-17 12:48:26 +0100296#define sizeof_task sizeof(struct task)
297#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100298#define sizeof_buffer sizeof(struct buffer)
299#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100300#define sizeof_requri REQURI_LEN
willy tarreau0f7af912005-12-17 12:21:26 +0100301
willy tarreau5cbea6f2005-12-17 12:48:26 +0100302/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100303#define FD_STCLOSE 0
304#define FD_STLISTEN 1
305#define FD_STCONN 2
306#define FD_STREADY 3
307#define FD_STERROR 4
308
willy tarreau5cbea6f2005-12-17 12:48:26 +0100309/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100310#define TASK_IDLE 0
311#define TASK_RUNNING 1
312
willy tarreau5cbea6f2005-12-17 12:48:26 +0100313/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100314#define PR_STNEW 0
315#define PR_STIDLE 1
316#define PR_STRUN 2
317#define PR_STDISABLED 3
318
willy tarreau5cbea6f2005-12-17 12:48:26 +0100319/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100320#define PR_MODE_TCP 0
321#define PR_MODE_HTTP 1
322#define PR_MODE_HEALTH 2
323
willy tarreau5cbea6f2005-12-17 12:48:26 +0100324/* bits for proxy->options */
325#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
326#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
327#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
328#define PR_O_COOK_IND 8 /* keep only indirect cookies */
329#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
330#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
331#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
332#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau9fe663a2005-12-17 13:02:59 +0100333#define PR_O_KEEPALIVE 64 /* follow keep-alive sessions */
334#define PR_O_FWDFOR 128 /* insert x-forwarded-for with client address */
willy tarreaua1598082005-12-17 13:08:06 +0100335#define PR_O_BIND_SRC 256 /* bind to a specific source address when connect()ing */
336#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
willy tarreau240afa62005-12-17 13:14:35 +0100337#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
willy tarreau9fe663a2005-12-17 13:02:59 +0100338
willy tarreau5cbea6f2005-12-17 12:48:26 +0100339
willy tarreaue39cd132005-12-17 13:00:18 +0100340/* various session flags */
341#define SN_DIRECT 1 /* connection made on the server matching the client cookie */
342#define SN_CLDENY 2 /* a client header matches a deny regex */
343#define SN_CLALLOW 4 /* a client header matches an allow regex */
344#define SN_SVDENY 8 /* a server header matches a deny regex */
345#define SN_SVALLOW 16 /* a server header matches an allow regex */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100346
347/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100348#define CL_STHEADERS 0
349#define CL_STDATA 1
350#define CL_STSHUTR 2
351#define CL_STSHUTW 3
352#define CL_STCLOSE 4
353
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100355#define SV_STIDLE 0
356#define SV_STCONN 1
357#define SV_STHEADERS 2
358#define SV_STDATA 3
359#define SV_STSHUTR 4
360#define SV_STSHUTW 5
361#define SV_STCLOSE 6
362
363/* result of an I/O event */
364#define RES_SILENT 0 /* didn't happen */
365#define RES_DATA 1 /* data were sent or received */
366#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
367#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
368
willy tarreau9fe663a2005-12-17 13:02:59 +0100369/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100370#define MODE_DEBUG 1
371#define MODE_STATS 2
372#define MODE_LOG 4
373#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100374#define MODE_QUIET 16
375
376/* server flags */
377#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100378
willy tarreaue39cd132005-12-17 13:00:18 +0100379/* what to do when a header matches a regex */
380#define ACT_ALLOW 0 /* allow the request */
381#define ACT_REPLACE 1 /* replace the matching header */
382#define ACT_REMOVE 2 /* remove the matching header */
383#define ACT_DENY 3 /* deny the request */
384
willy tarreau9fe663a2005-12-17 13:02:59 +0100385/* configuration sections */
386#define CFG_NONE 0
387#define CFG_GLOBAL 1
388#define CFG_LISTEN 2
389
willy tarreaua1598082005-12-17 13:08:06 +0100390/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100391#define LW_DATE 1 /* date */
392#define LW_CLIP 2 /* CLient IP */
393#define LW_SVIP 4 /* SerVer IP */
394#define LW_SVID 8 /* server ID */
395#define LW_REQ 16 /* http REQuest */
396#define LW_RESP 32 /* http RESPonse */
397#define LW_PXIP 64 /* proxy IP */
398#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100399#define LW_BYTES 256 /* bytes read from server */
willy tarreau9fe663a2005-12-17 13:02:59 +0100400
willy tarreau0f7af912005-12-17 12:21:26 +0100401/*********************************************************************/
402
403#define LIST_HEAD(a) ((void *)(&(a)))
404
405/*********************************************************************/
406
407struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100408 struct hdr_exp *next;
409 regex_t *preg; /* expression to look for */
410 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
411 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100412};
413
414struct buffer {
415 unsigned int l; /* data length */
416 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100417 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100418 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100419 char data[BUFSIZE];
420};
421
422struct server {
423 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100424 int state; /* server state (SRV_*) */
425 int cklen; /* the len of the cookie, to speed up checks */
426 char *cookie; /* the id set in the cookie */
427 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100428 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100429 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100430 int rise, fall; /* time in iterations */
431 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100432 int result; /* 0 = connect OK, -1 = connect KO */
433 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100434 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100435};
436
willy tarreau5cbea6f2005-12-17 12:48:26 +0100437/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100438struct task {
439 struct task *next, *prev; /* chaining ... */
440 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100441 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100442 int state; /* task state : IDLE or RUNNING */
443 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100444 int (*process)(struct task *t); /* the function which processes the task */
445 void *context; /* the task's context */
446};
447
448/* WARNING: if new fields are added, they must be initialized in event_accept() */
449struct session {
450 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100451 /* application specific below */
452 struct timeval crexpire; /* expiration date for a client read */
453 struct timeval cwexpire; /* expiration date for a client write */
454 struct timeval srexpire; /* expiration date for a server read */
455 struct timeval swexpire; /* expiration date for a server write */
456 struct timeval cnexpire; /* expiration date for a connect */
457 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
458 struct proxy *proxy; /* the proxy this socket belongs to */
459 int cli_fd; /* the client side fd */
460 int srv_fd; /* the server side fd */
461 int cli_state; /* state of the client side */
462 int srv_state; /* state of the server side */
463 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100464 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100465 struct buffer *req; /* request buffer */
466 struct buffer *rep; /* response buffer */
467 struct sockaddr_in cli_addr; /* the client address */
468 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100469 struct server *srv; /* the server being used */
willy tarreaua1598082005-12-17 13:08:06 +0100470 struct {
471 int logwait; /* log fields waiting to be collected : LW_* */
472 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
473 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
474 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
475 long t_data; /* delay before the first data byte from the server ... */
476 unsigned long t_close; /* total session duration */
477 char *uri; /* first line if log needed, NULL otherwise */
478 int status; /* HTTP status from the server, negative if from proxy */
479 long long bytes; /* number of bytes transferred from the server */
480 } logs;
willy tarreau0f7af912005-12-17 12:21:26 +0100481};
482
483struct proxy {
484 int listen_fd; /* the listen socket */
485 int state; /* proxy state */
486 struct sockaddr_in listen_addr; /* the address we listen to */
487 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100488 struct server *srv, *cursrv; /* known servers, current server */
489 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100490 char *cookie_name; /* name of the cookie to look for */
491 int clitimeout; /* client I/O timeout (in milliseconds) */
492 int srvtimeout; /* server I/O timeout (in milliseconds) */
493 int contimeout; /* connect timeout (in milliseconds) */
494 char *id; /* proxy id */
495 int nbconn; /* # of active sessions */
496 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100497 int conn_retries; /* maximum number of connect retries */
498 int options; /* PR_O_REDISP, PR_O_TRANSP */
499 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100500 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100501 struct proxy *next;
502 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
503 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau9fe663a2005-12-17 13:02:59 +0100504 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100505 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100506 int nb_reqadd, nb_rspadd;
507 struct hdr_exp *req_exp; /* regular expressions for request headers */
508 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
509 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100510 int grace; /* grace time after stop request */
511};
512
513/* info about one given fd */
514struct fdtab {
515 int (*read)(int fd); /* read function */
516 int (*write)(int fd); /* write function */
517 struct task *owner; /* the session (or proxy) associated with this fd */
518 int state; /* the state of this fd */
519};
520
521/*********************************************************************/
522
willy tarreau0f7af912005-12-17 12:21:26 +0100523int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100524char *cfg_cfgfile = NULL; /* configuration file */
525char *progname = NULL; /* program name */
526int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100527
528/* global options */
529static struct {
530 int uid;
531 int gid;
532 int nbproc;
533 int maxconn;
534 int maxsock; /* max # of sockets */
535 int mode;
536 char *chroot;
537 int logfac1, logfac2;
538 struct sockaddr_in logsrv1, logsrv2;
539} global = {
540 logfac1 : -1,
541 logfac2 : -1,
542 /* others NULL OK */
543};
544
willy tarreau0f7af912005-12-17 12:21:26 +0100545/*********************************************************************/
546
547fd_set *ReadEvent,
548 *WriteEvent,
549 *StaticReadEvent,
550 *StaticWriteEvent;
551
552void **pool_session = NULL,
553 **pool_buffer = NULL,
554 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100555 **pool_requri = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100556 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100557
558struct proxy *proxy = NULL; /* list of all existing proxies */
559struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100560struct task *rq = NULL; /* global run queue */
561struct task wait_queue = { /* global wait queue */
562 prev:LIST_HEAD(wait_queue),
563 next:LIST_HEAD(wait_queue)
564};
willy tarreau0f7af912005-12-17 12:21:26 +0100565
willy tarreau0f7af912005-12-17 12:21:26 +0100566static int totalconn = 0; /* total # of terminated sessions */
567static int actconn = 0; /* # of active sessions */
568static int maxfd = 0; /* # of the highest fd + 1 */
569static int listeners = 0; /* # of listeners */
570static int stopping = 0; /* non zero means stopping in progress */
571static struct timeval now = {0,0}; /* the current date at any moment */
572
573static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100574/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100575static char trash[BUFSIZE];
576
577/*
578 * Syslog facilities and levels
579 */
580
581#define MAX_SYSLOG_LEN 1024
582#define NB_LOG_FACILITIES 24
583const char *log_facilities[NB_LOG_FACILITIES] = {
584 "kern", "user", "mail", "daemon",
585 "auth", "syslog", "lpr", "news",
586 "uucp", "cron", "auth2", "ftp",
587 "ntp", "audit", "alert", "cron2",
588 "local0", "local1", "local2", "local3",
589 "local4", "local5", "local6", "local7"
590};
591
592
593#define NB_LOG_LEVELS 8
594const char *log_levels[NB_LOG_LEVELS] = {
595 "emerg", "alert", "crit", "err",
596 "warning", "notice", "info", "debug"
597};
598
599#define SYSLOG_PORT 514
600
601const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
602 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
603#define MAX_HOSTNAME_LEN 32
604static char hostname[MAX_HOSTNAME_LEN] = "";
605
willy tarreaua1598082005-12-17 13:08:06 +0100606const char *HTTP_400 =
607 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100608 "Cache-Control: no-cache\r\n"
609 "Connection: close\r\n"
610 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100611 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100612
willy tarreaua1598082005-12-17 13:08:06 +0100613const char *HTTP_403 =
614 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100615 "Cache-Control: no-cache\r\n"
616 "Connection: close\r\n"
617 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100618 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
619
620const char *HTTP_500 =
621 "HTTP/1.0 500 Server Error\r\n"
622 "Cache-Control: no-cache\r\n"
623 "Connection: close\r\n"
624 "\r\n"
625 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100626
627const char *HTTP_502 =
628 "HTTP/1.0 502 Proxy Error\r\n"
629 "Cache-Control: no-cache\r\n"
630 "Connection: close\r\n"
631 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100632 "<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 +0100633
willy tarreau0f7af912005-12-17 12:21:26 +0100634/*********************************************************************/
635/* statistics ******************************************************/
636/*********************************************************************/
637
willy tarreau750a4722005-12-17 13:21:24 +0100638#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100639static int stats_tsk_lsrch, stats_tsk_rsrch,
640 stats_tsk_good, stats_tsk_right, stats_tsk_left,
641 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100642#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100643
644
645/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100646/* debugging *******************************************************/
647/*********************************************************************/
648#ifdef DEBUG_FULL
649static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
650static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
651#endif
652
653/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100654/* function prototypes *********************************************/
655/*********************************************************************/
656
657int event_accept(int fd);
658int event_cli_read(int fd);
659int event_cli_write(int fd);
660int event_srv_read(int fd);
661int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100662int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100663
664/*********************************************************************/
665/* general purpose functions ***************************************/
666/*********************************************************************/
667
668void display_version() {
669 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100670 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100671}
672
673/*
674 * This function prints the command line usage and exits
675 */
676void usage(char *name) {
677 display_version();
678 fprintf(stderr,
679 "Usage : %s -f <cfgfile> [ -vd"
680#if STATTIME > 0
681 "sl"
682#endif
683 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
684 " -v displays version\n"
685 " -d enters debug mode\n"
686#if STATTIME > 0
687 " -s enables statistics output\n"
688 " -l enables long statistics format\n"
689#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100690 " -D goes daemon ; implies -q\n"
691 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100692 " -n sets the maximum total # of connections (%d)\n"
693 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100694 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100695 exit(1);
696}
697
698
699/*
700 * Displays the message on stderr with the date and pid.
701 */
702void Alert(char *fmt, ...) {
703 va_list argp;
704 struct timeval tv;
705 struct tm *tm;
706
willy tarreau9fe663a2005-12-17 13:02:59 +0100707 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100708 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100709
willy tarreau5cbea6f2005-12-17 12:48:26 +0100710 gettimeofday(&tv, NULL);
711 tm=localtime(&tv.tv_sec);
712 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100713 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100714 vfprintf(stderr, fmt, argp);
715 fflush(stderr);
716 va_end(argp);
717 }
willy tarreau0f7af912005-12-17 12:21:26 +0100718}
719
720
721/*
722 * Displays the message on stderr with the date and pid.
723 */
724void Warning(char *fmt, ...) {
725 va_list argp;
726 struct timeval tv;
727 struct tm *tm;
728
willy tarreau9fe663a2005-12-17 13:02:59 +0100729 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100730 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100731
willy tarreau5cbea6f2005-12-17 12:48:26 +0100732 gettimeofday(&tv, NULL);
733 tm=localtime(&tv.tv_sec);
734 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100735 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100736 vfprintf(stderr, fmt, argp);
737 fflush(stderr);
738 va_end(argp);
739 }
740}
741
742/*
743 * Displays the message on <out> only if quiet mode is not set.
744 */
745void qfprintf(FILE *out, char *fmt, ...) {
746 va_list argp;
747
willy tarreau9fe663a2005-12-17 13:02:59 +0100748 if (!(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100749 va_start(argp, fmt);
750 vfprintf(out, fmt, argp);
751 fflush(out);
752 va_end(argp);
753 }
willy tarreau0f7af912005-12-17 12:21:26 +0100754}
755
756
757/*
758 * converts <str> to a struct sockaddr_in* which is locally allocated.
759 * The format is "addr:port", where "addr" can be empty or "*" to indicate
760 * INADDR_ANY.
761 */
762struct sockaddr_in *str2sa(char *str) {
763 static struct sockaddr_in sa;
764 char *c;
765 int port;
766
willy tarreaua1598082005-12-17 13:08:06 +0100767 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100768 str=strdup(str);
769
770 if ((c=strrchr(str,':')) != NULL) {
771 *c++=0;
772 port=atol(c);
773 }
774 else
775 port=0;
776
777 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
778 sa.sin_addr.s_addr = INADDR_ANY;
779 }
780 else if (
781#ifndef SOLARIS
782 !inet_aton(str, &sa.sin_addr)
783#else
784 !inet_pton(AF_INET, str, &sa.sin_addr)
785#endif
786 ) {
787 struct hostent *he;
788
789 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100790 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100791 }
792 else
793 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
794 }
795 sa.sin_port=htons(port);
796 sa.sin_family=AF_INET;
797
798 free(str);
799 return &sa;
800}
801
willy tarreau9fe663a2005-12-17 13:02:59 +0100802
803/*
804 * This function sends a syslog message to both log servers of a proxy,
805 * or to global log servers if the proxy is NULL.
806 * It also tries not to waste too much time computing the message header.
807 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +0100808 */
809void send_log(struct proxy *p, int level, char *message, ...) {
810 static int logfd = -1; /* syslog UDP socket */
811 static long tvsec = -1; /* to force the string to be initialized */
812 struct timeval tv;
813 va_list argp;
814 static char logmsg[MAX_SYSLOG_LEN];
815 static char *dataptr = NULL;
816 int fac_level;
817 int hdr_len, data_len;
818 struct sockaddr_in *sa[2];
819 int facilities[2];
820 int nbloggers = 0;
821 char *log_ptr;
822
823 if (logfd < 0) {
824 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
825 return;
826 }
827
828 if (level < 0 || progname == NULL || message == NULL)
829 return;
830
831 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +0100832 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +0100833 /* this string is rebuild only once a second */
834 struct tm *tm = localtime(&tv.tv_sec);
835 tvsec = tv.tv_sec;
836
willy tarreauc29948c2005-12-17 13:10:27 +0100837 hdr_len = snprintf(logmsg, sizeof(logmsg),
838 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
839 monthname[tm->tm_mon],
840 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
841 progname, pid);
842 /* WARNING: depending upon implementations, snprintf may return
843 * either -1 or the number of bytes that would be needed to store
844 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +0100845 */
willy tarreauc29948c2005-12-17 13:10:27 +0100846 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
847 hdr_len = sizeof(logmsg);
848
849 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +0100850 }
851
852 va_start(argp, message);
853 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100854 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
855 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +0100856 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +0100857 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +0100858
859 if (p == NULL) {
860 if (global.logfac1 >= 0) {
861 sa[nbloggers] = &global.logsrv1;
862 facilities[nbloggers] = global.logfac1;
863 nbloggers++;
864 }
865 if (global.logfac2 >= 0) {
866 sa[nbloggers] = &global.logsrv2;
867 facilities[nbloggers] = global.logfac2;
868 nbloggers++;
869 }
870 } else {
871 if (p->logfac1 >= 0) {
872 sa[nbloggers] = &p->logsrv1;
873 facilities[nbloggers] = p->logfac1;
874 nbloggers++;
875 }
876 if (p->logfac2 >= 0) {
877 sa[nbloggers] = &p->logsrv2;
878 facilities[nbloggers] = p->logfac2;
879 nbloggers++;
880 }
881 }
882
883 while (nbloggers-- > 0) {
willy tarreauc29948c2005-12-17 13:10:27 +0100884 /* For each target, we may have a different facility.
885 * We can also have a different log level for each message.
886 * This induces variations in the message header length.
887 * Since we don't want to recompute it each time, nor copy it every
888 * time, we only change the facility in the pre-computed header,
889 * and we change the pointer to the header accordingly.
890 */
willy tarreau9fe663a2005-12-17 13:02:59 +0100891 fac_level = (facilities[nbloggers] << 3) + level;
892 log_ptr = logmsg + 3; /* last digit of the log level */
893 do {
894 *log_ptr = '0' + fac_level % 10;
895 fac_level /= 10;
896 log_ptr--;
897 } while (fac_level && log_ptr > logmsg);
898 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +0100899
willy tarreauc29948c2005-12-17 13:10:27 +0100900 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +0100901
902#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +0100903 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +0100904 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
905#else
willy tarreauc29948c2005-12-17 13:10:27 +0100906 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100907 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
908#endif
909 }
willy tarreau0f7af912005-12-17 12:21:26 +0100910}
911
912
913/* sets <tv> to the current time */
914static inline struct timeval *tv_now(struct timeval *tv) {
915 if (tv)
916 gettimeofday(tv, NULL);
917 return tv;
918}
919
920/*
921 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
922 */
923static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
924 if (!tv || !from)
925 return NULL;
926 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
927 tv->tv_sec = from->tv_sec + (ms/1000);
928 while (tv->tv_usec >= 1000000) {
929 tv->tv_usec -= 1000000;
930 tv->tv_sec++;
931 }
932 return tv;
933}
934
935/*
936 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
937 */
938static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +0100939 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100940 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100941 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +0100942 return 1;
943 else if (tv1->tv_usec < tv2->tv_usec)
944 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100945 else if (tv1->tv_usec > tv2->tv_usec)
946 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +0100947 else
948 return 0;
949}
950
951/*
952 * returns the absolute difference, in ms, between tv1 and tv2
953 */
954unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
955 int cmp;
956 unsigned long ret;
957
958
willy tarreauef900ab2005-12-17 12:52:52 +0100959 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100960 if (!cmp)
961 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +0100962 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100963 struct timeval *tmp = tv1;
964 tv1 = tv2;
965 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100966 }
willy tarreauef900ab2005-12-17 12:52:52 +0100967 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100968 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100969 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100970 else
willy tarreauef900ab2005-12-17 12:52:52 +0100971 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100972 return (unsigned long) ret;
973}
974
975/*
willy tarreau750a4722005-12-17 13:21:24 +0100976 * returns the difference, in ms, between tv1 and tv2
977 */
978static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
979 unsigned long ret;
980
willy tarreau6e682ce2005-12-17 13:26:49 +0100981 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
982 if (tv2->tv_usec > tv1->tv_usec)
983 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100984 else
willy tarreau6e682ce2005-12-17 13:26:49 +0100985 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +0100986 return (unsigned long) ret;
987}
988
989/*
willy tarreau0f7af912005-12-17 12:21:26 +0100990 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
991 */
992static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100993 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +0100994 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100995 return -1;
willy tarreau750a4722005-12-17 13:21:24 +0100996 else if (tv1->tv_usec > tv2->tv_usec + 1000)
997 return 1;
willy tarreauefae1842005-12-17 12:51:03 +0100998 else
999 return 0;
1000 }
willy tarreau0f7af912005-12-17 12:21:26 +01001001 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001002 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001003 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001004 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1005 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1006 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001007 else
1008 return 0;
1009}
1010
1011/*
1012 * returns the remaining time between tv1=now and event=tv2
1013 * if tv2 is passed, 0 is returned.
1014 */
1015static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1016 unsigned long ret;
1017
willy tarreau0f7af912005-12-17 12:21:26 +01001018 if (tv_cmp_ms(tv1, tv2) >= 0)
1019 return 0; /* event elapsed */
1020
willy tarreauef900ab2005-12-17 12:52:52 +01001021 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001022 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001023 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001024 else
willy tarreauef900ab2005-12-17 12:52:52 +01001025 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001026 return (unsigned long) ret;
1027}
1028
1029
1030/*
1031 * zeroes a struct timeval
1032 */
1033
1034static inline struct timeval *tv_eternity(struct timeval *tv) {
1035 tv->tv_sec = tv->tv_usec = 0;
1036 return tv;
1037}
1038
1039/*
1040 * returns 1 if tv is null, else 0
1041 */
1042static inline int tv_iseternity(struct timeval *tv) {
1043 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1044 return 1;
1045 else
1046 return 0;
1047}
1048
1049/*
1050 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1051 * considering that 0 is the eternity.
1052 */
1053static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1054 if (tv_iseternity(tv1))
1055 if (tv_iseternity(tv2))
1056 return 0; /* same */
1057 else
1058 return 1; /* tv1 later than tv2 */
1059 else if (tv_iseternity(tv2))
1060 return -1; /* tv2 later than tv1 */
1061
1062 if (tv1->tv_sec > tv2->tv_sec)
1063 return 1;
1064 else if (tv1->tv_sec < tv2->tv_sec)
1065 return -1;
1066 else if (tv1->tv_usec > tv2->tv_usec)
1067 return 1;
1068 else if (tv1->tv_usec < tv2->tv_usec)
1069 return -1;
1070 else
1071 return 0;
1072}
1073
1074/*
1075 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1076 * considering that 0 is the eternity.
1077 */
1078static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1079 if (tv_iseternity(tv1))
1080 if (tv_iseternity(tv2))
1081 return 0; /* same */
1082 else
1083 return 1; /* tv1 later than tv2 */
1084 else if (tv_iseternity(tv2))
1085 return -1; /* tv2 later than tv1 */
1086
willy tarreauefae1842005-12-17 12:51:03 +01001087 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001088 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001089 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001090 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001091 return -1;
1092 else
1093 return 0;
1094 }
1095 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001096 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001097 return 1;
1098 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001099 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001100 return -1;
1101 else
1102 return 0;
1103}
1104
1105/*
1106 * returns the first event between tv1 and tv2 into tvmin.
1107 * a zero tv is ignored. tvmin is returned.
1108 */
1109static inline struct timeval *tv_min(struct timeval *tvmin,
1110 struct timeval *tv1, struct timeval *tv2) {
1111
1112 if (tv_cmp2(tv1, tv2) <= 0)
1113 *tvmin = *tv1;
1114 else
1115 *tvmin = *tv2;
1116
1117 return tvmin;
1118}
1119
1120
1121
1122/***********************************************************/
1123/* fd management ***************************************/
1124/***********************************************************/
1125
1126
1127
willy tarreau5cbea6f2005-12-17 12:48:26 +01001128/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1129 * The file descriptor is also closed.
1130 */
willy tarreau0f7af912005-12-17 12:21:26 +01001131static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001132 FD_CLR(fd, StaticReadEvent);
1133 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001134 close(fd);
1135 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001136
1137 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1138 maxfd--;
1139}
1140
1141/* recomputes the maxfd limit from the fd */
1142static inline void fd_insert(int fd) {
1143 if (fd+1 > maxfd)
1144 maxfd = fd+1;
1145}
1146
1147/*************************************************************/
1148/* task management ***************************************/
1149/*************************************************************/
1150
willy tarreau5cbea6f2005-12-17 12:48:26 +01001151/* puts the task <t> in run queue <q>, and returns <t> */
1152static inline struct task *task_wakeup(struct task **q, struct task *t) {
1153 if (t->state == TASK_RUNNING)
1154 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001155 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001156 t->rqnext = *q;
1157 t->state = TASK_RUNNING;
1158 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001159 }
1160}
1161
willy tarreau5cbea6f2005-12-17 12:48:26 +01001162/* removes the task <t> from the queue <q>
1163 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001164 * set the run queue to point to the next one, and return it
1165 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001166static inline struct task *task_sleep(struct task **q, struct task *t) {
1167 if (t->state == TASK_RUNNING) {
1168 *q = t->rqnext;
1169 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001170 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001171 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001172}
1173
1174/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001175 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001176 * from the run queue. A pointer to the task itself is returned.
1177 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001178static inline struct task *task_delete(struct task *t) {
1179 t->prev->next = t->next;
1180 t->next->prev = t->prev;
1181 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001182}
1183
1184/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001185 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001186 */
1187static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001188 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001189}
1190
willy tarreau5cbea6f2005-12-17 12:48:26 +01001191/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001192 * may be only moved or left where it was, depending on its timing requirements.
1193 * <task> is returned.
1194 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001195struct task *task_queue(struct task *task) {
1196 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001197 struct task *start_from;
1198
1199 /* first, test if the task was already in a list */
1200 if (task->prev == NULL) {
1201 // start_from = list;
1202 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001203#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001204 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001205#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001206 /* insert the unlinked <task> into the list, searching back from the last entry */
1207 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1208 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001209#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001210 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001211#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001212 }
1213
1214 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1215 // start_from = start_from->next;
1216 // stats_tsk_nsrch++;
1217 // }
1218 }
1219 else if (task->prev == list ||
1220 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1221 start_from = task->next;
1222 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001223#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001224 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001225#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001226 return task; /* it's already in the right place */
1227 }
1228
willy tarreau750a4722005-12-17 13:21:24 +01001229#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001230 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001231#endif
1232
1233 /* if the task is not at the right place, there's little chance that
1234 * it has only shifted a bit, and it will nearly always be queued
1235 * at the end of the list because of constant timeouts
1236 * (observed in real case).
1237 */
1238#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1239 start_from = list->prev; /* assume we'll queue to the end of the list */
1240 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1241 start_from = start_from->prev;
1242#if STATTIME > 0
1243 stats_tsk_lsrch++;
1244#endif
1245 }
1246#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001247 /* insert the unlinked <task> into the list, searching after position <start_from> */
1248 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1249 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001250#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001251 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001252#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001253 }
willy tarreau750a4722005-12-17 13:21:24 +01001254#endif /* WE_REALLY_... */
1255
willy tarreau0f7af912005-12-17 12:21:26 +01001256 /* we need to unlink it now */
1257 task_delete(task);
1258 }
1259 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001260#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001261 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001262#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001263#ifdef LEFT_TO_TOP /* not very good */
1264 start_from = list;
1265 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1266 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001267#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001268 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001269#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001270 }
1271#else
1272 start_from = task->prev->prev; /* valid because of the previous test above */
1273 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1274 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001275#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001276 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001277#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001278 }
1279#endif
1280 /* we need to unlink it now */
1281 task_delete(task);
1282 }
1283 task->prev = start_from;
1284 task->next = start_from->next;
1285 task->next->prev = task;
1286 start_from->next = task;
1287 return task;
1288}
1289
1290
1291/*********************************************************************/
1292/* more specific functions ***************************************/
1293/*********************************************************************/
1294
1295/* some prototypes */
1296static int maintain_proxies(void);
1297
willy tarreau5cbea6f2005-12-17 12:48:26 +01001298/* this either returns the sockname or the original destination address. Code
1299 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1300 */
1301static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001302#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001303 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1304#else
willy tarreaua1598082005-12-17 13:08:06 +01001305#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001306 return getsockname(fd, (struct sockaddr *)sa, salen);
1307#else
1308 return -1;
1309#endif
1310#endif
1311}
1312
1313/*
1314 * frees the context associated to a session. It must have been removed first.
1315 */
1316static inline void session_free(struct session *s) {
1317 if (s->req)
1318 pool_free(buffer, s->req);
1319 if (s->rep)
1320 pool_free(buffer, s->rep);
willy tarreaua1598082005-12-17 13:08:06 +01001321 if (s->logs.uri)
1322 pool_free(requri, s->logs.uri);
willy tarreau9fe663a2005-12-17 13:02:59 +01001323
willy tarreau5cbea6f2005-12-17 12:48:26 +01001324 pool_free(session, s);
1325}
1326
willy tarreau0f7af912005-12-17 12:21:26 +01001327
1328/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001329 * This function initiates a connection to the current server (s->srv) if (s->direct)
1330 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001331 * it's OK, -1 if it's impossible.
1332 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001333int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001334 int one = 1;
1335 int fd;
1336
1337 // fprintf(stderr,"connect_server : s=%p\n",s);
1338
willy tarreaue39cd132005-12-17 13:00:18 +01001339 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001340 s->srv_addr = s->srv->addr;
1341 }
1342 else if (s->proxy->options & PR_O_BALANCE) {
1343 if (s->proxy->options & PR_O_BALANCE_RR) {
1344 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001345 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001346 if (s->proxy->cursrv == NULL)
1347 s->proxy->cursrv = s->proxy->srv;
1348 if (s->proxy->cursrv->state & SRV_RUNNING)
1349 break;
1350 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001351 retry--;
1352 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001353
1354 if (retry == 0) /* no server left */
1355 return -1;
1356
1357 s->srv = s->proxy->cursrv;
1358 s->srv_addr = s->srv->addr;
1359 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001360 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001361 else /* unknown balancing algorithm */
1362 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001363 }
willy tarreaua1598082005-12-17 13:08:06 +01001364 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001365 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001366 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001367 }
1368 else if (s->proxy->options & PR_O_TRANSP) {
1369 /* in transparent mode, use the original dest addr if no dispatch specified */
1370 int salen = sizeof(struct sockaddr_in);
1371 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1372 qfprintf(stderr, "Cannot get original server address.\n");
1373 return -1;
1374 }
1375 }
willy tarreau0f7af912005-12-17 12:21:26 +01001376
1377 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001378 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001379 return -1;
1380 }
1381
willy tarreau9fe663a2005-12-17 13:02:59 +01001382 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001383 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1384 close(fd);
1385 return -1;
1386 }
1387
willy tarreau0f7af912005-12-17 12:21:26 +01001388 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1389 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001390 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001391 close(fd);
1392 return -1;
1393 }
1394
willy tarreaua1598082005-12-17 13:08:06 +01001395 /* allow specific binding */
1396 if (s->proxy->options & PR_O_BIND_SRC &&
1397 bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1398 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1399 close(fd);
1400 return -1;
1401 }
1402
willy tarreau0f7af912005-12-17 12:21:26 +01001403 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1404 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001405 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001406 close(fd);
1407 return -1;
1408 }
1409 else if (errno != EALREADY && errno != EISCONN) {
1410 close(fd);
1411 return -1;
1412 }
1413 }
1414
willy tarreau5cbea6f2005-12-17 12:48:26 +01001415 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001416 fdtab[fd].read = &event_srv_read;
1417 fdtab[fd].write = &event_srv_write;
1418 fdtab[fd].state = FD_STCONN; /* connection in progress */
1419
1420 FD_SET(fd, StaticWriteEvent); /* for connect status */
1421
1422 fd_insert(fd);
1423
1424 if (s->proxy->contimeout)
1425 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1426 else
1427 tv_eternity(&s->cnexpire);
1428 return 0;
1429}
1430
1431/*
1432 * this function is called on a read event from a client socket.
1433 * It returns 0.
1434 */
1435int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001436 struct task *t = fdtab[fd].owner;
1437 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001438 struct buffer *b = s->req;
1439 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001440
1441 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1442
willy tarreau0f7af912005-12-17 12:21:26 +01001443 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001444 while (1) {
1445 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1446 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001447 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001448 }
1449 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001450 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001451 }
1452 else {
1453 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001454 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1455 * since it means that the rewrite protection has been removed. This
1456 * implies that the if statement can be removed.
1457 */
1458 if (max > b->rlim - b->data)
1459 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001460 }
1461
1462 if (max == 0) { /* not anymore room to store data */
1463 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001464 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001465 }
1466
willy tarreau3242e862005-12-17 12:27:53 +01001467#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001468 {
1469 int skerr, lskerr;
1470
1471 lskerr = sizeof(skerr);
1472 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1473 if (skerr)
1474 ret = -1;
1475 else
1476 ret = recv(fd, b->r, max, 0);
1477 }
willy tarreau3242e862005-12-17 12:27:53 +01001478#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001479 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001480#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001481 if (ret > 0) {
1482 b->r += ret;
1483 b->l += ret;
1484 s->res_cr = RES_DATA;
1485
1486 if (b->r == b->data + BUFSIZE) {
1487 b->r = b->data; /* wrap around the buffer */
1488 }
willy tarreaua1598082005-12-17 13:08:06 +01001489
1490 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001491 /* we hope to read more data or to get a close on next round */
1492 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001493 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001494 else if (ret == 0) {
1495 s->res_cr = RES_NULL;
1496 break;
1497 }
1498 else if (errno == EAGAIN) {/* ignore EAGAIN */
1499 break;
1500 }
1501 else {
1502 s->res_cr = RES_ERROR;
1503 fdtab[fd].state = FD_STERROR;
1504 break;
1505 }
1506 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001507 }
1508 else {
1509 s->res_cr = RES_ERROR;
1510 fdtab[fd].state = FD_STERROR;
1511 }
1512
willy tarreau5cbea6f2005-12-17 12:48:26 +01001513 if (s->res_cr != RES_SILENT) {
1514 if (s->proxy->clitimeout)
1515 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1516 else
1517 tv_eternity(&s->crexpire);
1518
1519 task_wakeup(&rq, t);
1520 }
willy tarreau0f7af912005-12-17 12:21:26 +01001521
willy tarreau0f7af912005-12-17 12:21:26 +01001522 return 0;
1523}
1524
1525
1526/*
1527 * this function is called on a read event from a server socket.
1528 * It returns 0.
1529 */
1530int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001531 struct task *t = fdtab[fd].owner;
1532 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001533 struct buffer *b = s->rep;
1534 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001535
1536 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1537
willy tarreau0f7af912005-12-17 12:21:26 +01001538 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001539 while (1) {
1540 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1541 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001542 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001543 }
1544 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001545 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001546 }
1547 else {
1548 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001549 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1550 * since it means that the rewrite protection has been removed. This
1551 * implies that the if statement can be removed.
1552 */
1553 if (max > b->rlim - b->data)
1554 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001555 }
1556
1557 if (max == 0) { /* not anymore room to store data */
1558 FD_CLR(fd, StaticReadEvent);
1559 break;
1560 }
1561
willy tarreau3242e862005-12-17 12:27:53 +01001562#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001563 {
1564 int skerr, lskerr;
1565
1566 lskerr = sizeof(skerr);
1567 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1568 if (skerr)
1569 ret = -1;
1570 else
1571 ret = recv(fd, b->r, max, 0);
1572 }
willy tarreau3242e862005-12-17 12:27:53 +01001573#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001574 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001575#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001576 if (ret > 0) {
1577 b->r += ret;
1578 b->l += ret;
1579 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001580
willy tarreau5cbea6f2005-12-17 12:48:26 +01001581 if (b->r == b->data + BUFSIZE) {
1582 b->r = b->data; /* wrap around the buffer */
1583 }
willy tarreaua1598082005-12-17 13:08:06 +01001584
1585 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001586 /* we hope to read more data or to get a close on next round */
1587 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001588 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001589 else if (ret == 0) {
1590 s->res_sr = RES_NULL;
1591 break;
1592 }
1593 else if (errno == EAGAIN) {/* ignore EAGAIN */
1594 break;
1595 }
1596 else {
1597 s->res_sr = RES_ERROR;
1598 fdtab[fd].state = FD_STERROR;
1599 break;
1600 }
1601 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001602 }
1603 else {
1604 s->res_sr = RES_ERROR;
1605 fdtab[fd].state = FD_STERROR;
1606 }
1607
willy tarreau5cbea6f2005-12-17 12:48:26 +01001608 if (s->res_sr != RES_SILENT) {
1609 if (s->proxy->srvtimeout)
1610 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1611 else
1612 tv_eternity(&s->srexpire);
1613
1614 task_wakeup(&rq, t);
1615 }
willy tarreau0f7af912005-12-17 12:21:26 +01001616
willy tarreau0f7af912005-12-17 12:21:26 +01001617 return 0;
1618}
1619
1620/*
1621 * this function is called on a write event from a client socket.
1622 * It returns 0.
1623 */
1624int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001625 struct task *t = fdtab[fd].owner;
1626 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001627 struct buffer *b = s->rep;
1628 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001629
1630 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1631
1632 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001633 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001634 // max = BUFSIZE; BUG !!!!
1635 max = 0;
1636 }
1637 else if (b->r > b->w) {
1638 max = b->r - b->w;
1639 }
1640 else
1641 max = b->data + BUFSIZE - b->w;
1642
willy tarreau0f7af912005-12-17 12:21:26 +01001643 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001644#ifndef MSG_NOSIGNAL
1645 int skerr, lskerr;
1646#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001647
1648 if (max == 0) {
1649 s->res_cw = RES_NULL;
1650 task_wakeup(&rq, t);
1651 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001652 }
1653
willy tarreau3242e862005-12-17 12:27:53 +01001654#ifndef MSG_NOSIGNAL
1655 lskerr=sizeof(skerr);
1656 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1657 if (skerr)
1658 ret = -1;
1659 else
1660 ret = send(fd, b->w, max, MSG_DONTWAIT);
1661#else
willy tarreau0f7af912005-12-17 12:21:26 +01001662 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001663#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001664
1665 if (ret > 0) {
1666 b->l -= ret;
1667 b->w += ret;
1668
1669 s->res_cw = RES_DATA;
1670
1671 if (b->w == b->data + BUFSIZE) {
1672 b->w = b->data; /* wrap around the buffer */
1673 }
1674 }
1675 else if (ret == 0) {
1676 /* nothing written, just make as if we were never called */
1677// s->res_cw = RES_NULL;
1678 return 0;
1679 }
1680 else if (errno == EAGAIN) /* ignore EAGAIN */
1681 return 0;
1682 else {
1683 s->res_cw = RES_ERROR;
1684 fdtab[fd].state = FD_STERROR;
1685 }
1686 }
1687 else {
1688 s->res_cw = RES_ERROR;
1689 fdtab[fd].state = FD_STERROR;
1690 }
1691
1692 if (s->proxy->clitimeout)
1693 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1694 else
1695 tv_eternity(&s->cwexpire);
1696
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001698 return 0;
1699}
1700
1701
1702/*
1703 * this function is called on a write event from a server socket.
1704 * It returns 0.
1705 */
1706int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001707 struct task *t = fdtab[fd].owner;
1708 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001709 struct buffer *b = s->req;
1710 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001711
1712 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1713
1714 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001715 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001716 // max = BUFSIZE; BUG !!!!
1717 max = 0;
1718 }
1719 else if (b->r > b->w) {
1720 max = b->r - b->w;
1721 }
1722 else
1723 max = b->data + BUFSIZE - b->w;
1724
willy tarreau0f7af912005-12-17 12:21:26 +01001725 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001726#ifndef MSG_NOSIGNAL
1727 int skerr, lskerr;
1728#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001729 if (max == 0) {
1730 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001731 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001732 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001733 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001734 return 0;
1735 }
1736
willy tarreauef900ab2005-12-17 12:52:52 +01001737
willy tarreau3242e862005-12-17 12:27:53 +01001738#ifndef MSG_NOSIGNAL
1739 lskerr=sizeof(skerr);
1740 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1741 if (skerr)
1742 ret = -1;
1743 else
1744 ret = send(fd, b->w, max, MSG_DONTWAIT);
1745#else
willy tarreau0f7af912005-12-17 12:21:26 +01001746 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001747#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001748 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001749 if (ret > 0) {
1750 b->l -= ret;
1751 b->w += ret;
1752
1753 s->res_sw = RES_DATA;
1754
1755 if (b->w == b->data + BUFSIZE) {
1756 b->w = b->data; /* wrap around the buffer */
1757 }
1758 }
1759 else if (ret == 0) {
1760 /* nothing written, just make as if we were never called */
1761 // s->res_sw = RES_NULL;
1762 return 0;
1763 }
1764 else if (errno == EAGAIN) /* ignore EAGAIN */
1765 return 0;
1766 else {
1767 s->res_sw = RES_ERROR;
1768 fdtab[fd].state = FD_STERROR;
1769 }
1770 }
1771 else {
1772 s->res_sw = RES_ERROR;
1773 fdtab[fd].state = FD_STERROR;
1774 }
1775
1776 if (s->proxy->srvtimeout)
1777 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1778 else
1779 tv_eternity(&s->swexpire);
1780
willy tarreau5cbea6f2005-12-17 12:48:26 +01001781 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001782 return 0;
1783}
1784
1785
1786/*
willy tarreaue39cd132005-12-17 13:00:18 +01001787 * returns a message to the client ; the connection is shut down for read,
1788 * and the request is cleared so that no server connection can be initiated.
1789 * The client must be in a valid state for this (HEADER, DATA ...).
1790 * Nothing is performed on the server side.
1791 * The reply buffer must be empty before this.
1792 */
1793void client_retnclose(struct session *s, int len, const char *msg) {
1794 FD_CLR(s->cli_fd, StaticReadEvent);
1795 FD_SET(s->cli_fd, StaticWriteEvent);
1796 tv_eternity(&s->crexpire);
1797 shutdown(s->cli_fd, SHUT_RD);
1798 s->cli_state = CL_STSHUTR;
1799 strcpy(s->rep->data, msg);
1800 s->rep->l = len;
1801 s->rep->r += len;
1802 s->req->l = 0;
1803}
1804
1805
1806/*
1807 * returns a message into the rep buffer, and flushes the req buffer.
1808 * The reply buffer must be empty before this.
1809 */
1810void client_return(struct session *s, int len, const char *msg) {
1811 strcpy(s->rep->data, msg);
1812 s->rep->l = len;
1813 s->rep->r += len;
1814 s->req->l = 0;
1815}
1816
willy tarreau9fe663a2005-12-17 13:02:59 +01001817/*
1818 * send a log for the session when we have enough info about it
1819 */
1820void sess_log(struct session *s) {
1821 unsigned char *pn;
1822 struct proxy *p = s->proxy;
1823 int log;
1824 char *uri;
1825 char *pxid;
1826 char *srv;
1827
1828 /* This is a first attempt at a better logging system.
1829 * For now, we rely on send_log() to provide the date, although it obviously
1830 * is the date of the log and not of the request, and most fields are not
1831 * computed.
1832 */
1833
willy tarreaua1598082005-12-17 13:08:06 +01001834 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01001835
1836 pn = (log & LW_CLIP) ?
1837 (unsigned char *)&s->cli_addr.sin_addr :
1838 (unsigned char *)"\0\0\0\0";
1839
willy tarreaua1598082005-12-17 13:08:06 +01001840 uri = (log & LW_REQ) ? s->logs.uri : "<BADREQ>";
willy tarreau9fe663a2005-12-17 13:02:59 +01001841 pxid = p->id;
1842 //srv = (log & LW_SVID) ? s->srv->id : "<svid>";
willy tarreaua1598082005-12-17 13:08:06 +01001843 srv = ((p->to_log & LW_SVID) && s->srv != NULL) ? s->srv->id : "<NOSRV>";
1844
1845 if (p->to_log & LW_DATE) {
1846 struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
1847
1848 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",
1849 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1850 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
1851 tm->tm_hour, tm->tm_min, tm->tm_sec,
1852 pxid, srv,
1853 s->logs.t_request,
1854 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1855 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1856 s->logs.t_close,
1857 s->logs.status, s->logs.bytes,
1858 uri);
1859 }
1860 else {
1861 send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld \"%s\"\n",
1862 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1863 pxid, srv,
1864 s->logs.t_request,
1865 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
1866 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1867 s->logs.t_close,
1868 s->logs.status, s->logs.bytes,
1869 uri);
1870 }
1871
1872 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001873}
1874
willy tarreaue39cd132005-12-17 13:00:18 +01001875
1876/*
willy tarreau0f7af912005-12-17 12:21:26 +01001877 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 * to an accept. It tries to accept as many connections as possible.
1879 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001880 */
1881int event_accept(int fd) {
1882 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001883 struct session *s;
1884 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001885 int cfd;
1886 int one = 1;
1887
willy tarreau5cbea6f2005-12-17 12:48:26 +01001888 while (p->nbconn < p->maxconn) {
1889 struct sockaddr_in addr;
1890 int laddr = sizeof(addr);
1891 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1892 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001893
willy tarreau5cbea6f2005-12-17 12:48:26 +01001894 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1895 Alert("out of memory in event_accept().\n");
1896 FD_CLR(fd, StaticReadEvent);
1897 p->state = PR_STIDLE;
1898 close(cfd);
1899 return 0;
1900 }
willy tarreau0f7af912005-12-17 12:21:26 +01001901
willy tarreau5cbea6f2005-12-17 12:48:26 +01001902 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1903 Alert("out of memory in event_accept().\n");
1904 FD_CLR(fd, StaticReadEvent);
1905 p->state = PR_STIDLE;
1906 close(cfd);
1907 pool_free(session, s);
1908 return 0;
1909 }
willy tarreau0f7af912005-12-17 12:21:26 +01001910
willy tarreau5cbea6f2005-12-17 12:48:26 +01001911 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001912 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001913 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1914 close(cfd);
1915 pool_free(task, t);
1916 pool_free(session, s);
1917 return 0;
1918 }
willy tarreau0f7af912005-12-17 12:21:26 +01001919
willy tarreau5cbea6f2005-12-17 12:48:26 +01001920 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1921 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1922 (char *) &one, sizeof(one)) == -1)) {
1923 Alert("accept(): cannot set the socket in non blocking mode. 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 tarreau9fe663a2005-12-17 13:02:59 +01001930 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1931 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1932 t->state = TASK_IDLE;
1933 t->process = process_session;
1934 t->context = s;
1935
1936 s->task = t;
1937 s->proxy = p;
1938 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1939 s->srv_state = SV_STIDLE;
1940 s->req = s->rep = NULL; /* will be allocated later */
1941 s->flags = 0;
1942 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1943 s->cli_fd = cfd;
1944 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01001945 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01001946 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01001947
1948 s->logs.logwait = p->to_log;
1949 s->logs.tv_accept = now;
1950 s->logs.t_request = -1;
1951 s->logs.t_connect = -1;
1952 s->logs.t_data = -1;
1953 s->logs.t_close = 0;
1954 s->logs.uri = NULL;
1955 s->logs.status = -1;
1956 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01001957
willy tarreau5cbea6f2005-12-17 12:48:26 +01001958 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1959 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau535ae7a2005-12-17 12:58:00 +01001960 struct sockaddr_in sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001961 unsigned char *pn, *sn;
1962 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01001963
willy tarreau5cbea6f2005-12-17 12:48:26 +01001964 namelen = sizeof(sockname);
1965 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1966 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1967 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau535ae7a2005-12-17 12:58:00 +01001968 pn = (unsigned char *)&s->cli_addr.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001969
willy tarreau9fe663a2005-12-17 13:02:59 +01001970 if (p->to_log) {
1971 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01001972 if (s->logs.logwait & LW_CLIP)
1973 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01001974 sess_log(s);
1975 }
1976 else
1977 send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1978 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
1979 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1980 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau5cbea6f2005-12-17 12:48:26 +01001981 }
willy tarreau0f7af912005-12-17 12:21:26 +01001982
willy tarreau9fe663a2005-12-17 13:02:59 +01001983 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreauef900ab2005-12-17 12:52:52 +01001984 int len;
1985 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1986 write(1, trash, len);
1987 }
willy tarreau0f7af912005-12-17 12:21:26 +01001988
willy tarreau5cbea6f2005-12-17 12:48:26 +01001989 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1990 close(cfd); /* nothing can be done for this fd without memory */
1991 pool_free(task, t);
1992 pool_free(session, s);
1993 return 0;
1994 }
1995 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01001996 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001997 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1998 s->req->rlim = s->req->data + BUFSIZE;
1999 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
2000 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002001
willy tarreau5cbea6f2005-12-17 12:48:26 +01002002 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2003 pool_free(buffer, s->req);
2004 close(cfd); /* nothing can be done for this fd without memory */
2005 pool_free(task, t);
2006 pool_free(session, s);
2007 return 0;
2008 }
2009 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002010 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002011 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 +01002012
willy tarreau5cbea6f2005-12-17 12:48:26 +01002013 fdtab[cfd].read = &event_cli_read;
2014 fdtab[cfd].write = &event_cli_write;
2015 fdtab[cfd].owner = t;
2016 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002017
willy tarreau5cbea6f2005-12-17 12:48:26 +01002018 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreaue39cd132005-12-17 13:00:18 +01002019 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002020 }
2021 else {
2022 FD_SET(cfd, StaticReadEvent);
2023 }
2024
2025 fd_insert(cfd);
2026
2027 tv_eternity(&s->cnexpire);
2028 tv_eternity(&s->srexpire);
2029 tv_eternity(&s->swexpire);
2030 tv_eternity(&s->cwexpire);
2031
2032 if (s->proxy->clitimeout)
2033 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2034 else
2035 tv_eternity(&s->crexpire);
2036
2037 t->expire = s->crexpire;
2038
2039 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002040
2041 if (p->mode != PR_MODE_HEALTH)
2042 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002043
2044 p->nbconn++;
2045 actconn++;
2046 totalconn++;
2047
2048 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2049 } /* end of while (p->nbconn < p->maxconn) */
2050 return 0;
2051}
willy tarreau0f7af912005-12-17 12:21:26 +01002052
willy tarreau0f7af912005-12-17 12:21:26 +01002053
willy tarreau5cbea6f2005-12-17 12:48:26 +01002054/*
2055 * This function is used only for server health-checks. It handles
2056 * the connection acknowledgement and returns 1 if the socket is OK,
2057 * or -1 if an error occured.
2058 */
2059int event_srv_hck(int fd) {
2060 struct task *t = fdtab[fd].owner;
2061 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002062
willy tarreau5cbea6f2005-12-17 12:48:26 +01002063 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002064 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002065 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2066 if (skerr)
2067 s->result = -1;
2068 else
2069 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002070
willy tarreau5cbea6f2005-12-17 12:48:26 +01002071 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002072 return 0;
2073}
2074
2075
2076/*
2077 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2078 * and moves <end> just after the end of <str>.
2079 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2080 * the shift value (positive or negative) is returned.
2081 * If there's no space left, the move is not done.
2082 *
2083 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002084int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002085 int delta;
2086 int len;
2087
2088 len = strlen(str);
2089 delta = len - (end - pos);
2090
2091 if (delta + b->r >= b->data + BUFSIZE)
2092 return 0; /* no space left */
2093
2094 /* first, protect the end of the buffer */
2095 memmove(end + delta, end, b->data + b->l - end);
2096
2097 /* now, copy str over pos */
2098 memcpy(pos, str,len);
2099
willy tarreau5cbea6f2005-12-17 12:48:26 +01002100 /* we only move data after the displaced zone */
2101 if (b->r > pos) b->r += delta;
2102 if (b->w > pos) b->w += delta;
2103 if (b->h > pos) b->h += delta;
2104 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002105 b->l += delta;
2106
2107 return delta;
2108}
2109
willy tarreau240afa62005-12-17 13:14:35 +01002110/* same except that the string len is given, which allows str to be NULL if
2111 * len is 0.
2112 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002113int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002114 int delta;
2115
2116 delta = len - (end - pos);
2117
2118 if (delta + b->r >= b->data + BUFSIZE)
2119 return 0; /* no space left */
2120
2121 /* first, protect the end of the buffer */
2122 memmove(end + delta, end, b->data + b->l - end);
2123
2124 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002125 if (len)
2126 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002127
willy tarreau5cbea6f2005-12-17 12:48:26 +01002128 /* we only move data after the displaced zone */
2129 if (b->r > pos) b->r += delta;
2130 if (b->w > pos) b->w += delta;
2131 if (b->h > pos) b->h += delta;
2132 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002133 b->l += delta;
2134
2135 return delta;
2136}
2137
2138
2139int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2140 char *old_dst = dst;
2141
2142 while (*str) {
2143 if (*str == '\\') {
2144 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002145 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002146 int len, num;
2147
2148 num = *str - '0';
2149 str++;
2150
2151 if (matches[num].rm_so > -1) {
2152 len = matches[num].rm_eo - matches[num].rm_so;
2153 memcpy(dst, src + matches[num].rm_so, len);
2154 dst += len;
2155 }
2156
2157 }
2158 else if (*str == 'x') {
2159 unsigned char hex1, hex2;
2160 str++;
2161
2162 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2163
2164 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2165 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2166 *dst++ = (hex1<<4) + hex2;
2167 }
2168 else
2169 *dst++ = *str++;
2170 }
2171 else
2172 *dst++ = *str++;
2173 }
2174 *dst = 0;
2175 return dst - old_dst;
2176}
2177
willy tarreau9fe663a2005-12-17 13:02:59 +01002178
willy tarreau0f7af912005-12-17 12:21:26 +01002179/*
2180 * manages the client FSM and its socket. BTW, it also tries to handle the
2181 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2182 * 0 else.
2183 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002184int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002185 int s = t->srv_state;
2186 int c = t->cli_state;
2187 struct buffer *req = t->req;
2188 struct buffer *rep = t->rep;
2189
willy tarreau750a4722005-12-17 13:21:24 +01002190#ifdef DEBUG_FULL
2191 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2192#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002193 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2194 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2195 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2196 //);
2197 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002198 /* now parse the partial (or complete) headers */
2199 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2200 char *ptr;
2201 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01002202
willy tarreau5cbea6f2005-12-17 12:48:26 +01002203 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002204
willy tarreau0f7af912005-12-17 12:21:26 +01002205 /* look for the end of the current header */
2206 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2207 ptr++;
2208
willy tarreau5cbea6f2005-12-17 12:48:26 +01002209 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002210 int line, len;
2211 /* we can only get here after an end of headers */
2212 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002213
willy tarreaue39cd132005-12-17 13:00:18 +01002214 if (t->flags & SN_CLDENY) {
2215 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002216 t->logs.status = 403;
willy tarreau750a4722005-12-17 13:21:24 +01002217 if (t->proxy->mode == PR_MODE_HTTP)
2218 client_retnclose(t, strlen(HTTP_403), HTTP_403);
willy tarreaue39cd132005-12-17 13:00:18 +01002219 return 1;
2220 }
2221
willy tarreau5cbea6f2005-12-17 12:48:26 +01002222 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002223 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2224 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002225 }
willy tarreau0f7af912005-12-17 12:21:26 +01002226
willy tarreau9fe663a2005-12-17 13:02:59 +01002227 if (t->proxy->options & PR_O_FWDFOR) {
2228 /* insert an X-Forwarded-For header */
2229 unsigned char *pn;
2230 pn = (unsigned char *)&t->cli_addr.sin_addr;
willy tarreau750a4722005-12-17 13:21:24 +01002231 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01002232 pn[0], pn[1], pn[2], pn[3]);
willy tarreau750a4722005-12-17 13:21:24 +01002233 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau9fe663a2005-12-17 13:02:59 +01002234 }
2235
willy tarreau5cbea6f2005-12-17 12:48:26 +01002236 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002237 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002238
willy tarreau750a4722005-12-17 13:21:24 +01002239 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002240 /* FIXME: we'll set the client in a wait state while we try to
2241 * connect to the server. Is this really needed ? wouldn't it be
2242 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002243 //FD_CLR(t->cli_fd, StaticReadEvent);
2244 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002245 break;
2246 }
willy tarreau0f7af912005-12-17 12:21:26 +01002247
willy tarreau5cbea6f2005-12-17 12:48:26 +01002248 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2249 if (ptr > req->r - 2) {
2250 /* this is a partial header, let's wait for more to come */
2251 req->lr = ptr;
2252 break;
2253 }
willy tarreau0f7af912005-12-17 12:21:26 +01002254
willy tarreau5cbea6f2005-12-17 12:48:26 +01002255 /* now we know that *ptr is either \r or \n,
2256 * and that there are at least 1 char after it.
2257 */
2258 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2259 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2260 else
2261 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002262
willy tarreau5cbea6f2005-12-17 12:48:26 +01002263 /*
2264 * now we know that we have a full header ; we can do whatever
2265 * we want with these pointers :
2266 * req->h = beginning of header
2267 * ptr = end of header (first \r or \n)
2268 * req->lr = beginning of next line (next rep->h)
2269 * req->r = end of data (not used at this stage)
2270 */
willy tarreau0f7af912005-12-17 12:21:26 +01002271
willy tarreaua1598082005-12-17 13:08:06 +01002272 if (t->logs.logwait & LW_REQ &&
2273 t->proxy->mode & PR_MODE_HTTP) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002274 /* we have a complete HTTP request that we must log */
2275 int urilen;
2276
willy tarreaua1598082005-12-17 13:08:06 +01002277 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002278 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002279 t->logs.status = 500;
2280 if (t->proxy->mode == PR_MODE_HTTP)
2281 client_retnclose(t, strlen(HTTP_500), HTTP_500);
willy tarreau9fe663a2005-12-17 13:02:59 +01002282 return 1;
2283 }
2284
2285 urilen = ptr - req->h;
2286 if (urilen >= REQURI_LEN)
2287 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002288 memcpy(t->logs.uri, req->h, urilen);
2289 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002290
willy tarreaua1598082005-12-17 13:08:06 +01002291 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002292 sess_log(t);
2293 }
2294
willy tarreau5cbea6f2005-12-17 12:48:26 +01002295 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002296
willy tarreau9fe663a2005-12-17 13:02:59 +01002297 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002298 int len, max;
2299 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2300 max = ptr - req->h;
2301 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002302 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002303 trash[len++] = '\n';
2304 write(1, trash, len);
2305 }
willy tarreau0f7af912005-12-17 12:21:26 +01002306
willy tarreau5cbea6f2005-12-17 12:48:26 +01002307 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002308 if (t->proxy->req_exp != NULL && !(t->flags & SN_CLDENY)) {
2309 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002310 char term;
2311
2312 term = *ptr;
2313 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002314 exp = t->proxy->req_exp;
2315 do {
2316 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
2317 switch (exp->action) {
2318 case ACT_ALLOW:
2319 if (!(t->flags & SN_CLDENY))
2320 t->flags |= SN_CLALLOW;
2321 break;
2322 case ACT_REPLACE:
2323 if (!(t->flags & SN_CLDENY)) {
2324 int len = exp_replace(trash, req->h, exp->replace, pmatch);
2325 ptr += buffer_replace2(req, req->h, ptr, trash, len);
2326 }
2327 break;
2328 case ACT_REMOVE:
2329 if (!(t->flags & SN_CLDENY))
2330 delete_header = 1;
2331 break;
2332 case ACT_DENY:
2333 if (!(t->flags & SN_CLALLOW))
2334 t->flags |= SN_CLDENY;
2335 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002336 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002337 break;
willy tarreau0f7af912005-12-17 12:21:26 +01002338 }
willy tarreaue39cd132005-12-17 13:00:18 +01002339 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002340 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01002341 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002342
willy tarreau240afa62005-12-17 13:14:35 +01002343 /* Now look for cookies. Conforming to RFC2109, we have to support
2344 * attributes whose name begin with a '$', and associate them with
2345 * the right cookie, if we want to delete this cookie.
2346 * So there are 3 cases for each cookie read :
2347 * 1) it's a special attribute, beginning with a '$' : ignore it.
2348 * 2) it's a server id cookie that we *MAY* want to delete : save
2349 * some pointers on it (last semi-colon, beginning of cookie...)
2350 * 3) it's an application cookie : we *MAY* have to delete a previous
2351 * "special" cookie.
2352 * At the end of loop, if a "special" cookie remains, we may have to
2353 * remove it. If no application cookie persists in the header, we
2354 * *MUST* delete it
2355 */
2356 if (!delete_header && (t->proxy->cookie_name != NULL)
2357 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002358 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
2359 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01002360 char *del_colon, *del_cookie, *colon;
2361 int app_cookies;
2362
willy tarreau5cbea6f2005-12-17 12:48:26 +01002363 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01002364 colon = p1;
2365 /* del_cookie == NULL => nothing to be deleted */
2366 del_colon = del_cookie = NULL;
2367 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002368
2369 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01002370 /* skip spaces and colons, but keep an eye on these ones */
2371 while (p1 < ptr) {
2372 if (*p1 == ';' || *p1 == ',')
2373 colon = p1;
2374 else if (!isspace((int)*p1))
2375 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002376 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01002377 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002378
2379 if (p1 == ptr)
2380 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002381
2382 /* p1 is at the beginning of the cookie name */
2383 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01002384 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002385 p2++;
2386
2387 if (p2 == ptr)
2388 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002389
2390 p3 = p2 + 1; /* skips the '=' sign */
2391 if (p3 == ptr)
2392 break;
2393
willy tarreau240afa62005-12-17 13:14:35 +01002394 p4 = p3;
2395 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002396 p4++;
2397
2398 /* here, we have the cookie name between p1 and p2,
2399 * and its value between p3 and p4.
2400 * we can process it.
2401 */
2402
willy tarreau240afa62005-12-17 13:14:35 +01002403 if (*p1 == '$') {
2404 /* skip this one */
2405 }
2406 else if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2407 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002408 /* Cool... it's the right one */
2409 struct server *srv = t->proxy->srv;
2410
2411 while (srv &&
2412 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
2413 srv = srv->next;
2414 }
2415
2416 if (srv) { /* we found the server */
willy tarreaue39cd132005-12-17 13:00:18 +01002417 t->flags |= SN_DIRECT;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002418 t->srv = srv;
2419 }
willy tarreau240afa62005-12-17 13:14:35 +01002420 /* if this cookie was set in insert+indirect mode, then it's better that the
2421 * server never sees it.
2422 */
2423 if (del_cookie == NULL &&
2424 (t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
2425 del_cookie = p1;
2426 del_colon = colon;
2427 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002428 }
2429 else {
willy tarreau240afa62005-12-17 13:14:35 +01002430 /* now we know that we must keep this cookie since it's
2431 * not ours. But if we wanted to delete our cookie
2432 * earlier, we cannot remove the complete header, but we
2433 * can remove the previous block itself.
2434 */
2435 app_cookies++;
2436
2437 if (del_cookie != NULL) {
2438 buffer_replace2(req, del_cookie, p1, NULL, 0);
2439 p4 -= (p1 - del_cookie);
2440 ptr -= (p1 - del_cookie);
2441 del_cookie = del_colon = NULL;
2442 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002443 }
willy tarreau240afa62005-12-17 13:14:35 +01002444
willy tarreau5cbea6f2005-12-17 12:48:26 +01002445 /* we'll have to look for another cookie ... */
2446 p1 = p4;
2447 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01002448
2449 /* There's no more cookie on this line.
2450 * We may have marked the last one(s) for deletion.
2451 * We must do this now in two ways :
2452 * - if there is no app cookie, we simply delete the header ;
2453 * - if there are app cookies, we must delete the end of the
2454 * string properly, including the colon/semi-colon before
2455 * the cookie name.
2456 */
2457 if (del_cookie != NULL) {
2458 if (app_cookies) {
2459 buffer_replace2(req, del_colon, ptr, NULL, 0);
2460 /* WARNING! <ptr> becomes invalid for now. If some code
2461 * below needs to rely on it before the end of the global
2462 * header loop, we need to correct it with this code :
2463 * ptr = del_colon;
2464 */
2465 }
2466 else
2467 delete_header = 1;
2468 }
2469 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002470
2471 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002472 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01002473 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01002474 }
willy tarreau240afa62005-12-17 13:14:35 +01002475 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
2476
willy tarreau5cbea6f2005-12-17 12:48:26 +01002477 req->h = req->lr;
2478 } /* while (req->lr < req->r) */
2479
2480 /* end of header processing (even if incomplete) */
2481
willy tarreauef900ab2005-12-17 12:52:52 +01002482 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2483 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2484 * full. We cannot loop here since event_cli_read will disable it only if
2485 * req->l == rlim-data
2486 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002487 FD_SET(t->cli_fd, StaticReadEvent);
2488 if (t->proxy->clitimeout)
2489 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2490 else
2491 tv_eternity(&t->crexpire);
2492 }
2493
willy tarreaue39cd132005-12-17 13:00:18 +01002494 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01002495 * won't be able to free more later, so the session will never terminate.
2496 */
willy tarreaue39cd132005-12-17 13:00:18 +01002497 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01002498 t->logs.status = 400;
willy tarreau750a4722005-12-17 13:21:24 +01002499 if (t->proxy->mode == PR_MODE_HTTP)
2500 client_retnclose(t, strlen(HTTP_400), HTTP_400);
willy tarreaue39cd132005-12-17 13:00:18 +01002501 return 1;
2502 }
2503 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2504 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
2505
2506 /* read timeout, read error, or last read : give up.
2507 * since we are in header mode, if there's no space left for headers, we
2508 * won't be able to free more later, so the session will never terminate.
2509 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002510 tv_eternity(&t->crexpire);
2511 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002512 t->cli_state = CL_STCLOSE;
2513 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002514 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002515
2516 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002517 }
2518 else if (c == CL_STDATA) {
2519 /* read or write error */
2520 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002521 tv_eternity(&t->crexpire);
2522 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002523 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002524 t->cli_state = CL_STCLOSE;
2525 return 1;
2526 }
2527 /* read timeout, last read, or end of server write */
2528 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2529 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002530 FD_CLR(t->cli_fd, StaticReadEvent);
2531 // if (req->l == 0) /* nothing to write on the server side */
2532 // FD_CLR(t->srv_fd, StaticWriteEvent);
2533 tv_eternity(&t->crexpire);
2534 shutdown(t->cli_fd, SHUT_RD);
2535 t->cli_state = CL_STSHUTR;
2536 return 1;
2537 }
2538 /* write timeout, or last server read and buffer empty */
2539 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2540 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002541 FD_CLR(t->cli_fd, StaticWriteEvent);
2542 tv_eternity(&t->cwexpire);
2543 shutdown(t->cli_fd, SHUT_WR);
2544 t->cli_state = CL_STSHUTW;
2545 return 1;
2546 }
2547
willy tarreauef900ab2005-12-17 12:52:52 +01002548 if (req->l >= req->rlim - req->data) {
2549 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002550 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002551 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002552 FD_CLR(t->cli_fd, StaticReadEvent);
2553 tv_eternity(&t->crexpire);
2554 }
2555 }
2556 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002557 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002558 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2559 FD_SET(t->cli_fd, StaticReadEvent);
2560 if (t->proxy->clitimeout)
2561 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2562 else
2563 tv_eternity(&t->crexpire);
2564 }
2565 }
2566
2567 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002568 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002569 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2570 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2571 tv_eternity(&t->cwexpire);
2572 }
2573 }
2574 else { /* buffer not empty */
2575 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2576 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2577 if (t->proxy->clitimeout)
2578 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2579 else
2580 tv_eternity(&t->cwexpire);
2581 }
2582 }
2583 return 0; /* other cases change nothing */
2584 }
2585 else if (c == CL_STSHUTR) {
2586 if ((t->res_cw == RES_ERROR) ||
2587 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002588 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002589 tv_eternity(&t->cwexpire);
2590 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002591 t->cli_state = CL_STCLOSE;
2592 return 1;
2593 }
2594 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002595 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002596 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2597 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2598 tv_eternity(&t->cwexpire);
2599 }
2600 }
2601 else { /* buffer not empty */
2602 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2603 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2604 if (t->proxy->clitimeout)
2605 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2606 else
2607 tv_eternity(&t->cwexpire);
2608 }
2609 }
2610 return 0;
2611 }
2612 else if (c == CL_STSHUTW) {
2613 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002614 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002615 tv_eternity(&t->crexpire);
2616 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002617 t->cli_state = CL_STCLOSE;
2618 return 1;
2619 }
willy tarreauef900ab2005-12-17 12:52:52 +01002620 else if (req->l >= req->rlim - req->data) {
2621 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002622 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002623 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002624 FD_CLR(t->cli_fd, StaticReadEvent);
2625 tv_eternity(&t->crexpire);
2626 }
2627 }
2628 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002629 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002630 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2631 FD_SET(t->cli_fd, StaticReadEvent);
2632 if (t->proxy->clitimeout)
2633 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2634 else
2635 tv_eternity(&t->crexpire);
2636 }
2637 }
2638 return 0;
2639 }
2640 else { /* CL_STCLOSE: nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01002641 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002642 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002643 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002644 write(1, trash, len);
2645 }
2646 return 0;
2647 }
2648 return 0;
2649}
2650
2651
2652/*
2653 * manages the server FSM and its socket. It returns 1 if a state has changed
2654 * (and a resync may be needed), 0 else.
2655 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002657 int s = t->srv_state;
2658 int c = t->cli_state;
2659 struct buffer *req = t->req;
2660 struct buffer *rep = t->rep;
2661
willy tarreau750a4722005-12-17 13:21:24 +01002662#ifdef DEBUG_FULL
2663 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2664#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002665 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2666 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2667 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2668 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002669 if (s == SV_STIDLE) {
2670 if (c == CL_STHEADERS)
2671 return 0; /* stay in idle, waiting for data to reach the client side */
2672 else if (c == CL_STCLOSE ||
2673 c == CL_STSHUTW ||
2674 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2675 tv_eternity(&t->cnexpire);
2676 t->srv_state = SV_STCLOSE;
2677 return 1;
2678 }
2679 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002680 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002681 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2682 t->srv_state = SV_STCONN;
2683 }
2684 else { /* try again */
2685 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002686 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002687 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002688 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2689 }
2690
2691 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002692 t->srv_state = SV_STCONN;
2693 break;
2694 }
2695 }
2696 if (t->conn_retries < 0) {
2697 /* if conn_retries < 0 or other error, let's abort */
2698 tv_eternity(&t->cnexpire);
2699 t->srv_state = SV_STCLOSE;
willy tarreaua1598082005-12-17 13:08:06 +01002700 t->logs.status = 502;
willy tarreau750a4722005-12-17 13:21:24 +01002701 if (t->proxy->mode == PR_MODE_HTTP)
2702 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002703 }
2704 }
2705 return 1;
2706 }
2707 }
2708 else if (s == SV_STCONN) { /* connection in progress */
2709 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2710 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2711 return 0; /* nothing changed */
2712 }
2713 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2714 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2715 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002716 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002717 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002718 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002719 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002720 if (t->conn_retries >= 0) {
2721 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002722 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002723 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2724 }
2725 if (connect_server(t) == 0)
2726 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002727 }
2728 /* if conn_retries < 0 or other error, let's abort */
2729 tv_eternity(&t->cnexpire);
2730 t->srv_state = SV_STCLOSE;
willy tarreau750a4722005-12-17 13:21:24 +01002731 t->logs.status = 502;
2732 if (t->proxy->mode == PR_MODE_HTTP)
2733 client_return(t, strlen(HTTP_502), HTTP_502);
willy tarreau0f7af912005-12-17 12:21:26 +01002734 return 1;
2735 }
2736 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01002737 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01002738
willy tarreau0f7af912005-12-17 12:21:26 +01002739 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2740 if (req->l == 0) /* nothing to write */
2741 FD_CLR(t->srv_fd, StaticWriteEvent);
2742 else /* need the right to write */
2743 FD_SET(t->srv_fd, StaticWriteEvent);
2744
2745 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2746 FD_SET(t->srv_fd, StaticReadEvent);
2747 if (t->proxy->srvtimeout)
2748 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2749 else
2750 tv_eternity(&t->srexpire);
2751
2752 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002753 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002754 }
willy tarreauef900ab2005-12-17 12:52:52 +01002755 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002756 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002757 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2758 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002759 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002760 return 1;
2761 }
2762 }
2763 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002764
2765 /* now parse the partial (or complete) headers */
2766 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2767 char *ptr;
2768 int delete_header;
2769
2770 ptr = rep->lr;
2771
2772 /* look for the end of the current header */
2773 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2774 ptr++;
2775
2776 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002777 int line, len;
2778
2779 /* we can only get here after an end of headers */
2780 /* we'll have something else to do here : add new headers ... */
2781
willy tarreaue39cd132005-12-17 13:00:18 +01002782 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002783 /* the server is known, it's not the one the client requested, we have to
2784 * insert a set-cookie here.
2785 */
willy tarreau750a4722005-12-17 13:21:24 +01002786 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01002787 t->proxy->cookie_name, t->srv->cookie);
willy tarreau750a4722005-12-17 13:21:24 +01002788
2789 /* Here, we will tell an eventual cache on the client side that we don't
2790 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
2791 * Some caches understand the correct form: 'no-cache="set-cookie"', but
2792 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
2793 */
willy tarreau240afa62005-12-17 13:14:35 +01002794 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01002795 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
2796 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreau240afa62005-12-17 13:14:35 +01002797
willy tarreau750a4722005-12-17 13:21:24 +01002798 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002799 }
2800
2801 /* headers to be added */
2802 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002803 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
2804 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002805 }
2806
2807 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002808 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01002809 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002810 break;
2811 }
2812
2813 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2814 if (ptr > rep->r - 2) {
2815 /* this is a partial header, let's wait for more to come */
2816 rep->lr = ptr;
2817 break;
2818 }
2819
2820 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2821 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2822
2823 /* now we know that *ptr is either \r or \n,
2824 * and that there are at least 1 char after it.
2825 */
2826 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2827 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2828 else
2829 rep->lr = ptr + 2; /* \r\n or \n\r */
2830
2831 /*
2832 * now we know that we have a full header ; we can do whatever
2833 * we want with these pointers :
2834 * rep->h = beginning of header
2835 * ptr = end of header (first \r or \n)
2836 * rep->lr = beginning of next line (next rep->h)
2837 * rep->r = end of data (not used at this stage)
2838 */
2839
willy tarreaua1598082005-12-17 13:08:06 +01002840
2841 if (t->logs.logwait & LW_RESP) {
2842 t->logs.logwait &= ~LW_RESP;
2843 t->logs.status = atoi(rep->h + 9);
2844 }
2845
willy tarreau5cbea6f2005-12-17 12:48:26 +01002846 delete_header = 0;
2847
willy tarreau9fe663a2005-12-17 13:02:59 +01002848 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849 int len, max;
2850 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2851 max = ptr - rep->h;
2852 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002853 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002854 trash[len++] = '\n';
2855 write(1, trash, len);
2856 }
2857
2858 /* try headers regexps */
willy tarreaue39cd132005-12-17 13:00:18 +01002859 if (t->proxy->rsp_exp != NULL && !(t->flags & SN_SVDENY)) {
2860 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002861 char term;
2862
2863 term = *ptr;
2864 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01002865 exp = t->proxy->rsp_exp;
2866 do {
2867 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2868 switch (exp->action) {
2869 case ACT_ALLOW:
2870 if (!(t->flags & SN_SVDENY))
2871 t->flags |= SN_SVALLOW;
2872 break;
2873 case ACT_REPLACE:
2874 if (!(t->flags & SN_SVDENY)) {
2875 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2876 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2877 }
2878 break;
2879 case ACT_REMOVE:
2880 if (!(t->flags & SN_SVDENY))
2881 delete_header = 1;
2882 break;
2883 case ACT_DENY:
2884 if (!(t->flags & SN_SVALLOW))
2885 t->flags |= SN_SVDENY;
2886 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002887 }
2888 break;
2889 }
willy tarreaue39cd132005-12-17 13:00:18 +01002890 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002891 *ptr = term; /* restore the string terminator */
2892 }
2893
2894 /* check for server cookies */
willy tarreau240afa62005-12-17 13:14:35 +01002895 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY)
2896 && (t->proxy->cookie_name != NULL) && (ptr >= rep->h + 12)
2897 && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002898 char *p1, *p2, *p3, *p4;
2899
2900 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2901
2902 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01002903 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002904 p1++;
2905
2906 if (p1 == ptr || *p1 == ';') /* end of cookie */
2907 break;
2908
2909 /* p1 is at the beginning of the cookie name */
2910 p2 = p1;
2911
2912 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2913 p2++;
2914
2915 if (p2 == ptr || *p2 == ';') /* next cookie */
2916 break;
2917
2918 p3 = p2 + 1; /* skips the '=' sign */
2919 if (p3 == ptr)
2920 break;
2921
2922 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01002923 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01002924 p4++;
2925
2926 /* here, we have the cookie name between p1 and p2,
2927 * and its value between p3 and p4.
2928 * we can process it.
2929 */
2930
2931 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2932 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2933 /* Cool... it's the right one */
2934
2935 /* If the cookie is in insert mode on a known server, we'll delete
2936 * this occurrence because we'll insert another one later.
2937 * We'll delete it too if the "indirect" option is set and we're in
2938 * a direct access. */
2939 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01002940 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002941 /* this header must be deleted */
2942 delete_header = 1;
2943 }
2944 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2945 /* replace bytes p3->p4 with the cookie name associated
2946 * with this server since we know it.
2947 */
2948 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2949 }
2950 break;
2951 }
2952 else {
2953 // fprintf(stderr,"Ignoring unknown cookie : ");
2954 // write(2, p1, p2-p1);
2955 // fprintf(stderr," = ");
2956 // write(2, p3, p4-p3);
2957 // fprintf(stderr,"\n");
2958 }
2959 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2960 } /* we're now at the end of the cookie value */
2961 } /* end of cookie processing */
2962
2963 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01002964 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002965 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01002966
willy tarreau5cbea6f2005-12-17 12:48:26 +01002967 rep->h = rep->lr;
2968 } /* while (rep->lr < rep->r) */
2969
2970 /* end of header processing (even if incomplete) */
2971
willy tarreauef900ab2005-12-17 12:52:52 +01002972 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2973 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2974 * full. We cannot loop here since event_srv_read will disable it only if
2975 * rep->l == rlim-data
2976 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002977 FD_SET(t->srv_fd, StaticReadEvent);
2978 if (t->proxy->srvtimeout)
2979 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2980 else
2981 tv_eternity(&t->srexpire);
2982 }
willy tarreau0f7af912005-12-17 12:21:26 +01002983
2984 /* read or write error */
2985 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002986 tv_eternity(&t->srexpire);
2987 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002988 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002989 t->srv_state = SV_STCLOSE;
2990 return 1;
2991 }
willy tarreauef900ab2005-12-17 12:52:52 +01002992 /* read timeout, last read, or end of client write
2993 * since we are in header mode, if there's no space left for headers, we
2994 * won't be able to free more later, so the session will never terminate.
2995 */
2996 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2997 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002998 FD_CLR(t->srv_fd, StaticReadEvent);
2999 tv_eternity(&t->srexpire);
3000 shutdown(t->srv_fd, SHUT_RD);
3001 t->srv_state = SV_STSHUTR;
3002 return 1;
3003
3004 }
3005 /* write timeout, or last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01003006 /* FIXME!!! here, we don't want to switch to SHUTW if the
3007 * client shuts read too early, because we may still have
3008 * some work to do on the headers.
3009 */
3010 else if (((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) ||
willy tarreau0f7af912005-12-17 12:21:26 +01003011 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
3012 FD_CLR(t->srv_fd, StaticWriteEvent);
3013 tv_eternity(&t->swexpire);
3014 shutdown(t->srv_fd, SHUT_WR);
3015 t->srv_state = SV_STSHUTW;
3016 return 1;
3017 }
3018
3019 if (req->l == 0) {
3020 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3021 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3022 tv_eternity(&t->swexpire);
3023 }
3024 }
3025 else { /* client buffer not empty */
3026 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3027 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3028 if (t->proxy->srvtimeout)
3029 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3030 else
3031 tv_eternity(&t->swexpire);
3032 }
3033 }
3034
willy tarreau5cbea6f2005-12-17 12:48:26 +01003035 /* be nice with the client side which would like to send a complete header
3036 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
3037 * would read all remaining data at once ! The client should not write past rep->lr
3038 * when the server is in header state.
3039 */
3040 //return header_processed;
3041 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003042 }
3043 else if (s == SV_STDATA) {
3044 /* read or write error */
3045 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003046 tv_eternity(&t->srexpire);
3047 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003048 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003049 t->srv_state = SV_STCLOSE;
3050 return 1;
3051 }
3052 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01003053 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
3054 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003055 FD_CLR(t->srv_fd, StaticReadEvent);
3056 tv_eternity(&t->srexpire);
3057 shutdown(t->srv_fd, SHUT_RD);
3058 t->srv_state = SV_STSHUTR;
3059 return 1;
3060
3061 }
3062 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01003063 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
3064 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003065 FD_CLR(t->srv_fd, StaticWriteEvent);
3066 tv_eternity(&t->swexpire);
3067 shutdown(t->srv_fd, SHUT_WR);
3068 t->srv_state = SV_STSHUTW;
3069 return 1;
3070 }
3071 else if (req->l == 0) {
3072 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3073 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3074 tv_eternity(&t->swexpire);
3075 }
3076 }
3077 else { /* buffer not empty */
3078 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3079 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3080 if (t->proxy->srvtimeout)
3081 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3082 else
3083 tv_eternity(&t->swexpire);
3084 }
3085 }
3086
3087 if (rep->l == BUFSIZE) { /* no room to read more data */
3088 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3089 FD_CLR(t->srv_fd, StaticReadEvent);
3090 tv_eternity(&t->srexpire);
3091 }
3092 }
3093 else {
3094 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3095 FD_SET(t->srv_fd, StaticReadEvent);
3096 if (t->proxy->srvtimeout)
3097 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3098 else
3099 tv_eternity(&t->srexpire);
3100 }
3101 }
3102
3103 return 0; /* other cases change nothing */
3104 }
3105 else if (s == SV_STSHUTR) {
3106 if ((t->res_sw == RES_ERROR) ||
3107 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
3108 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003109 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003110 tv_eternity(&t->swexpire);
3111 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003112 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003113 t->srv_state = SV_STCLOSE;
3114 return 1;
3115 }
3116 else if (req->l == 0) {
3117 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3118 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
3119 tv_eternity(&t->swexpire);
3120 }
3121 }
3122 else { /* buffer not empty */
3123 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3124 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
3125 if (t->proxy->srvtimeout)
3126 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3127 else
3128 tv_eternity(&t->swexpire);
3129 }
3130 }
3131 return 0;
3132 }
3133 else if (s == SV_STSHUTW) {
3134 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
3135 c == CL_STSHUTW || c == CL_STCLOSE ||
3136 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003137 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003138 tv_eternity(&t->srexpire);
3139 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003140 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003141 t->srv_state = SV_STCLOSE;
3142 return 1;
3143 }
3144 else if (rep->l == BUFSIZE) { /* no room to read more data */
3145 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
3146 FD_CLR(t->srv_fd, StaticReadEvent);
3147 tv_eternity(&t->srexpire);
3148 }
3149 }
3150 else {
3151 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
3152 FD_SET(t->srv_fd, StaticReadEvent);
3153 if (t->proxy->srvtimeout)
3154 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3155 else
3156 tv_eternity(&t->srexpire);
3157 }
3158 }
3159 return 0;
3160 }
3161 else { /* SV_STCLOSE : nothing to do */
willy tarreau9fe663a2005-12-17 13:02:59 +01003162 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003163 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003164 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003165 write(1, trash, len);
3166 }
3167 return 0;
3168 }
3169 return 0;
3170}
3171
3172
willy tarreau5cbea6f2005-12-17 12:48:26 +01003173/* Processes the client and server jobs of a session task, then
3174 * puts it back to the wait queue in a clean state, or
3175 * cleans up its resources if it must be deleted. Returns
3176 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01003177 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003178int process_session(struct task *t) {
3179 struct session *s = t->context;
3180 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003181
willy tarreau5cbea6f2005-12-17 12:48:26 +01003182 do {
3183 fsm_resync = 0;
3184 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3185 fsm_resync |= process_cli(s);
3186 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3187 fsm_resync |= process_srv(s);
3188 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
3189 } while (fsm_resync);
3190
3191 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003192 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003193 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01003194
willy tarreau5cbea6f2005-12-17 12:48:26 +01003195 tv_min(&min1, &s->crexpire, &s->cwexpire);
3196 tv_min(&min2, &s->srexpire, &s->swexpire);
3197 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003198 tv_min(&t->expire, &min1, &min2);
3199
3200 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003201 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01003202
willy tarreau5cbea6f2005-12-17 12:48:26 +01003203 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01003204 }
3205
willy tarreau5cbea6f2005-12-17 12:48:26 +01003206 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01003207 actconn--;
3208
willy tarreau9fe663a2005-12-17 13:02:59 +01003209 if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003210 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003211 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003212 write(1, trash, len);
3213 }
3214
willy tarreau750a4722005-12-17 13:21:24 +01003215 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003216 if (s->rep != NULL)
3217 s->logs.bytes = s->rep->total;
3218
willy tarreau9fe663a2005-12-17 13:02:59 +01003219 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01003220 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01003221 sess_log(s);
3222
willy tarreau0f7af912005-12-17 12:21:26 +01003223 /* the task MUST not be in the run queue anymore */
3224 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003225 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01003226 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003227 return -1; /* rest in peace for eternity */
3228}
3229
3230
3231
3232/*
3233 * manages a server health-check. Returns
3234 * the time the task accepts to wait, or -1 for infinity.
3235 */
3236int process_chk(struct task *t) {
3237 struct server *s = t->context;
3238 int fd = s->curfd;
3239 int one = 1;
3240
willy tarreauef900ab2005-12-17 12:52:52 +01003241 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003242
3243 if (fd < 0) { /* no check currently running */
3244 //fprintf(stderr, "process_chk: 2\n");
3245 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
3246 task_queue(t); /* restore t to its place in the task list */
3247 return tv_remain(&now, &t->expire);
3248 }
3249
3250 /* we'll initiate a new check */
3251 s->result = 0; /* no result yet */
3252 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003253 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01003254 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
3255 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
3256 //fprintf(stderr, "process_chk: 3\n");
3257
3258 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
3259 /* OK, connection in progress or established */
3260
3261 //fprintf(stderr, "process_chk: 4\n");
3262
3263 s->curfd = fd; /* that's how we know a test is in progress ;-) */
3264 fdtab[fd].owner = t;
3265 fdtab[fd].read = NULL;
3266 fdtab[fd].write = &event_srv_hck;
3267 fdtab[fd].state = FD_STCONN; /* connection in progress */
3268 FD_SET(fd, StaticWriteEvent); /* for connect status */
3269 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003270 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3271 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003272 task_queue(t); /* restore t to its place in the task list */
3273 return tv_remain(&now, &t->expire);
3274 }
3275 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
3276 s->result = -1; /* a real error */
3277 }
3278 }
3279 //fprintf(stderr, "process_chk: 5\n");
3280 close(fd);
3281 }
3282
3283 if (!s->result) { /* nothing done */
3284 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003285 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003286 task_queue(t); /* restore t to its place in the task list */
3287 return tv_remain(&now, &t->expire);
3288 }
3289
3290 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01003291 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003292 s->health--; /* still good */
3293 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003294 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003295 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003296 Warning("server %s DOWN.\n", s->id);
3297
willy tarreau9fe663a2005-12-17 13:02:59 +01003298 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003299 }
willy tarreauef900ab2005-12-17 12:52:52 +01003300
willy tarreau5cbea6f2005-12-17 12:48:26 +01003301 s->health = 0; /* failure */
3302 s->state &= ~SRV_RUNNING;
3303 }
3304
3305 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01003306 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
3307 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003308 }
3309 else {
3310 //fprintf(stderr, "process_chk: 8\n");
3311 /* there was a test running */
3312 if (s->result > 0) { /* good server detected */
3313 //fprintf(stderr, "process_chk: 9\n");
3314 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01003315 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003316 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003317 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003318 Warning("server %s UP.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003319 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003320 }
willy tarreauef900ab2005-12-17 12:52:52 +01003321
willy tarreaue47c8d72005-12-17 12:55:52 +01003322 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003323 s->state |= SRV_RUNNING;
3324 }
willy tarreauef900ab2005-12-17 12:52:52 +01003325 s->curfd = -1; /* no check running anymore */
3326 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003327 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003328 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003329 }
3330 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
3331 //fprintf(stderr, "process_chk: 10\n");
3332 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01003333 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003334 s->health--; /* still good */
3335 else {
willy tarreau535ae7a2005-12-17 12:58:00 +01003336 if (s->health == s->rise) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003337 if (!(global.mode & MODE_QUIET))
willy tarreau535ae7a2005-12-17 12:58:00 +01003338 Warning("server %s DOWN.\n", s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003339
3340 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003341 }
willy tarreauef900ab2005-12-17 12:52:52 +01003342
willy tarreau5cbea6f2005-12-17 12:48:26 +01003343 s->health = 0; /* failure */
3344 s->state &= ~SRV_RUNNING;
3345 }
3346 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01003347 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003348 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01003349 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003350 }
3351 /* if result is 0 and there's no timeout, we have to wait again */
3352 }
3353 //fprintf(stderr, "process_chk: 11\n");
3354 s->result = 0;
3355 task_queue(t); /* restore t to its place in the task list */
3356 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01003357}
3358
3359
willy tarreau5cbea6f2005-12-17 12:48:26 +01003360
willy tarreau0f7af912005-12-17 12:21:26 +01003361#if STATTIME > 0
3362int stats(void);
3363#endif
3364
3365/*
3366 * Main select() loop.
3367 */
3368
3369void select_loop() {
3370 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01003371 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01003372 int status;
3373 int fd,i;
3374 struct timeval delta;
3375 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003376 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01003377
willy tarreau5cbea6f2005-12-17 12:48:26 +01003378 tv_now(&now);
3379
3380 while (1) {
3381 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01003382
willy tarreau5cbea6f2005-12-17 12:48:26 +01003383 /* look for expired tasks and add them to the run queue.
3384 */
3385 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3386 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3387 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01003388 if (t->state & TASK_RUNNING)
3389 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003390
3391 /* wakeup expired entries. It doesn't matter if they are
3392 * already running because of a previous event
3393 */
3394 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01003395 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003396 task_wakeup(&rq, t);
3397 }
3398 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003399 /* first non-runnable task. Use its expiration date as an upper bound */
3400 int temp_time = tv_remain(&now, &t->expire);
3401 if (temp_time)
3402 next_time = temp_time;
3403 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003404 break;
3405 }
3406 }
3407
3408 /* process each task in the run queue now. Each task may be deleted
3409 * since we only use tnext.
3410 */
3411 tnext = rq;
3412 while ((t = tnext) != NULL) {
3413 int temp_time;
3414
3415 tnext = t->rqnext;
3416 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01003417 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003418 temp_time = t->process(t);
3419 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01003420 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003421 }
3422
willy tarreauef900ab2005-12-17 12:52:52 +01003423 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01003424
3425 /* maintain all proxies in a consistent state. This should quickly become a task */
3426 time2 = maintain_proxies();
3427 next_time = MINTIME(time2, next_time);
3428
3429 /* stop when there's no connection left and we don't allow them anymore */
3430 if (!actconn && listeners == 0)
3431 break;
3432
willy tarreau0f7af912005-12-17 12:21:26 +01003433
3434#if STATTIME > 0
3435 time2 = stats();
3436 // fprintf(stderr," stats = %d\n", time2);
3437 next_time = MINTIME(time2, next_time);
3438#endif
3439
willy tarreau5cbea6f2005-12-17 12:48:26 +01003440 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01003441 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003442 /* to avoid eventual select loops due to timer precision */
3443 next_time += SCHEDULER_RESOLUTION;
3444 delta.tv_sec = next_time / 1000;
3445 delta.tv_usec = (next_time % 1000) * 1000;
3446 }
3447 else if (next_time == 0) { /* allow select to return immediately when needed */
3448 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003449 }
3450
3451
3452 /* let's restore fdset state */
3453
3454 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003455 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003456 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
3457 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
3458 }
3459
3460// /* just a verification code, needs to be removed for performance */
3461// for (i=0; i<maxfd; i++) {
3462// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
3463// abort();
3464// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
3465// abort();
3466//
3467// }
3468
3469 status=select(maxfd,
3470 readnotnull ? ReadEvent : NULL,
3471 writenotnull ? WriteEvent : NULL,
3472 NULL,
3473 (next_time >= 0) ? &delta : NULL);
3474
willy tarreau5cbea6f2005-12-17 12:48:26 +01003475 /* this is an experiment on the separation of the select work */
3476 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3477 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
3478
willy tarreau0f7af912005-12-17 12:21:26 +01003479 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003480
willy tarreau0f7af912005-12-17 12:21:26 +01003481 if (status > 0) { /* must proceed with events */
3482
3483 int fds;
3484 char count;
3485
3486 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
3487 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
3488 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
3489
willy tarreau5cbea6f2005-12-17 12:48:26 +01003490 /* if we specify read first, the accepts and zero reads will be
3491 * seen first. Moreover, system buffers will be flushed faster.
3492 */
willy tarreau0f7af912005-12-17 12:21:26 +01003493 if (fdtab[fd].state == FD_STCLOSE)
3494 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01003495
3496 if (FD_ISSET(fd, ReadEvent))
3497 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003498
willy tarreau5cbea6f2005-12-17 12:48:26 +01003499 if (FD_ISSET(fd, WriteEvent))
3500 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003501 }
3502 }
3503 else {
3504 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
3505 }
willy tarreau0f7af912005-12-17 12:21:26 +01003506 }
3507}
3508
3509
3510#if STATTIME > 0
3511/*
3512 * Display proxy statistics regularly. It is designed to be called from the
3513 * select_loop().
3514 */
3515int stats(void) {
3516 static int lines;
3517 static struct timeval nextevt;
3518 static struct timeval lastevt;
3519 static struct timeval starttime = {0,0};
3520 unsigned long totaltime, deltatime;
3521 int ret;
3522
willy tarreau750a4722005-12-17 13:21:24 +01003523 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01003524 deltatime = (tv_diff(&lastevt, &now)?:1);
3525 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01003526
willy tarreau9fe663a2005-12-17 13:02:59 +01003527 if (global.mode & MODE_STATS) {
3528 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003529 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003530 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
3531 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003532 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003533 actconn, totalconn,
3534 stats_tsk_new, stats_tsk_good,
3535 stats_tsk_left, stats_tsk_right,
3536 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
3537 }
3538 }
3539
3540 tv_delayfrom(&nextevt, &now, STATTIME);
3541
3542 lastevt=now;
3543 }
3544 ret = tv_remain(&now, &nextevt);
3545 return ret;
3546}
3547#endif
3548
3549
3550/*
3551 * this function enables proxies when there are enough free sessions,
3552 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01003553 * select_loop(). It returns the time left before next expiration event
3554 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01003555 */
3556static int maintain_proxies(void) {
3557 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003558 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01003559
3560 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003561 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003562
3563 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01003564 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01003565 while (p) {
3566 if (p->nbconn < p->maxconn) {
3567 if (p->state == PR_STIDLE) {
3568 FD_SET(p->listen_fd, StaticReadEvent);
3569 p->state = PR_STRUN;
3570 }
3571 }
3572 else {
3573 if (p->state == PR_STRUN) {
3574 FD_CLR(p->listen_fd, StaticReadEvent);
3575 p->state = PR_STIDLE;
3576 }
3577 }
3578 p = p->next;
3579 }
3580 }
3581 else { /* block all proxies */
3582 while (p) {
3583 if (p->state == PR_STRUN) {
3584 FD_CLR(p->listen_fd, StaticReadEvent);
3585 p->state = PR_STIDLE;
3586 }
3587 p = p->next;
3588 }
3589 }
3590
willy tarreau5cbea6f2005-12-17 12:48:26 +01003591 if (stopping) {
3592 p = proxy;
3593 while (p) {
3594 if (p->state != PR_STDISABLED) {
3595 int t;
3596 t = tv_remain(&now, &p->stop_time);
3597 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003598 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01003599 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01003600
willy tarreau5cbea6f2005-12-17 12:48:26 +01003601 fd_delete(p->listen_fd);
3602 p->state = PR_STDISABLED;
3603 listeners--;
3604 }
3605 else {
3606 tleft = MINTIME(t, tleft);
3607 }
3608 }
3609 p = p->next;
3610 }
3611 }
3612 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003613}
3614
3615/*
3616 * this function disables health-check servers so that the process will quickly be ignored
3617 * by load balancers.
3618 */
3619static void soft_stop(void) {
3620 struct proxy *p;
3621
3622 stopping = 1;
3623 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003624 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003625 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01003626 if (p->state != PR_STDISABLED) {
3627 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01003628 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01003629 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01003630 }
willy tarreau0f7af912005-12-17 12:21:26 +01003631 p = p->next;
3632 }
3633}
3634
3635/*
3636 * upon SIGUSR1, let's have a soft stop.
3637 */
3638void sig_soft_stop(int sig) {
3639 soft_stop();
3640 signal(sig, SIG_IGN);
3641}
3642
3643
3644void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003645 struct task *t, *tnext;
3646 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003647
willy tarreau5cbea6f2005-12-17 12:48:26 +01003648 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3649 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3650 tnext = t->next;
3651 s = t->context;
3652 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3653 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3654 "req=%d, rep=%d, clifd=%d\n",
3655 s, tv_remain(&now, &t->expire),
3656 s->cli_state,
3657 s->srv_state,
3658 FD_ISSET(s->cli_fd, StaticReadEvent),
3659 FD_ISSET(s->cli_fd, StaticWriteEvent),
3660 FD_ISSET(s->srv_fd, StaticReadEvent),
3661 FD_ISSET(s->srv_fd, StaticWriteEvent),
3662 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3663 );
willy tarreau0f7af912005-12-17 12:21:26 +01003664 }
3665}
3666
willy tarreaue39cd132005-12-17 13:00:18 +01003667void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
3668 struct hdr_exp *exp;
3669
3670 while (*head != NULL)
3671 head = &(*head)->next;
3672
3673 exp = calloc(1, sizeof(struct hdr_exp));
3674
3675 exp->preg = preg;
3676 exp->replace = replace;
3677 exp->action = action;
3678 *head = exp;
3679}
3680
willy tarreau9fe663a2005-12-17 13:02:59 +01003681
willy tarreau0f7af912005-12-17 12:21:26 +01003682/*
willy tarreau9fe663a2005-12-17 13:02:59 +01003683 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01003684 */
willy tarreau9fe663a2005-12-17 13:02:59 +01003685int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01003686
willy tarreau9fe663a2005-12-17 13:02:59 +01003687 if (!strcmp(args[0], "global")) { /* new section */
3688 /* no option, nothing special to do */
3689 return 0;
3690 }
3691 else if (!strcmp(args[0], "daemon")) {
3692 global.mode |= MODE_DAEMON;
3693 }
3694 else if (!strcmp(args[0], "debug")) {
3695 global.mode |= MODE_DEBUG;
3696 }
3697 else if (!strcmp(args[0], "quiet")) {
3698 global.mode |= MODE_QUIET;
3699 }
3700 else if (!strcmp(args[0], "stats")) {
3701 global.mode |= MODE_STATS;
3702 }
3703 else if (!strcmp(args[0], "uid")) {
3704 if (global.uid != 0) {
3705 Alert("parsing [%s:%d] : <uid> already specified. Continuing.\n", file, linenum);
3706 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003707 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003708 if (*(args[1]) == 0) {
3709 Alert("parsing [%s:%d] : <uid> expects an integer argument.\n", file, linenum);
3710 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003711 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003712 global.uid = atol(args[1]);
3713 }
3714 else if (!strcmp(args[0], "gid")) {
3715 if (global.gid != 0) {
3716 Alert("parsing [%s:%d] : <gid> already specified. Continuing.\n", file, linenum);
3717 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003718 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003719 if (*(args[1]) == 0) {
3720 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003721 return -1;
3722 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003723 global.gid = atol(args[1]);
3724 }
3725 else if (!strcmp(args[0], "nbproc")) {
3726 if (global.nbproc != 0) {
3727 Alert("parsing [%s:%d] : <nbproc> already specified. Continuing.\n", file, linenum);
3728 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003729 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003730 if (*(args[1]) == 0) {
3731 Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
3732 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003733 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003734 global.nbproc = atol(args[1]);
3735 }
3736 else if (!strcmp(args[0], "maxconn")) {
3737 if (global.maxconn != 0) {
3738 Alert("parsing [%s:%d] : <maxconn> already specified. Continuing.\n", file, linenum);
3739 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003740 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003741 if (*(args[1]) == 0) {
3742 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3743 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003744 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003745 global.maxconn = atol(args[1]);
3746 }
3747 else if (!strcmp(args[0], "chroot")) {
3748 if (global.chroot != NULL) {
3749 Alert("parsing [%s:%d] : <chroot> already specified. Continuing.\n", file, linenum);
3750 return 0;
3751 }
3752 if (*(args[1]) == 0) {
3753 Alert("parsing [%s:%d] : <chroot> expects a directory as an argument.\n", file, linenum);
3754 return -1;
3755 }
3756 global.chroot = strdup(args[1]);
3757 }
3758 else if (!strcmp(args[0], "log")) { /* syslog server address */
3759 struct sockaddr_in *sa;
3760 int facility;
3761
3762 if (*(args[1]) == 0 || *(args[2]) == 0) {
3763 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n", file, linenum);
3764 return -1;
3765 }
3766
3767 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3768 if (!strcmp(log_facilities[facility], args[2]))
3769 break;
3770
3771 if (facility >= NB_LOG_FACILITIES) {
3772 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3773 exit(1);
3774 }
3775
3776 sa = str2sa(args[1]);
3777 if (!sa->sin_port)
3778 sa->sin_port = htons(SYSLOG_PORT);
3779
3780 if (global.logfac1 == -1) {
3781 global.logsrv1 = *sa;
3782 global.logfac1 = facility;
3783 }
3784 else if (global.logfac2 == -1) {
3785 global.logsrv2 = *sa;
3786 global.logfac2 = facility;
3787 }
3788 else {
3789 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3790 return -1;
3791 }
3792
3793 }
3794 else {
3795 Alert("parsing [%s:%d] : unknown keyword <%s> in <global> section\n", file, linenum, args[0]);
3796 return -1;
3797 }
3798 return 0;
3799}
3800
3801
3802/*
3803 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
3804 */
3805int cfg_parse_listen(char *file, int linenum, char **args) {
3806 static struct proxy *curproxy = NULL;
3807 struct server *newsrv = NULL;
3808
3809 if (!strcmp(args[0], "listen")) { /* new proxy */
3810 if (strchr(args[2], ':') == NULL) {
3811 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3812 file, linenum);
3813 return -1;
3814 }
3815
3816 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
3817 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3818 return -1;
3819 }
3820 curproxy->next = proxy;
3821 proxy = curproxy;
3822 curproxy->id = strdup(args[1]);
3823 curproxy->listen_addr = *str2sa(args[2]);
3824 curproxy->state = PR_STNEW;
3825 /* set default values */
3826 curproxy->maxconn = cfg_maxpconn;
3827 curproxy->conn_retries = CONN_RETRIES;
3828 curproxy->options = 0;
3829 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3830 curproxy->mode = PR_MODE_TCP;
3831 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3832 curproxy->to_log = 0;
3833 return 0;
3834 }
3835 else if (curproxy == NULL) {
3836 Alert("parsing [%s:%d] : <listen> expected.\n", file, linenum);
3837 return -1;
3838 }
3839
3840 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3841 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3842 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3843 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3844 else {
3845 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3846 return -1;
3847 }
3848 }
3849 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3850 curproxy->state = PR_STDISABLED;
3851 }
3852 else if (!strcmp(args[0], "cookie")) { /* cookie name */
3853 int cur_arg;
3854 if (curproxy->cookie_name != NULL) {
3855 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3856 file, linenum);
3857 return 0;
3858 }
3859
3860 if (*(args[1]) == 0) {
3861 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3862 file, linenum);
3863 return -1;
3864 }
3865 curproxy->cookie_name = strdup(args[1]);
3866
3867 cur_arg = 2;
3868 while (*(args[cur_arg])) {
3869 if (!strcmp(args[cur_arg], "rewrite")) {
3870 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01003871 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003872 else if (!strcmp(args[cur_arg], "indirect")) {
3873 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01003874 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003875 else if (!strcmp(args[cur_arg], "insert")) {
3876 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01003877 }
willy tarreau240afa62005-12-17 13:14:35 +01003878 else if (!strcmp(args[cur_arg], "nocache")) {
3879 curproxy->options |= PR_O_COOK_NOC;
3880 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003881 else {
3882 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003883 file, linenum);
3884 return -1;
3885 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003886 cur_arg++;
3887 }
3888 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3889 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3890 file, linenum);
3891 return -1;
3892 }
3893 }
3894 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3895 if (curproxy->contimeout != 0) {
3896 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n", file, linenum);
3897 return 0;
3898 }
3899 if (*(args[1]) == 0) {
3900 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3901 file, linenum);
3902 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003903 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003904 curproxy->contimeout = atol(args[1]);
3905 }
3906 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3907 if (curproxy->clitimeout != 0) {
3908 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3909 file, linenum);
3910 return 0;
3911 }
3912 if (*(args[1]) == 0) {
3913 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3914 file, linenum);
3915 return -1;
3916 }
3917 curproxy->clitimeout = atol(args[1]);
3918 }
3919 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3920 if (curproxy->srvtimeout != 0) {
3921 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n", file, linenum);
3922 return 0;
3923 }
3924 if (*(args[1]) == 0) {
3925 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003926 file, linenum);
3927 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003928 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003929 curproxy->srvtimeout = atol(args[1]);
3930 }
3931 else if (!strcmp(args[0], "retries")) { /* connection retries */
3932 if (*(args[1]) == 0) {
3933 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3934 file, linenum);
3935 return -1;
3936 }
3937 curproxy->conn_retries = atol(args[1]);
3938 }
3939 else if (!strcmp(args[0], "option")) {
3940 if (*(args[1]) == 0) {
3941 Alert("parsing [%s:%d] : <option> expects an option name.\n", file, linenum);
3942 return -1;
3943 }
3944 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003945 /* enable reconnections to dispatch */
3946 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01003947#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003948 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01003949 /* enable transparent proxy connections */
3950 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01003951#endif
3952 else if (!strcmp(args[1], "keepalive"))
3953 /* enable keep-alive */
3954 curproxy->options |= PR_O_KEEPALIVE;
3955 else if (!strcmp(args[1], "forwardfor"))
3956 /* insert x-forwarded-for field */
3957 curproxy->options |= PR_O_FWDFOR;
3958 else if (!strcmp(args[1], "httplog")) {
3959 /* generate a complete HTTP log */
willy tarreaua1598082005-12-17 13:08:06 +01003960 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP;
3961 }
3962 else if (!strcmp(args[1], "dontlognull")) {
3963 /* don't log empty requests */
3964 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003965 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003966 else {
3967 Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
3968 return -1;
3969 }
3970 return 0;
3971 }
3972 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3973 /* enable reconnections to dispatch */
3974 curproxy->options |= PR_O_REDISP;
3975 }
willy tarreaua1598082005-12-17 13:08:06 +01003976#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01003977 else if (!strcmp(args[0], "transparent")) {
3978 /* enable transparent proxy connections */
3979 curproxy->options |= PR_O_TRANSP;
3980 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003981#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01003982 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3983 if (*(args[1]) == 0) {
3984 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
3985 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003986 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003987 curproxy->maxconn = atol(args[1]);
3988 }
3989 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3990 if (*(args[1]) == 0) {
3991 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n", file, linenum);
3992 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003993 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003994 curproxy->grace = atol(args[1]);
3995 }
3996 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3997 if (strchr(args[1], ':') == NULL) {
3998 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n", file, linenum);
3999 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004000 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004001 curproxy->dispatch_addr = *str2sa(args[1]);
4002 }
4003 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
4004 if (*(args[1])) {
4005 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004006 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01004007 }
4008 else {
4009 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n", file, linenum);
4010 return -1;
4011 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004012 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004013 else /* if no option is set, use round-robin by default */
4014 curproxy->options |= PR_O_BALANCE_RR;
4015 }
4016 else if (!strcmp(args[0], "server")) { /* server address */
4017 int cur_arg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004018
willy tarreau9fe663a2005-12-17 13:02:59 +01004019 if (strchr(args[2], ':') == NULL) {
4020 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
4021 file, linenum);
4022 return -1;
4023 }
4024 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
4025 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
4026 return -1;
4027 }
4028 newsrv->next = curproxy->srv;
4029 curproxy->srv = newsrv;
4030 newsrv->proxy = curproxy;
4031 newsrv->id = strdup(args[1]);
4032 newsrv->addr = *str2sa(args[2]);
4033 newsrv->state = SRV_RUNNING; /* early server setup */
4034 newsrv->curfd = -1; /* no health-check in progress */
4035 newsrv->inter = DEF_CHKINTR;
4036 newsrv->rise = DEF_RISETIME;
4037 newsrv->fall = DEF_FALLTIME;
4038 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
4039 cur_arg = 3;
4040 while (*args[cur_arg]) {
4041 if (!strcmp(args[cur_arg], "cookie")) {
4042 newsrv->cookie = strdup(args[cur_arg + 1]);
4043 newsrv->cklen = strlen(args[cur_arg + 1]);
4044 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004045 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004046 else if (!strcmp(args[cur_arg], "rise")) {
4047 newsrv->rise = atol(args[cur_arg + 1]);
4048 newsrv->health = newsrv->rise;
4049 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01004050 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004051 else if (!strcmp(args[cur_arg], "fall")) {
4052 newsrv->fall = atol(args[cur_arg + 1]);
4053 cur_arg += 2;
4054 }
4055 else if (!strcmp(args[cur_arg], "inter")) {
4056 newsrv->inter = atol(args[cur_arg + 1]);
4057 cur_arg += 2;
4058 }
4059 else if (!strcmp(args[cur_arg], "check")) {
4060 struct task *t;
4061
4062 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
4063 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004064 return -1;
4065 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004066
4067 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
4068 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
4069 t->state = TASK_IDLE;
4070 t->process = process_chk;
4071 t->context = newsrv;
4072
4073 if (curproxy->state != PR_STDISABLED) {
4074 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
4075 task_queue(t);
4076 task_wakeup(&rq, t);
4077 }
4078
4079 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004080 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004081 else {
4082 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
4083 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01004084 return -1;
4085 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004086 }
4087 curproxy->nbservers++;
4088 }
4089 else if (!strcmp(args[0], "log")) { /* syslog server address */
4090 struct sockaddr_in *sa;
4091 int facility;
4092
4093 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
4094 curproxy->logfac1 = global.logfac1;
4095 curproxy->logsrv1 = global.logsrv1;
4096 curproxy->logfac2 = global.logfac2;
4097 curproxy->logsrv2 = global.logsrv2;
4098 }
4099 else if (*(args[1]) && *(args[2])) {
willy tarreau0f7af912005-12-17 12:21:26 +01004100 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
4101 if (!strcmp(log_facilities[facility], args[2]))
4102 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01004103
willy tarreau0f7af912005-12-17 12:21:26 +01004104 if (facility >= NB_LOG_FACILITIES) {
4105 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
4106 exit(1);
4107 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004108
willy tarreau0f7af912005-12-17 12:21:26 +01004109 sa = str2sa(args[1]);
4110 if (!sa->sin_port)
4111 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01004112
willy tarreau0f7af912005-12-17 12:21:26 +01004113 if (curproxy->logfac1 == -1) {
4114 curproxy->logsrv1 = *sa;
4115 curproxy->logfac1 = facility;
4116 }
4117 else if (curproxy->logfac2 == -1) {
4118 curproxy->logsrv2 = *sa;
4119 curproxy->logfac2 = facility;
4120 }
4121 else {
4122 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01004123 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004124 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004125 }
4126 else {
4127 Alert("parsing [%s:%d] : <log> expects either <address[:port]> and <facility> or 'global' as arguments.\n",
4128 file, linenum);
4129 return -1;
4130 }
4131 }
willy tarreaua1598082005-12-17 13:08:06 +01004132 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
4133 if (strchr(args[1], ':') == NULL) {
4134 Alert("parsing [%s:%d] : <source> expects <addr:port> as argument.\n",
4135 file, linenum);
4136 return -1;
4137 }
4138
4139 curproxy->source_addr = *str2sa(args[1]);
4140 curproxy->options |= PR_O_BIND_SRC;
4141 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004142 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
4143 regex_t *preg;
4144
4145 if (*(args[1]) == 0 || *(args[2]) == 0) {
4146 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
4147 file, linenum);
4148 return -1;
4149 }
4150
4151 preg = calloc(1, sizeof(regex_t));
4152 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4153 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4154 return -1;
4155 }
4156
4157 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4158 }
4159 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
4160 regex_t *preg;
4161
4162 if (*(args[1]) == 0) {
4163 Alert("parsing [%s:%d] : <reqdel> expects <regex> as an argument.\n", file, linenum);
4164 return -1;
4165 }
4166
4167 preg = calloc(1, sizeof(regex_t));
4168 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4169 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4170 return -1;
4171 }
4172
4173 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4174 }
4175 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
4176 regex_t *preg;
4177
4178 if (*(args[1]) == 0) {
4179 Alert("parsing [%s:%d] : <reqdeny> expects <regex> as an argument.\n", file, linenum);
4180 return -1;
4181 }
4182
4183 preg = calloc(1, sizeof(regex_t));
4184 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4185 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4186 return -1;
4187 }
4188
4189 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4190 }
4191 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
4192 regex_t *preg;
4193
4194 if (*(args[1]) == 0) {
4195 Alert("parsing [%s:%d] : <reqallow> expects <regex> as an argument.\n", file, linenum);
4196 return -1;
4197 }
4198
4199 preg = calloc(1, sizeof(regex_t));
4200 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4201 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4202 return -1;
4203 }
4204
4205 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4206 }
4207 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
4208 regex_t *preg;
4209
4210 if (*(args[1]) == 0 || *(args[2]) == 0) {
4211 Alert("parsing [%s:%d] : <reqirep> expects <search> and <replace> as arguments.\n",
4212 file, linenum);
4213 return -1;
4214 }
4215
4216 preg = calloc(1, sizeof(regex_t));
4217 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4218 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4219 return -1;
4220 }
4221
4222 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
4223 }
4224 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
4225 regex_t *preg;
4226
4227 if (*(args[1]) == 0) {
4228 Alert("parsing [%s:%d] : <reqidel> expects <regex> as an argument.\n", file, linenum);
4229 return -1;
4230 }
4231
4232 preg = calloc(1, sizeof(regex_t));
4233 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4234 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4235 return -1;
4236 }
4237
4238 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
4239 }
4240 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
4241 regex_t *preg;
4242
4243 if (*(args[1]) == 0) {
4244 Alert("parsing [%s:%d] : <reqideny> expects <regex> as an argument.\n", file, linenum);
4245 return -1;
4246 }
4247
4248 preg = calloc(1, sizeof(regex_t));
4249 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4250 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4251 return -1;
4252 }
4253
4254 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
4255 }
4256 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
4257 regex_t *preg;
4258
4259 if (*(args[1]) == 0) {
4260 Alert("parsing [%s:%d] : <reqiallow> expects <regex> as an argument.\n", file, linenum);
4261 return -1;
4262 }
4263
4264 preg = calloc(1, sizeof(regex_t));
4265 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4266 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4267 return -1;
4268 }
4269
4270 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
4271 }
4272 else if (!strcmp(args[0], "reqadd")) { /* add request header */
4273 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
4274 Alert("parsing [%s:%d] : too many `reqadd'. Continuing.\n", file, linenum);
4275 return 0;
4276 }
4277
4278 if (*(args[1]) == 0) {
4279 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n", file, linenum);
4280 return -1;
4281 }
4282
4283 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01004284 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004285 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01004286 regex_t *preg;
willy tarreau0f7af912005-12-17 12:21:26 +01004287
4288 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004289 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004290 file, linenum);
4291 return -1;
4292 }
4293
4294 preg = calloc(1, sizeof(regex_t));
4295 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4296 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4297 return -1;
4298 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004299
4300 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4301 }
4302 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
4303 regex_t *preg;
4304
4305 if (*(args[1]) == 0) {
4306 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n", file, linenum);
4307 return -1;
4308 }
willy tarreaue39cd132005-12-17 13:00:18 +01004309
willy tarreau9fe663a2005-12-17 13:02:59 +01004310 preg = calloc(1, sizeof(regex_t));
4311 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
4312 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4313 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004314 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004315
4316 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4317 }
4318 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreau0f7af912005-12-17 12:21:26 +01004319 regex_t *preg;
willy tarreaue39cd132005-12-17 13:00:18 +01004320
willy tarreau9fe663a2005-12-17 13:02:59 +01004321 if (*(args[1]) == 0 || *(args[2]) == 0) {
4322 Alert("parsing [%s:%d] : <rspirep> expects <search> and <replace> as arguments.\n",
willy tarreau5cbea6f2005-12-17 12:48:26 +01004323 file, linenum);
willy tarreaue39cd132005-12-17 13:00:18 +01004324 return -1;
4325 }
4326
4327 preg = calloc(1, sizeof(regex_t));
willy tarreau9fe663a2005-12-17 13:02:59 +01004328 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreaue39cd132005-12-17 13:00:18 +01004329 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4330 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004331 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004332
4333 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
4334 }
4335 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
4336 regex_t *preg;
4337
4338 if (*(args[1]) == 0) {
4339 Alert("parsing [%s:%d] : <rspidel> expects <search> as an argument.\n", file, linenum);
4340 return -1;
4341 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004342
willy tarreau9fe663a2005-12-17 13:02:59 +01004343 preg = calloc(1, sizeof(regex_t));
4344 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
4345 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
4346 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004347 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004348
4349 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
4350 }
4351 else if (!strcmp(args[0], "rspadd")) { /* add response header */
4352 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
4353 Alert("parsing [%s:%d] : too many `rspadd'. Continuing.\n", file, linenum);
4354 return 0;
4355 }
4356
4357 if (*(args[1]) == 0) {
4358 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n", file, linenum);
4359 return -1;
4360 }
4361
4362 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
4363 }
4364 else {
4365 Alert("parsing [%s:%d] : unknown keyword <%s> in <listen> section\n", file, linenum, args[0]);
4366 return -1;
4367 }
4368 return 0;
4369}
willy tarreaue39cd132005-12-17 13:00:18 +01004370
willy tarreau5cbea6f2005-12-17 12:48:26 +01004371
willy tarreau9fe663a2005-12-17 13:02:59 +01004372/*
4373 * This function reads and parses the configuration file given in the argument.
4374 * returns 0 if OK, -1 if error.
4375 */
4376int readcfgfile(char *file) {
4377 char thisline[256];
4378 char *line;
4379 FILE *f;
4380 int linenum = 0;
4381 char *end;
4382 char *args[MAX_LINE_ARGS];
4383 int arg;
4384 int cfgerr = 0;
4385 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01004386
willy tarreau9fe663a2005-12-17 13:02:59 +01004387 struct proxy *curproxy = NULL;
4388 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01004389
willy tarreau9fe663a2005-12-17 13:02:59 +01004390 if ((f=fopen(file,"r")) == NULL)
4391 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01004392
willy tarreau9fe663a2005-12-17 13:02:59 +01004393 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
4394 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004395
willy tarreau9fe663a2005-12-17 13:02:59 +01004396 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004397
willy tarreau9fe663a2005-12-17 13:02:59 +01004398 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01004399 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01004400 line++;
4401
4402 arg = 0;
4403 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01004404
willy tarreau9fe663a2005-12-17 13:02:59 +01004405 while (*line && arg < MAX_LINE_ARGS) {
4406 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
4407 * C equivalent value. Other combinations left unchanged (eg: \1).
4408 */
4409 if (*line == '\\') {
4410 int skip = 0;
4411 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
4412 *line = line[1];
4413 skip = 1;
4414 }
4415 else if (line[1] == 'r') {
4416 *line = '\r';
4417 skip = 1;
4418 }
4419 else if (line[1] == 'n') {
4420 *line = '\n';
4421 skip = 1;
4422 }
4423 else if (line[1] == 't') {
4424 *line = '\t';
4425 skip = 1;
4426 }
4427 else if (line[1] == 'x' && (line + 3 < end )) {
4428 unsigned char hex1, hex2;
4429 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
4430 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
4431 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
4432 *line = (hex1<<4) + hex2;
4433 skip = 3;
4434 }
4435 if (skip) {
4436 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
4437 end -= skip;
4438 }
4439 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004440 }
willy tarreaua1598082005-12-17 13:08:06 +01004441 else if (*line == '#' || *line == '\n' || *line == '\r') {
4442 /* end of string, end of loop */
4443 *line = 0;
4444 break;
4445 }
willy tarreauc29948c2005-12-17 13:10:27 +01004446 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004447 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01004448 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01004449 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01004450 line++;
4451 args[++arg] = line;
4452 }
4453 else {
4454 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01004455 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004456 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004457
willy tarreau9fe663a2005-12-17 13:02:59 +01004458 /* empty line */
4459 if (!**args)
4460 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01004461
willy tarreau9fe663a2005-12-17 13:02:59 +01004462 /* zero out remaining args */
4463 while (++arg < MAX_LINE_ARGS) {
4464 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004465 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004466
willy tarreau9fe663a2005-12-17 13:02:59 +01004467 if (!strcmp(args[0], "listen")) /* new proxy */
4468 confsect = CFG_LISTEN;
4469 else if (!strcmp(args[0], "global")) /* global config */
4470 confsect = CFG_GLOBAL;
4471 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004472
willy tarreau9fe663a2005-12-17 13:02:59 +01004473 switch (confsect) {
4474 case CFG_LISTEN:
4475 if (cfg_parse_listen(file, linenum, args) < 0)
4476 return -1;
4477 break;
4478 case CFG_GLOBAL:
4479 if (cfg_parse_global(file, linenum, args) < 0)
4480 return -1;
4481 break;
4482 default:
4483 Alert("parsing [%s:%d] : unknown keyword <%s> out of section.\n", file, linenum, args[0]);
4484 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01004485 }
willy tarreau9fe663a2005-12-17 13:02:59 +01004486
4487
willy tarreau0f7af912005-12-17 12:21:26 +01004488 }
4489 fclose(f);
4490
4491 /*
4492 * Now, check for the integrity of all that we have collected.
4493 */
4494
4495 if ((curproxy = proxy) == NULL) {
4496 Alert("parsing %s : no <listen> line. Nothing to do !\n",
4497 file);
4498 return -1;
4499 }
4500
4501 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01004502 if (curproxy->state == PR_STDISABLED) {
4503 curproxy = curproxy->next;
4504 continue;
4505 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004506 if ((curproxy->mode != PR_MODE_HEALTH) &&
4507 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01004508 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004509 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
4510 file, curproxy->id);
4511 cfgerr++;
4512 }
4513 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
4514 if (curproxy->options & PR_O_TRANSP) {
4515 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
4516 file, curproxy->id);
4517 cfgerr++;
4518 }
4519 else if (curproxy->srv == NULL) {
4520 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
4521 file, curproxy->id);
4522 cfgerr++;
4523 }
willy tarreaua1598082005-12-17 13:08:06 +01004524 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004525 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
4526 file, curproxy->id);
4527 }
4528 }
4529 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01004530 if (curproxy->cookie_name != NULL) {
4531 Warning("parsing %s : cookie will be ignored for listener %s.\n",
4532 file, curproxy->id);
4533 }
4534 if ((newsrv = curproxy->srv) != NULL) {
4535 Warning("parsing %s : servers will be ignored for listener %s.\n",
4536 file, curproxy->id);
4537 }
willy tarreaue39cd132005-12-17 13:00:18 +01004538 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004539 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
4540 file, curproxy->id);
4541 }
willy tarreaue39cd132005-12-17 13:00:18 +01004542 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01004543 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
4544 file, curproxy->id);
4545 }
4546 }
4547 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
4548 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
4549 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
4550 file, curproxy->id);
4551 cfgerr++;
4552 }
4553 else {
4554 while (newsrv != NULL) {
4555 /* nothing to check for now */
4556 newsrv = newsrv->next;
4557 }
4558 }
4559 }
4560 curproxy = curproxy->next;
4561 }
4562 if (cfgerr > 0) {
4563 Alert("Errors found in configuration file, aborting.\n");
4564 return -1;
4565 }
4566 else
4567 return 0;
4568}
4569
4570
4571/*
4572 * This function initializes all the necessary variables. It only returns
4573 * if everything is OK. If something fails, it exits.
4574 */
4575void init(int argc, char **argv) {
4576 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01004577 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01004578 char *old_argv = *argv;
4579 char *tmp;
willy tarreau9fe663a2005-12-17 13:02:59 +01004580 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01004581
4582 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004583 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004584 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
4585 sizeof(int)*8);
4586 exit(1);
4587 }
4588
4589 pid = getpid();
4590 progname = *argv;
4591 while ((tmp = strchr(progname, '/')) != NULL)
4592 progname = tmp + 1;
4593
4594 argc--; argv++;
4595 while (argc > 0) {
4596 char *flag;
4597
4598 if (**argv == '-') {
4599 flag = *argv+1;
4600
4601 /* 1 arg */
4602 if (*flag == 'v') {
4603 display_version();
4604 exit(0);
4605 }
4606 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01004607 arg_mode |= MODE_DEBUG;
willy tarreau0f7af912005-12-17 12:21:26 +01004608 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01004609 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004610 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01004611 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01004612#if STATTIME > 0
4613 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01004614 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01004615 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01004616 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01004617#endif
4618 else { /* >=2 args */
4619 argv++; argc--;
4620 if (argc == 0)
4621 usage(old_argv);
4622
4623 switch (*flag) {
4624 case 'n' : cfg_maxconn = atol(*argv); break;
4625 case 'N' : cfg_maxpconn = atol(*argv); break;
4626 case 'f' : cfg_cfgfile = *argv; break;
4627 default: usage(old_argv);
4628 }
4629 }
4630 }
4631 else
4632 usage(old_argv);
4633 argv++; argc--;
4634 }
4635
willy tarreau0f7af912005-12-17 12:21:26 +01004636 if (!cfg_cfgfile)
4637 usage(old_argv);
4638
4639 gethostname(hostname, MAX_HOSTNAME_LEN);
4640
4641 if (readcfgfile(cfg_cfgfile) < 0) {
4642 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
4643 exit(1);
4644 }
4645
willy tarreau9fe663a2005-12-17 13:02:59 +01004646 if (cfg_maxconn > 0)
4647 global.maxconn = cfg_maxconn;
4648
4649 if (global.maxconn == 0)
4650 global.maxconn = DEFAULT_MAXCONN;
4651
4652 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
4653
4654 if (arg_mode & MODE_DEBUG) {
4655 /* command line debug mode inhibits configuration mode */
4656 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4657 }
willy tarreau750a4722005-12-17 13:21:24 +01004658 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01004659
4660 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
4661 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
4662 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
4663 }
4664
4665 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
4666 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
4667 global.nbproc = 1;
4668 }
4669
4670 if (global.nbproc < 1)
4671 global.nbproc = 1;
4672
willy tarreau0f7af912005-12-17 12:21:26 +01004673 ReadEvent = (fd_set *)calloc(1,
4674 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004675 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004676 WriteEvent = (fd_set *)calloc(1,
4677 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004678 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004679 StaticReadEvent = (fd_set *)calloc(1,
4680 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004681 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004682 StaticWriteEvent = (fd_set *)calloc(1,
4683 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01004684 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01004685
4686 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01004687 sizeof(struct fdtab) * (global.maxsock));
4688 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004689 fdtab[i].state = FD_STCLOSE;
4690 }
4691}
4692
4693/*
4694 * this function starts all the proxies. It returns 0 if OK, -1 if not.
4695 */
4696int start_proxies() {
4697 struct proxy *curproxy;
4698 int one = 1;
4699 int fd;
4700
4701 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
4702
4703 if (curproxy->state == PR_STDISABLED)
4704 continue;
4705
4706 if ((fd = curproxy->listen_fd =
4707 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
4708 Alert("cannot create listening socket for proxy %s. Aborting.\n",
4709 curproxy->id);
4710 return -1;
4711 }
4712
willy tarreau9fe663a2005-12-17 13:02:59 +01004713 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004714 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
4715 curproxy->id);
4716 close(fd);
4717 return -1;
4718 }
4719
willy tarreau0f7af912005-12-17 12:21:26 +01004720 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
4721 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
4722 (char *) &one, sizeof(one)) == -1)) {
4723 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
4724 curproxy->id);
4725 close(fd);
4726 return -1;
4727 }
4728
4729 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
4730 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
4731 curproxy->id);
4732 }
4733
4734 if (bind(fd,
4735 (struct sockaddr *)&curproxy->listen_addr,
4736 sizeof(curproxy->listen_addr)) == -1) {
4737 Alert("cannot bind socket for proxy %s. Aborting.\n",
4738 curproxy->id);
4739 close(fd);
4740 return -1;
4741 }
4742
4743 if (listen(fd, curproxy->maxconn) == -1) {
4744 Alert("cannot listen to socket for proxy %s. Aborting.\n",
4745 curproxy->id);
4746 close(fd);
4747 return -1;
4748 }
4749
4750 /* the function for the accept() event */
4751 fdtab[fd].read = &event_accept;
4752 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004753 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01004754 curproxy->state = PR_STRUN;
4755 fdtab[fd].state = FD_STLISTEN;
4756 FD_SET(fd, StaticReadEvent);
4757 fd_insert(fd);
4758 listeners++;
willy tarreau9fe663a2005-12-17 13:02:59 +01004759
willy tarreaua1598082005-12-17 13:08:06 +01004760 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004761
willy tarreau0f7af912005-12-17 12:21:26 +01004762 }
4763 return 0;
4764}
4765
4766
4767int main(int argc, char **argv) {
4768 init(argc, argv);
4769
willy tarreau9fe663a2005-12-17 13:02:59 +01004770 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01004771 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004772 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01004773 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01004774 }
4775
4776 signal(SIGQUIT, dump);
4777 signal(SIGUSR1, sig_soft_stop);
4778
4779 /* on very high loads, a sigpipe sometimes happen just between the
4780 * getsockopt() which tells "it's OK to write", and the following write :-(
4781 */
willy tarreau3242e862005-12-17 12:27:53 +01004782#ifndef MSG_NOSIGNAL
4783 signal(SIGPIPE, SIG_IGN);
4784#endif
willy tarreau0f7af912005-12-17 12:21:26 +01004785
4786 if (start_proxies() < 0)
4787 exit(1);
4788
willy tarreau9fe663a2005-12-17 13:02:59 +01004789 /* open log files */
4790
4791 /* chroot if needed */
4792 if (global.chroot != NULL) {
4793 if (chroot(global.chroot) == -1) {
4794 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
4795 exit(1);
4796 }
4797 chdir("/");
4798 }
4799
4800 /* setgid / setuid */
4801 if (global.gid && setregid(global.gid, global.gid) == -1) {
4802 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
4803 exit(1);
4804 }
4805
4806 if (global.uid && setreuid(global.uid, global.uid) == -1) {
4807 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
4808 exit(1);
4809 }
4810
4811 if (global.mode & MODE_DAEMON) {
4812 int ret = 0;
4813 int proc;
4814
4815 /* the father launches the required number of processes */
4816 for (proc = 0; proc < global.nbproc; proc++) {
4817 ret = fork();
4818 if (ret < 0) {
4819 Alert("[%s.main()] Cannot fork.\n", argv[0]);
4820 exit(1); /* there has been an error */
4821 }
4822 else if (ret == 0) /* child breaks here */
4823 break;
4824 }
4825 if (proc == global.nbproc)
4826 exit(0); /* parent must leave */
4827
willy tarreau750a4722005-12-17 13:21:24 +01004828 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
4829 * that we can detach from the TTY. We MUST NOT do it in other cases since
4830 * it would have already be done, and 0-2 would have been affected to listening
4831 * sockets
4832 */
4833 if (!(global.mode & MODE_QUIET)) {
4834 /* detach from the tty */
4835 fclose(stdin); fclose(stdout); fclose(stderr);
4836 close(0); close(1); close(2); /* close all fd's */
4837 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
4838 }
willy tarreaua1598082005-12-17 13:08:06 +01004839 pid = getpid(); /* update child's pid */
willy tarreau9fe663a2005-12-17 13:02:59 +01004840 setpgid(1, 0);
willy tarreau750a4722005-12-17 13:21:24 +01004841 setpgrp();
willy tarreau9fe663a2005-12-17 13:02:59 +01004842 }
4843
willy tarreau0f7af912005-12-17 12:21:26 +01004844 select_loop();
4845
4846 exit(0);
4847}
willy tarreaua1598082005-12-17 13:08:06 +01004848