blob: 1445d1b3b1cfcde3785200fada5861103eee8bd1 [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
willy tarreau0174f312005-12-18 01:02:42 +01003 * 2000-2005 - 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 tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreau0f7af912005-12-17 12:21:26 +010033 *
34 */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <unistd.h>
39#include <string.h>
40#include <ctype.h>
41#include <sys/time.h>
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <netinet/tcp.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <netdb.h>
48#include <fcntl.h>
49#include <errno.h>
50#include <signal.h>
51#include <stdarg.h>
52#include <sys/resource.h>
53#include <time.h>
54#include <regex.h>
55#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010056#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010057#include <linux/netfilter_ipv4.h>
58#endif
willy tarreau0f7af912005-12-17 12:21:26 +010059
willy tarreau12350152005-12-18 01:03:27 +010060#if defined(__dietlibc__)
61#include <strings.h>
62#endif
63
willy tarreau598da412005-12-18 01:07:29 +010064#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010065
66#define HAPROXY_VERSION "1.2.4"
willy tarreau0174f312005-12-18 01:02:42 +010067#define HAPROXY_DATE "2005/01/22"
willy tarreau0f7af912005-12-17 12:21:26 +010068
69/* this is for libc5 for example */
70#ifndef TCP_NODELAY
71#define TCP_NODELAY 1
72#endif
73
74#ifndef SHUT_RD
75#define SHUT_RD 0
76#endif
77
78#ifndef SHUT_WR
79#define SHUT_WR 1
80#endif
81
willy tarreau0174f312005-12-18 01:02:42 +010082/*
83 * BUFSIZE defines the size of a read and write buffer. It is the maximum
84 * amount of bytes which can be stored by the proxy for each session. However,
85 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
86 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
87 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
88 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
89 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
90 */
91#ifndef BUFSIZE
92#define BUFSIZE 16384
93#endif
willy tarreau0f7af912005-12-17 12:21:26 +010094
95// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +010096#ifndef MAXREWRITE
97#define MAXREWRITE (BUFSIZE / 2)
98#endif
99
willy tarreau9fe663a2005-12-17 13:02:59 +0100100#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100101#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100102
willy tarreau5cbea6f2005-12-17 12:48:26 +0100103// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100104#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100105
willy tarreaue39cd132005-12-17 13:00:18 +0100106// max # of added headers per request
107#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100108
109// max # of matches per regexp
110#define MAX_MATCH 10
111
willy tarreau0174f312005-12-18 01:02:42 +0100112// cookie delimitor in "prefix" mode. This character is inserted between the
113// persistence cookie and the original value. The '~' is allowed by RFC2965,
114// and should not be too common in server names.
115#ifndef COOKIE_DELIM
116#define COOKIE_DELIM '~'
117#endif
118
willy tarreau0f7af912005-12-17 12:21:26 +0100119#define CONN_RETRIES 3
120
willy tarreau5cbea6f2005-12-17 12:48:26 +0100121#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100122#define DEF_CHKINTR 2000
123#define DEF_FALLTIME 3
124#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100125#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100126
willy tarreau9fe663a2005-12-17 13:02:59 +0100127/* default connections limit */
128#define DEFAULT_MAXCONN 2000
129
willy tarreau0f7af912005-12-17 12:21:26 +0100130/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
131#define INTBITS 5
132
133/* show stats this every millisecond, 0 to disable */
134#ifndef STATTIME
135#define STATTIME 2000
136#endif
137
willy tarreau5cbea6f2005-12-17 12:48:26 +0100138/* this reduces the number of calls to select() by choosing appropriate
139 * sheduler precision in milliseconds. It should be near the minimum
140 * time that is needed by select() to collect all events. All timeouts
141 * are rounded up by adding this value prior to pass it to select().
142 */
143#define SCHEDULER_RESOLUTION 9
144
willy tarreau0f7af912005-12-17 12:21:26 +0100145#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
146#define SETNOW(a) (*a=now)
147
willy tarreau9da061b2005-12-17 12:29:56 +0100148/****** string-specific macros and functions ******/
149/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
150#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
151
152/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
153#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
154
willy tarreau0174f312005-12-18 01:02:42 +0100155/* returns 1 only if only zero or one bit is set in X, which means that X is a
156 * power of 2, and 0 otherwise */
157#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100158/*
159 * copies at most <size-1> chars from <src> to <dst>. Last char is always
160 * set to 0, unless <size> is 0. The number of chars copied is returned
161 * (excluding the terminating zero).
162 * This code has been optimized for size and speed : on x86, it's 45 bytes
163 * long, uses only registers, and consumes only 4 cycles per char.
164 */
willy tarreau750a4722005-12-17 13:21:24 +0100165int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100166 char *orig = dst;
167 if (size) {
168 while (--size && (*dst = *src)) {
169 src++; dst++;
170 }
171 *dst = 0;
172 }
173 return dst - orig;
174}
willy tarreau9da061b2005-12-17 12:29:56 +0100175
willy tarreau4302f492005-12-18 01:00:37 +0100176/*
177 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
178 * dynamically allocated. In the first case, <__pool> is updated to point to
179 * the next element in the list.
180 */
181#define pool_alloc_from(__pool, __len) ({ \
182 void *__p; \
183 if ((__p = (__pool)) == NULL) \
184 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
185 else { \
186 __pool = *(void **)(__pool); \
187 } \
188 __p; \
189})
190
191/*
192 * Puts a memory area back to the corresponding pool.
193 * Items are chained directly through a pointer that
194 * is written in the beginning of the memory area, so
195 * there's no need for any carrier cell. This implies
196 * that each memory area is at least as big as one
197 * pointer.
198 */
199#define pool_free_to(__pool, __ptr) ({ \
200 *(void **)(__ptr) = (void *)(__pool); \
201 __pool = (void *)(__ptr); \
202})
203
204
willy tarreau0f7af912005-12-17 12:21:26 +0100205#define MEM_OPTIM
206#ifdef MEM_OPTIM
207/*
208 * Returns a pointer to type <type> taken from the
209 * pool <pool_type> or dynamically allocated. In the
210 * first case, <pool_type> is updated to point to the
211 * next element in the list.
212 */
213#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100214 void *__p; \
215 if ((__p = pool_##type) == NULL) \
216 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100217 else { \
218 pool_##type = *(void **)pool_##type; \
219 } \
willy tarreau4302f492005-12-18 01:00:37 +0100220 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100221})
222
223/*
224 * Puts a memory area back to the corresponding pool.
225 * Items are chained directly through a pointer that
226 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100227 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100228 * that each memory area is at least as big as one
229 * pointer.
230 */
231#define pool_free(type, ptr) ({ \
232 *(void **)ptr = (void *)pool_##type; \
233 pool_##type = (void *)ptr; \
234})
235
236#else
237#define pool_alloc(type) (calloc(1,sizeof_##type));
238#define pool_free(type, ptr) (free(ptr));
239#endif /* MEM_OPTIM */
240
willy tarreau5cbea6f2005-12-17 12:48:26 +0100241#define sizeof_task sizeof(struct task)
242#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100243#define sizeof_buffer sizeof(struct buffer)
244#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau12350152005-12-18 01:03:27 +0100245#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau9fe663a2005-12-17 13:02:59 +0100246#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100247#define sizeof_capture CAPTURE_LEN
willy tarreau12350152005-12-18 01:03:27 +0100248#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100249
willy tarreau5cbea6f2005-12-17 12:48:26 +0100250/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100251#define FD_STCLOSE 0
252#define FD_STLISTEN 1
253#define FD_STCONN 2
254#define FD_STREADY 3
255#define FD_STERROR 4
256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100257/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100258#define TASK_IDLE 0
259#define TASK_RUNNING 1
260
willy tarreau5cbea6f2005-12-17 12:48:26 +0100261/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100262#define PR_STNEW 0
263#define PR_STIDLE 1
264#define PR_STRUN 2
265#define PR_STDISABLED 3
266
willy tarreau5cbea6f2005-12-17 12:48:26 +0100267/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100268#define PR_MODE_TCP 0
269#define PR_MODE_HTTP 1
270#define PR_MODE_HEALTH 2
271
willy tarreau5cbea6f2005-12-17 12:48:26 +0100272/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100273#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
274#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
275#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
276#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
277#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
278#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
279#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
280#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100281#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100282#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
283#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
284#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
285#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
286#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
287#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
288#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
289#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
290#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
291#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
292#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100293
willy tarreaue39cd132005-12-17 13:00:18 +0100294/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100295#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
296#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
297#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
298#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
299#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
300#define SN_POST 0x00000020 /* the request was an HTTP POST */
301
302#define SN_CK_NONE 0x00000000 /* this session had no cookie */
303#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
304#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
305#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
306#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
307#define SN_CK_SHIFT 6 /* bit shift */
308
309#define SN_ERR_CLITO 0x00000100 /* client time-out */
310#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
311#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
312#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
313#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
314#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
315#define SN_ERR_SHIFT 8 /* bit shift */
316
317#define SN_FINST_R 0x00001000 /* session ended during client request */
318#define SN_FINST_C 0x00002000 /* session ended during server connect */
319#define SN_FINST_H 0x00003000 /* session ended during server headers */
320#define SN_FINST_D 0x00004000 /* session ended during data phase */
321#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
322#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
323#define SN_FINST_SHIFT 12 /* bit shift */
324
325#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
326#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
327#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
328#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
329#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100330#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100331#define SN_SCK_SHIFT 16 /* bit shift */
332
willy tarreau97f58572005-12-18 00:53:44 +0100333#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
334#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
335#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100336
337/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100338#define CL_STHEADERS 0
339#define CL_STDATA 1
340#define CL_STSHUTR 2
341#define CL_STSHUTW 3
342#define CL_STCLOSE 4
343
willy tarreau5cbea6f2005-12-17 12:48:26 +0100344/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100345#define SV_STIDLE 0
346#define SV_STCONN 1
347#define SV_STHEADERS 2
348#define SV_STDATA 3
349#define SV_STSHUTR 4
350#define SV_STSHUTW 5
351#define SV_STCLOSE 6
352
353/* result of an I/O event */
354#define RES_SILENT 0 /* didn't happen */
355#define RES_DATA 1 /* data were sent or received */
356#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
357#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
358
willy tarreau9fe663a2005-12-17 13:02:59 +0100359/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100360#define MODE_DEBUG 1
361#define MODE_STATS 2
362#define MODE_LOG 4
363#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100364#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100365#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100366#define MODE_VERBOSE 64
willy tarreau5cbea6f2005-12-17 12:48:26 +0100367
368/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100369#define SRV_RUNNING 1 /* the server is UP */
370#define SRV_BACKUP 2 /* this server is a backup server */
371#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100372#define SRV_BIND_SRC 8 /* this server uses a specific source address */
willy tarreau0f7af912005-12-17 12:21:26 +0100373
willy tarreaue39cd132005-12-17 13:00:18 +0100374/* what to do when a header matches a regex */
375#define ACT_ALLOW 0 /* allow the request */
376#define ACT_REPLACE 1 /* replace the matching header */
377#define ACT_REMOVE 2 /* remove the matching header */
378#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100379#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100380
willy tarreau9fe663a2005-12-17 13:02:59 +0100381/* configuration sections */
382#define CFG_NONE 0
383#define CFG_GLOBAL 1
384#define CFG_LISTEN 2
385
willy tarreaua1598082005-12-17 13:08:06 +0100386/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100387#define LW_DATE 1 /* date */
388#define LW_CLIP 2 /* CLient IP */
389#define LW_SVIP 4 /* SerVer IP */
390#define LW_SVID 8 /* server ID */
391#define LW_REQ 16 /* http REQuest */
392#define LW_RESP 32 /* http RESPonse */
393#define LW_PXIP 64 /* proxy IP */
394#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100395#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100396#define LW_COOKIE 512 /* captured cookie */
397#define LW_REQHDR 1024 /* request header(s) */
398#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100399
willy tarreau0f7af912005-12-17 12:21:26 +0100400/*********************************************************************/
401
402#define LIST_HEAD(a) ((void *)(&(a)))
403
404/*********************************************************************/
405
willy tarreau4302f492005-12-18 01:00:37 +0100406struct cap_hdr {
407 struct cap_hdr *next;
408 char *name; /* header name, case insensitive */
409 int namelen; /* length of the header name, to speed-up lookups */
410 int len; /* capture length, not including terminal zero */
411 int index; /* index in the output array */
412 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
413};
414
willy tarreau0f7af912005-12-17 12:21:26 +0100415struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100416 struct hdr_exp *next;
417 regex_t *preg; /* expression to look for */
418 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
419 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100420};
421
422struct buffer {
423 unsigned int l; /* data length */
424 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100425 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100426 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100427 char data[BUFSIZE];
428};
429
430struct server {
431 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100432 int state; /* server state (SRV_*) */
433 int cklen; /* the len of the cookie, to speed up checks */
434 char *cookie; /* the id set in the cookie */
435 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100436 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100437 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100438 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100439 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100440 int rise, fall; /* time in iterations */
441 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100442 int result; /* 0 = connect OK, -1 = connect KO */
443 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100444 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100445};
446
willy tarreau5cbea6f2005-12-17 12:48:26 +0100447/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100448struct task {
449 struct task *next, *prev; /* chaining ... */
450 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100451 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100452 int state; /* task state : IDLE or RUNNING */
453 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100454 int (*process)(struct task *t); /* the function which processes the task */
455 void *context; /* the task's context */
456};
457
458/* WARNING: if new fields are added, they must be initialized in event_accept() */
459struct session {
460 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100461 /* application specific below */
462 struct timeval crexpire; /* expiration date for a client read */
463 struct timeval cwexpire; /* expiration date for a client write */
464 struct timeval srexpire; /* expiration date for a server read */
465 struct timeval swexpire; /* expiration date for a server write */
466 struct timeval cnexpire; /* expiration date for a connect */
467 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
468 struct proxy *proxy; /* the proxy this socket belongs to */
469 int cli_fd; /* the client side fd */
470 int srv_fd; /* the server side fd */
471 int cli_state; /* state of the client side */
472 int srv_state; /* state of the server side */
473 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100474 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100475 struct buffer *req; /* request buffer */
476 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100477 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100478 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100479 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100480 char **req_cap; /* array of captured request headers (may be NULL) */
481 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100482 struct {
483 int logwait; /* log fields waiting to be collected : LW_* */
484 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
485 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
486 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
487 long t_data; /* delay before the first data byte from the server ... */
488 unsigned long t_close; /* total session duration */
489 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100490 char *cli_cookie; /* cookie presented by the client, in capture mode */
491 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100492 int status; /* HTTP status from the server, negative if from proxy */
493 long long bytes; /* number of bytes transferred from the server */
494 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100495 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100496};
497
willy tarreaua41a8b42005-12-17 14:02:24 +0100498struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100499 int fd; /* the listen socket */
500 struct sockaddr_storage addr; /* the address we listen to */
501 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100502};
503
504
willy tarreau0f7af912005-12-17 12:21:26 +0100505struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100506 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100507 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100508 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100509 struct server *srv, *cursrv; /* known servers, current server */
510 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100511 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100512 int cookie_len; /* strlen(cookie_name), computed only once */
513 char *appsession_name; /* name of the cookie to look for */
514 int appsession_name_len; /* strlen(appsession_name), computed only once */
515 int appsession_len; /* length of the appsession cookie value to be used */
516 int appsession_timeout;
517 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100518 char *capture_name; /* beginning of the name of the cookie to capture */
519 int capture_namelen; /* length of the cookie name to match */
520 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100521 int clitimeout; /* client I/O timeout (in milliseconds) */
522 int srvtimeout; /* server I/O timeout (in milliseconds) */
523 int contimeout; /* connect timeout (in milliseconds) */
524 char *id; /* proxy id */
525 int nbconn; /* # of active sessions */
526 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100527 int conn_retries; /* maximum number of connect retries */
528 int options; /* PR_O_REDISP, PR_O_TRANSP */
529 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100530 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100531 struct proxy *next;
532 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
533 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100534 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100535 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100536 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100537 int nb_reqadd, nb_rspadd;
538 struct hdr_exp *req_exp; /* regular expressions for request headers */
539 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100540 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
541 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
542 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
543 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100544 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100545 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100546 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
547 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100548 struct {
549 char *msg400; /* message for error 400 */
550 int len400; /* message length for error 400 */
551 char *msg403; /* message for error 403 */
552 int len403; /* message length for error 403 */
553 char *msg408; /* message for error 408 */
554 int len408; /* message length for error 408 */
555 char *msg500; /* message for error 500 */
556 int len500; /* message length for error 500 */
557 char *msg502; /* message for error 502 */
558 int len502; /* message length for error 502 */
559 char *msg503; /* message for error 503 */
560 int len503; /* message length for error 503 */
561 char *msg504; /* message for error 504 */
562 int len504; /* message length for error 504 */
563 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100564};
565
566/* info about one given fd */
567struct fdtab {
568 int (*read)(int fd); /* read function */
569 int (*write)(int fd); /* write function */
570 struct task *owner; /* the session (or proxy) associated with this fd */
571 int state; /* the state of this fd */
572};
573
574/*********************************************************************/
575
willy tarreau0f7af912005-12-17 12:21:26 +0100576int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100577char *cfg_cfgfile = NULL; /* configuration file */
578char *progname = NULL; /* program name */
579int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100580
581/* global options */
582static struct {
583 int uid;
584 int gid;
585 int nbproc;
586 int maxconn;
587 int maxsock; /* max # of sockets */
588 int mode;
589 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100590 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100591 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100592 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100593 struct sockaddr_in logsrv1, logsrv2;
594} global = {
595 logfac1 : -1,
596 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100597 loglev1 : 7, /* max syslog level : debug */
598 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100599 /* others NULL OK */
600};
601
willy tarreau0f7af912005-12-17 12:21:26 +0100602/*********************************************************************/
603
604fd_set *ReadEvent,
605 *WriteEvent,
606 *StaticReadEvent,
607 *StaticWriteEvent;
608
609void **pool_session = NULL,
610 **pool_buffer = NULL,
611 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100612 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100613 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100614 **pool_capture = NULL,
615 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100616
617struct proxy *proxy = NULL; /* list of all existing proxies */
618struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100619struct task *rq = NULL; /* global run queue */
620struct task wait_queue = { /* global wait queue */
621 prev:LIST_HEAD(wait_queue),
622 next:LIST_HEAD(wait_queue)
623};
willy tarreau0f7af912005-12-17 12:21:26 +0100624
willy tarreau0f7af912005-12-17 12:21:26 +0100625static int totalconn = 0; /* total # of terminated sessions */
626static int actconn = 0; /* # of active sessions */
627static int maxfd = 0; /* # of the highest fd + 1 */
628static int listeners = 0; /* # of listeners */
629static int stopping = 0; /* non zero means stopping in progress */
630static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100631static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100632
633static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100634/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100635static char trash[BUFSIZE];
636
willy tarreaudd07e972005-12-18 00:48:48 +0100637const int zero = 0;
638const int one = 1;
639
willy tarreau0f7af912005-12-17 12:21:26 +0100640/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100641 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100642 */
643
644#define MAX_SYSLOG_LEN 1024
645#define NB_LOG_FACILITIES 24
646const char *log_facilities[NB_LOG_FACILITIES] = {
647 "kern", "user", "mail", "daemon",
648 "auth", "syslog", "lpr", "news",
649 "uucp", "cron", "auth2", "ftp",
650 "ntp", "audit", "alert", "cron2",
651 "local0", "local1", "local2", "local3",
652 "local4", "local5", "local6", "local7"
653};
654
655
656#define NB_LOG_LEVELS 8
657const char *log_levels[NB_LOG_LEVELS] = {
658 "emerg", "alert", "crit", "err",
659 "warning", "notice", "info", "debug"
660};
661
662#define SYSLOG_PORT 514
663
664const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
665 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100666
667const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
668const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
669const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
670const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
671 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
672 unknown, Set-cookie Rewritten */
673
willy tarreau0f7af912005-12-17 12:21:26 +0100674#define MAX_HOSTNAME_LEN 32
675static char hostname[MAX_HOSTNAME_LEN] = "";
676
willy tarreau8337c6b2005-12-17 13:41:01 +0100677const char *HTTP_302 =
678 "HTTP/1.0 302 Found\r\n"
679 "Cache-Control: no-cache\r\n"
680 "Connection: close\r\n"
681 "Location: "; /* not terminated since it will be concatenated with the URL */
682
willy tarreaua1598082005-12-17 13:08:06 +0100683const char *HTTP_400 =
684 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100685 "Cache-Control: no-cache\r\n"
686 "Connection: close\r\n"
687 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100688 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100689
willy tarreaua1598082005-12-17 13:08:06 +0100690const char *HTTP_403 =
691 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100692 "Cache-Control: no-cache\r\n"
693 "Connection: close\r\n"
694 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100695 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
696
willy tarreau8337c6b2005-12-17 13:41:01 +0100697const char *HTTP_408 =
698 "HTTP/1.0 408 Request Time-out\r\n"
699 "Cache-Control: no-cache\r\n"
700 "Connection: close\r\n"
701 "\r\n"
702 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
703
willy tarreau750a4722005-12-17 13:21:24 +0100704const char *HTTP_500 =
705 "HTTP/1.0 500 Server Error\r\n"
706 "Cache-Control: no-cache\r\n"
707 "Connection: close\r\n"
708 "\r\n"
709 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100710
711const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100712 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100713 "Cache-Control: no-cache\r\n"
714 "Connection: close\r\n"
715 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100716 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
717
718const char *HTTP_503 =
719 "HTTP/1.0 503 Service Unavailable\r\n"
720 "Cache-Control: no-cache\r\n"
721 "Connection: close\r\n"
722 "\r\n"
723 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
724
725const char *HTTP_504 =
726 "HTTP/1.0 504 Gateway Time-out\r\n"
727 "Cache-Control: no-cache\r\n"
728 "Connection: close\r\n"
729 "\r\n"
730 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100731
willy tarreau0f7af912005-12-17 12:21:26 +0100732/*********************************************************************/
733/* statistics ******************************************************/
734/*********************************************************************/
735
willy tarreau750a4722005-12-17 13:21:24 +0100736#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100737static int stats_tsk_lsrch, stats_tsk_rsrch,
738 stats_tsk_good, stats_tsk_right, stats_tsk_left,
739 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100740#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100741
742
743/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100744/* debugging *******************************************************/
745/*********************************************************************/
746#ifdef DEBUG_FULL
747static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
748static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
749#endif
750
751/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100752/* function prototypes *********************************************/
753/*********************************************************************/
754
755int event_accept(int fd);
756int event_cli_read(int fd);
757int event_cli_write(int fd);
758int event_srv_read(int fd);
759int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100760int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100761
willy tarreau12350152005-12-18 01:03:27 +0100762static int appsession_task_init(void);
763static int appsession_init(void);
764static int appsession_refresh(struct task *t);
765
willy tarreau0f7af912005-12-17 12:21:26 +0100766/*********************************************************************/
767/* general purpose functions ***************************************/
768/*********************************************************************/
769
770void display_version() {
771 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau0174f312005-12-18 01:02:42 +0100772 printf("Copyright 2000-2005 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100773}
774
775/*
776 * This function prints the command line usage and exits
777 */
778void usage(char *name) {
779 display_version();
780 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100781 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100782#if STATTIME > 0
783 "sl"
784#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100785 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100786 " -v displays version\n"
787 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100788 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100789#if STATTIME > 0
790 " -s enables statistics output\n"
791 " -l enables long statistics format\n"
792#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100793 " -D goes daemon ; implies -q\n"
794 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100795 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100796 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100797 " -N sets the default, per-proxy maximum # of connections (%d)\n"
798 " -p writes pids of all children to this file\n\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100799 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100800 exit(1);
801}
802
803
804/*
805 * Displays the message on stderr with the date and pid.
806 */
807void Alert(char *fmt, ...) {
808 va_list argp;
809 struct timeval tv;
810 struct tm *tm;
811
willy tarreau982249e2005-12-18 00:57:06 +0100812 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100813 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100814
willy tarreau5cbea6f2005-12-17 12:48:26 +0100815 gettimeofday(&tv, NULL);
816 tm=localtime(&tv.tv_sec);
817 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100818 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100819 vfprintf(stderr, fmt, argp);
820 fflush(stderr);
821 va_end(argp);
822 }
willy tarreau0f7af912005-12-17 12:21:26 +0100823}
824
825
826/*
827 * Displays the message on stderr with the date and pid.
828 */
829void Warning(char *fmt, ...) {
830 va_list argp;
831 struct timeval tv;
832 struct tm *tm;
833
willy tarreau982249e2005-12-18 00:57:06 +0100834 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100835 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100836
willy tarreau5cbea6f2005-12-17 12:48:26 +0100837 gettimeofday(&tv, NULL);
838 tm=localtime(&tv.tv_sec);
839 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100840 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100841 vfprintf(stderr, fmt, argp);
842 fflush(stderr);
843 va_end(argp);
844 }
845}
846
847/*
848 * Displays the message on <out> only if quiet mode is not set.
849 */
850void qfprintf(FILE *out, char *fmt, ...) {
851 va_list argp;
852
willy tarreau982249e2005-12-18 00:57:06 +0100853 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100854 va_start(argp, fmt);
855 vfprintf(out, fmt, argp);
856 fflush(out);
857 va_end(argp);
858 }
willy tarreau0f7af912005-12-17 12:21:26 +0100859}
860
861
862/*
863 * converts <str> to a struct sockaddr_in* which is locally allocated.
864 * The format is "addr:port", where "addr" can be empty or "*" to indicate
865 * INADDR_ANY.
866 */
867struct sockaddr_in *str2sa(char *str) {
868 static struct sockaddr_in sa;
869 char *c;
870 int port;
871
willy tarreaua1598082005-12-17 13:08:06 +0100872 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100873 str=strdup(str);
874
875 if ((c=strrchr(str,':')) != NULL) {
876 *c++=0;
877 port=atol(c);
878 }
879 else
880 port=0;
881
882 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
883 sa.sin_addr.s_addr = INADDR_ANY;
884 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100885 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100886 struct hostent *he;
887
888 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100889 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100890 }
891 else
892 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
893 }
894 sa.sin_port=htons(port);
895 sa.sin_family=AF_INET;
896
897 free(str);
898 return &sa;
899}
900
willy tarreau9fe663a2005-12-17 13:02:59 +0100901
902/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100903 * converts <str> to a list of listeners which are dynamically allocated.
904 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
905 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
906 * - <port> is a numerical port from 1 to 65535 ;
907 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
908 * This can be repeated as many times as necessary, separated by a coma.
909 * The <tail> argument is a pointer to a current list which should be appended
910 * to the tail of the new list. The pointer to the new list is returned.
911 */
912struct listener *str2listener(char *str, struct listener *tail) {
913 struct listener *l;
914 char *c, *next, *range, *dupstr;
915 int port, end;
916
917 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +0100918
willy tarreaua41a8b42005-12-17 14:02:24 +0100919 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100920 struct sockaddr_storage ss;
921
willy tarreaua41a8b42005-12-17 14:02:24 +0100922 str = next;
923 /* 1) look for the end of the first address */
924 if ((next = strrchr(str, ',')) != NULL) {
925 *next++ = 0;
926 }
927
willy tarreau8a86dbf2005-12-18 00:45:59 +0100928 /* 2) look for the addr/port delimiter, it's the last colon. */
929 if ((range = strrchr(str, ':')) == NULL) {
930 Alert("Missing port number: '%s'\n", str);
931 }
932
933 *range++ = 0;
934
935 if (strrchr(str, ':') != NULL) {
936 /* IPv6 address contains ':' */
937 memset(&ss, 0, sizeof(ss));
938 ss.ss_family = AF_INET6;
939
940 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
941 Alert("Invalid server address: '%s'\n", str);
942 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100943 }
944 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100945 memset(&ss, 0, sizeof(ss));
946 ss.ss_family = AF_INET;
947
948 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
949 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
950 }
951 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
952 struct hostent *he;
953
954 if ((he = gethostbyname(str)) == NULL) {
955 Alert("Invalid server name: '%s'\n", str);
956 }
957 else
958 ((struct sockaddr_in *)&ss)->sin_addr =
959 *(struct in_addr *) *(he->h_addr_list);
960 }
961 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100962
963 /* 3) look for the port-end delimiter */
964 if ((c = strchr(range, '-')) != NULL) {
965 *c++ = 0;
966 end = atol(c);
967 }
968 else {
969 end = atol(range);
970 }
971
972 for (port = atol(range); port <= end; port++) {
973 l = (struct listener *)calloc(1, sizeof(struct listener));
974 l->next = tail;
975 tail = l;
976
willy tarreau8a86dbf2005-12-18 00:45:59 +0100977 l->addr = ss;
978 if (ss.ss_family == AF_INET6)
979 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
980 else
981 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
982
willy tarreaua41a8b42005-12-17 14:02:24 +0100983 } /* end for(port) */
984 } /* end while(next) */
985 free(dupstr);
986 return tail;
987}
988
willy tarreau4302f492005-12-18 01:00:37 +0100989
990#define FD_SETS_ARE_BITFIELDS
991#ifdef FD_SETS_ARE_BITFIELDS
992/*
993 * This map is used with all the FD_* macros to check whether a particular bit
994 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
995 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
996 * byte should be encoded. Be careful to always pass bytes from 0 to 255
997 * exclusively to the macros.
998 */
999fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1000fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1001
1002#else
1003#error "Check if your OS uses bitfields for fd_sets"
1004#endif
1005
1006/* will try to encode the string <string> replacing all characters tagged in
1007 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1008 * prefixed by <escape>, and will store the result between <start> (included
1009 *) and <stop> (excluded), and will always terminate the string with a '\0'
1010 * before <stop>. The position of the '\0' is returned if the conversion
1011 * completes. If bytes are missing between <start> and <stop>, then the
1012 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1013 * cannot even be stored so we return <start> without writing the 0.
1014 * The input string must also be zero-terminated.
1015 */
1016char hextab[16] = "0123456789ABCDEF";
1017char *encode_string(char *start, char *stop,
1018 const char escape, const fd_set *map,
1019 const char *string)
1020{
1021 if (start < stop) {
1022 stop--; /* reserve one byte for the final '\0' */
1023 while (start < stop && *string != 0) {
1024 if (!FD_ISSET((unsigned char)(*string), map))
1025 *start++ = *string;
1026 else {
1027 if (start + 3 >= stop)
1028 break;
1029 *start++ = escape;
1030 *start++ = hextab[(*string >> 4) & 15];
1031 *start++ = hextab[*string & 15];
1032 }
1033 string++;
1034 }
1035 *start = '\0';
1036 }
1037 return start;
1038}
willy tarreaua41a8b42005-12-17 14:02:24 +01001039
1040/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001041 * This function sends a syslog message to both log servers of a proxy,
1042 * or to global log servers if the proxy is NULL.
1043 * It also tries not to waste too much time computing the message header.
1044 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001045 */
1046void send_log(struct proxy *p, int level, char *message, ...) {
1047 static int logfd = -1; /* syslog UDP socket */
1048 static long tvsec = -1; /* to force the string to be initialized */
1049 struct timeval tv;
1050 va_list argp;
1051 static char logmsg[MAX_SYSLOG_LEN];
1052 static char *dataptr = NULL;
1053 int fac_level;
1054 int hdr_len, data_len;
1055 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001056 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001057 int nbloggers = 0;
1058 char *log_ptr;
1059
1060 if (logfd < 0) {
1061 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1062 return;
1063 }
1064
1065 if (level < 0 || progname == NULL || message == NULL)
1066 return;
1067
1068 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001069 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001070 /* this string is rebuild only once a second */
1071 struct tm *tm = localtime(&tv.tv_sec);
1072 tvsec = tv.tv_sec;
1073
willy tarreauc29948c2005-12-17 13:10:27 +01001074 hdr_len = snprintf(logmsg, sizeof(logmsg),
1075 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1076 monthname[tm->tm_mon],
1077 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1078 progname, pid);
1079 /* WARNING: depending upon implementations, snprintf may return
1080 * either -1 or the number of bytes that would be needed to store
1081 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001082 */
willy tarreauc29948c2005-12-17 13:10:27 +01001083 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1084 hdr_len = sizeof(logmsg);
1085
1086 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001087 }
1088
1089 va_start(argp, message);
1090 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001091 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1092 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001093 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001094 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001095
1096 if (p == NULL) {
1097 if (global.logfac1 >= 0) {
1098 sa[nbloggers] = &global.logsrv1;
1099 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001100 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001101 nbloggers++;
1102 }
1103 if (global.logfac2 >= 0) {
1104 sa[nbloggers] = &global.logsrv2;
1105 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001106 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001107 nbloggers++;
1108 }
1109 } else {
1110 if (p->logfac1 >= 0) {
1111 sa[nbloggers] = &p->logsrv1;
1112 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001113 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001114 nbloggers++;
1115 }
1116 if (p->logfac2 >= 0) {
1117 sa[nbloggers] = &p->logsrv2;
1118 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001119 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001120 nbloggers++;
1121 }
1122 }
1123
1124 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001125 /* we can filter the level of the messages that are sent to each logger */
1126 if (level > loglevel[nbloggers])
1127 continue;
1128
willy tarreauc29948c2005-12-17 13:10:27 +01001129 /* For each target, we may have a different facility.
1130 * We can also have a different log level for each message.
1131 * This induces variations in the message header length.
1132 * Since we don't want to recompute it each time, nor copy it every
1133 * time, we only change the facility in the pre-computed header,
1134 * and we change the pointer to the header accordingly.
1135 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001136 fac_level = (facilities[nbloggers] << 3) + level;
1137 log_ptr = logmsg + 3; /* last digit of the log level */
1138 do {
1139 *log_ptr = '0' + fac_level % 10;
1140 fac_level /= 10;
1141 log_ptr--;
1142 } while (fac_level && log_ptr > logmsg);
1143 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001144
willy tarreauc29948c2005-12-17 13:10:27 +01001145 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001146
1147#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001148 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001149 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1150#else
willy tarreauc29948c2005-12-17 13:10:27 +01001151 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001152 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1153#endif
1154 }
willy tarreau0f7af912005-12-17 12:21:26 +01001155}
1156
1157
1158/* sets <tv> to the current time */
1159static inline struct timeval *tv_now(struct timeval *tv) {
1160 if (tv)
1161 gettimeofday(tv, NULL);
1162 return tv;
1163}
1164
1165/*
1166 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1167 */
1168static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1169 if (!tv || !from)
1170 return NULL;
1171 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1172 tv->tv_sec = from->tv_sec + (ms/1000);
1173 while (tv->tv_usec >= 1000000) {
1174 tv->tv_usec -= 1000000;
1175 tv->tv_sec++;
1176 }
1177 return tv;
1178}
1179
1180/*
1181 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1182 */
1183static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001184 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001185 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001186 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001187 return 1;
1188 else if (tv1->tv_usec < tv2->tv_usec)
1189 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001190 else if (tv1->tv_usec > tv2->tv_usec)
1191 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001192 else
1193 return 0;
1194}
1195
1196/*
1197 * returns the absolute difference, in ms, between tv1 and tv2
1198 */
1199unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1200 int cmp;
1201 unsigned long ret;
1202
1203
willy tarreauef900ab2005-12-17 12:52:52 +01001204 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001205 if (!cmp)
1206 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001207 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001208 struct timeval *tmp = tv1;
1209 tv1 = tv2;
1210 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001211 }
willy tarreauef900ab2005-12-17 12:52:52 +01001212 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001213 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001214 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001215 else
willy tarreauef900ab2005-12-17 12:52:52 +01001216 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001217 return (unsigned long) ret;
1218}
1219
1220/*
willy tarreau750a4722005-12-17 13:21:24 +01001221 * returns the difference, in ms, between tv1 and tv2
1222 */
1223static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1224 unsigned long ret;
1225
willy tarreau6e682ce2005-12-17 13:26:49 +01001226 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1227 if (tv2->tv_usec > tv1->tv_usec)
1228 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001229 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001230 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001231 return (unsigned long) ret;
1232}
1233
1234/*
willy tarreau0f7af912005-12-17 12:21:26 +01001235 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1236 */
1237static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001238 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001239 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001240 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001241 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1242 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001243 else
1244 return 0;
1245 }
willy tarreau0f7af912005-12-17 12:21:26 +01001246 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001247 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001248 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001249 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1250 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1251 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001252 else
1253 return 0;
1254}
1255
1256/*
1257 * returns the remaining time between tv1=now and event=tv2
1258 * if tv2 is passed, 0 is returned.
1259 */
1260static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1261 unsigned long ret;
1262
willy tarreau0f7af912005-12-17 12:21:26 +01001263 if (tv_cmp_ms(tv1, tv2) >= 0)
1264 return 0; /* event elapsed */
1265
willy tarreauef900ab2005-12-17 12:52:52 +01001266 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001267 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001268 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001269 else
willy tarreauef900ab2005-12-17 12:52:52 +01001270 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001271 return (unsigned long) ret;
1272}
1273
1274
1275/*
1276 * zeroes a struct timeval
1277 */
1278
1279static inline struct timeval *tv_eternity(struct timeval *tv) {
1280 tv->tv_sec = tv->tv_usec = 0;
1281 return tv;
1282}
1283
1284/*
1285 * returns 1 if tv is null, else 0
1286 */
1287static inline int tv_iseternity(struct timeval *tv) {
1288 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1289 return 1;
1290 else
1291 return 0;
1292}
1293
1294/*
1295 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1296 * considering that 0 is the eternity.
1297 */
1298static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1299 if (tv_iseternity(tv1))
1300 if (tv_iseternity(tv2))
1301 return 0; /* same */
1302 else
1303 return 1; /* tv1 later than tv2 */
1304 else if (tv_iseternity(tv2))
1305 return -1; /* tv2 later than tv1 */
1306
1307 if (tv1->tv_sec > tv2->tv_sec)
1308 return 1;
1309 else if (tv1->tv_sec < tv2->tv_sec)
1310 return -1;
1311 else if (tv1->tv_usec > tv2->tv_usec)
1312 return 1;
1313 else if (tv1->tv_usec < tv2->tv_usec)
1314 return -1;
1315 else
1316 return 0;
1317}
1318
1319/*
1320 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1321 * considering that 0 is the eternity.
1322 */
1323static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1324 if (tv_iseternity(tv1))
1325 if (tv_iseternity(tv2))
1326 return 0; /* same */
1327 else
1328 return 1; /* tv1 later than tv2 */
1329 else if (tv_iseternity(tv2))
1330 return -1; /* tv2 later than tv1 */
1331
willy tarreauefae1842005-12-17 12:51:03 +01001332 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001333 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001334 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001335 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001336 return -1;
1337 else
1338 return 0;
1339 }
1340 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001341 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001342 return 1;
1343 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001344 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001345 return -1;
1346 else
1347 return 0;
1348}
1349
1350/*
1351 * returns the first event between tv1 and tv2 into tvmin.
1352 * a zero tv is ignored. tvmin is returned.
1353 */
1354static inline struct timeval *tv_min(struct timeval *tvmin,
1355 struct timeval *tv1, struct timeval *tv2) {
1356
1357 if (tv_cmp2(tv1, tv2) <= 0)
1358 *tvmin = *tv1;
1359 else
1360 *tvmin = *tv2;
1361
1362 return tvmin;
1363}
1364
1365
1366
1367/***********************************************************/
1368/* fd management ***************************************/
1369/***********************************************************/
1370
1371
1372
willy tarreau5cbea6f2005-12-17 12:48:26 +01001373/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1374 * The file descriptor is also closed.
1375 */
willy tarreau0f7af912005-12-17 12:21:26 +01001376static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001377 FD_CLR(fd, StaticReadEvent);
1378 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001379 close(fd);
1380 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001381
1382 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1383 maxfd--;
1384}
1385
1386/* recomputes the maxfd limit from the fd */
1387static inline void fd_insert(int fd) {
1388 if (fd+1 > maxfd)
1389 maxfd = fd+1;
1390}
1391
1392/*************************************************************/
1393/* task management ***************************************/
1394/*************************************************************/
1395
willy tarreau5cbea6f2005-12-17 12:48:26 +01001396/* puts the task <t> in run queue <q>, and returns <t> */
1397static inline struct task *task_wakeup(struct task **q, struct task *t) {
1398 if (t->state == TASK_RUNNING)
1399 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001400 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001401 t->rqnext = *q;
1402 t->state = TASK_RUNNING;
1403 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001404 }
1405}
1406
willy tarreau5cbea6f2005-12-17 12:48:26 +01001407/* removes the task <t> from the queue <q>
1408 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001409 * set the run queue to point to the next one, and return it
1410 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001411static inline struct task *task_sleep(struct task **q, struct task *t) {
1412 if (t->state == TASK_RUNNING) {
1413 *q = t->rqnext;
1414 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001415 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001416 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001417}
1418
1419/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001420 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001421 * from the run queue. A pointer to the task itself is returned.
1422 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001423static inline struct task *task_delete(struct task *t) {
1424 t->prev->next = t->next;
1425 t->next->prev = t->prev;
1426 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001427}
1428
1429/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001430 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001431 */
1432static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001433 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001434}
1435
willy tarreau5cbea6f2005-12-17 12:48:26 +01001436/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001437 * may be only moved or left where it was, depending on its timing requirements.
1438 * <task> is returned.
1439 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001440struct task *task_queue(struct task *task) {
1441 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001442 struct task *start_from;
1443
1444 /* first, test if the task was already in a list */
1445 if (task->prev == NULL) {
1446 // start_from = list;
1447 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001448#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001449 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001450#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001451 /* insert the unlinked <task> into the list, searching back from the last entry */
1452 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1453 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001454#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001455 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001456#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001457 }
1458
1459 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1460 // start_from = start_from->next;
1461 // stats_tsk_nsrch++;
1462 // }
1463 }
1464 else if (task->prev == list ||
1465 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1466 start_from = task->next;
1467 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001468#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001469 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001470#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001471 return task; /* it's already in the right place */
1472 }
1473
willy tarreau750a4722005-12-17 13:21:24 +01001474#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001475 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001476#endif
1477
1478 /* if the task is not at the right place, there's little chance that
1479 * it has only shifted a bit, and it will nearly always be queued
1480 * at the end of the list because of constant timeouts
1481 * (observed in real case).
1482 */
1483#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1484 start_from = list->prev; /* assume we'll queue to the end of the list */
1485 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1486 start_from = start_from->prev;
1487#if STATTIME > 0
1488 stats_tsk_lsrch++;
1489#endif
1490 }
1491#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001492 /* insert the unlinked <task> into the list, searching after position <start_from> */
1493 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1494 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001495#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001496 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001497#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001498 }
willy tarreau750a4722005-12-17 13:21:24 +01001499#endif /* WE_REALLY_... */
1500
willy tarreau0f7af912005-12-17 12:21:26 +01001501 /* we need to unlink it now */
1502 task_delete(task);
1503 }
1504 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001505#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001506 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001507#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001508#ifdef LEFT_TO_TOP /* not very good */
1509 start_from = list;
1510 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1511 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001512#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001513 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001514#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001515 }
1516#else
1517 start_from = task->prev->prev; /* valid because of the previous test above */
1518 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1519 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001520#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001521 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001522#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001523 }
1524#endif
1525 /* we need to unlink it now */
1526 task_delete(task);
1527 }
1528 task->prev = start_from;
1529 task->next = start_from->next;
1530 task->next->prev = task;
1531 start_from->next = task;
1532 return task;
1533}
1534
1535
1536/*********************************************************************/
1537/* more specific functions ***************************************/
1538/*********************************************************************/
1539
1540/* some prototypes */
1541static int maintain_proxies(void);
1542
willy tarreau5cbea6f2005-12-17 12:48:26 +01001543/* this either returns the sockname or the original destination address. Code
1544 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1545 */
1546static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001547#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001548 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1549#else
willy tarreaua1598082005-12-17 13:08:06 +01001550#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001551 return getsockname(fd, (struct sockaddr *)sa, salen);
1552#else
1553 return -1;
1554#endif
1555#endif
1556}
1557
1558/*
1559 * frees the context associated to a session. It must have been removed first.
1560 */
1561static inline void session_free(struct session *s) {
1562 if (s->req)
1563 pool_free(buffer, s->req);
1564 if (s->rep)
1565 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001566
1567 if (s->rsp_cap != NULL) {
1568 struct cap_hdr *h;
1569 for (h = s->proxy->rsp_cap; h; h = h->next) {
1570 if (s->rsp_cap[h->index] != NULL)
1571 pool_free_to(h->pool, s->rsp_cap[h->index]);
1572 }
1573 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1574 }
1575 if (s->req_cap != NULL) {
1576 struct cap_hdr *h;
1577 for (h = s->proxy->req_cap; h; h = h->next) {
1578 if (s->req_cap[h->index] != NULL)
1579 pool_free_to(h->pool, s->req_cap[h->index]);
1580 }
1581 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1582 }
1583
willy tarreaua1598082005-12-17 13:08:06 +01001584 if (s->logs.uri)
1585 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001586 if (s->logs.cli_cookie)
1587 pool_free(capture, s->logs.cli_cookie);
1588 if (s->logs.srv_cookie)
1589 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001590
willy tarreau5cbea6f2005-12-17 12:48:26 +01001591 pool_free(session, s);
1592}
1593
willy tarreau0f7af912005-12-17 12:21:26 +01001594
1595/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001596 * This function tries to find a running server for the proxy <px>. A first
1597 * pass looks for active servers, and if none is found, a second pass also
1598 * looks for backup servers.
1599 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1600 */
1601static inline struct server *find_server(struct proxy *px) {
1602 struct server *srv = px->cursrv;
1603 int ignore_backup = 1;
1604
1605 do {
1606 do {
1607 if (srv == NULL)
1608 srv = px->srv;
1609 if (srv->state & SRV_RUNNING
1610 && !((srv->state & SRV_BACKUP) && ignore_backup))
1611 return srv;
1612 srv = srv->next;
1613 } while (srv != px->cursrv);
1614 } while (ignore_backup--);
1615 return NULL;
1616}
1617
1618/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001619 * This function initiates a connection to the current server (s->srv) if (s->direct)
1620 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001621 * it's OK, -1 if it's impossible.
1622 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001624 int fd;
1625
willy tarreau12350152005-12-18 01:03:27 +01001626#ifdef DEBUG_FULL
1627 fprintf(stderr,"connect_server : s=%p\n",s);
1628#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001629
willy tarreaue39cd132005-12-17 13:00:18 +01001630 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001631 s->srv_addr = s->srv->addr;
1632 }
1633 else if (s->proxy->options & PR_O_BALANCE) {
1634 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001635 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001636
willy tarreau8337c6b2005-12-17 13:41:01 +01001637 srv = find_server(s->proxy);
1638
1639 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001640 return -1;
1641
willy tarreau8337c6b2005-12-17 13:41:01 +01001642 s->srv_addr = srv->addr;
1643 s->srv = srv;
1644 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001645 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001646 else /* unknown balancing algorithm */
1647 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001648 }
willy tarreaua1598082005-12-17 13:08:06 +01001649 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001650 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001651 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001652 }
1653 else if (s->proxy->options & PR_O_TRANSP) {
1654 /* in transparent mode, use the original dest addr if no dispatch specified */
1655 int salen = sizeof(struct sockaddr_in);
1656 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1657 qfprintf(stderr, "Cannot get original server address.\n");
1658 return -1;
1659 }
1660 }
willy tarreau0f7af912005-12-17 12:21:26 +01001661
willy tarreaua41a8b42005-12-17 14:02:24 +01001662 /* if this server remaps proxied ports, we'll use
1663 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001664 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001665 struct sockaddr_in sockname;
1666 int namelen;
1667
1668 namelen = sizeof(sockname);
1669 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1670 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1671 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1672 }
1673
willy tarreau0f7af912005-12-17 12:21:26 +01001674 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001675 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001676 return -1;
1677 }
1678
willy tarreau9fe663a2005-12-17 13:02:59 +01001679 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001680 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1681 close(fd);
1682 return -1;
1683 }
1684
willy tarreau0f7af912005-12-17 12:21:26 +01001685 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1686 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001687 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001688 close(fd);
1689 return -1;
1690 }
1691
willy tarreau0174f312005-12-18 01:02:42 +01001692 /* allow specific binding :
1693 * - server-specific at first
1694 * - proxy-specific next
1695 */
1696 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1697 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1698 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1699 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1700 s->proxy->id, s->srv->id);
1701 close(fd);
1702 return -1;
1703 }
1704 }
1705 else if (s->proxy->options & PR_O_BIND_SRC) {
1706 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1707 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1708 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1709 close(fd);
1710 return -1;
1711 }
willy tarreaua1598082005-12-17 13:08:06 +01001712 }
1713
willy tarreau0f7af912005-12-17 12:21:26 +01001714 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1715 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001716 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001717 close(fd);
1718 return -1;
1719 }
1720 else if (errno != EALREADY && errno != EISCONN) {
1721 close(fd);
1722 return -1;
1723 }
1724 }
1725
willy tarreau5cbea6f2005-12-17 12:48:26 +01001726 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001727 fdtab[fd].read = &event_srv_read;
1728 fdtab[fd].write = &event_srv_write;
1729 fdtab[fd].state = FD_STCONN; /* connection in progress */
1730
1731 FD_SET(fd, StaticWriteEvent); /* for connect status */
1732
1733 fd_insert(fd);
1734
1735 if (s->proxy->contimeout)
1736 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1737 else
1738 tv_eternity(&s->cnexpire);
1739 return 0;
1740}
1741
1742/*
1743 * this function is called on a read event from a client socket.
1744 * It returns 0.
1745 */
1746int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001747 struct task *t = fdtab[fd].owner;
1748 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001749 struct buffer *b = s->req;
1750 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001751
willy tarreau12350152005-12-18 01:03:27 +01001752#ifdef DEBUG_FULL
1753 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1754#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001755
willy tarreau0f7af912005-12-17 12:21:26 +01001756 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001757 while (1) {
1758 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1759 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001760 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001761 }
1762 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001763 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001764 }
1765 else {
1766 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001767 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1768 * since it means that the rewrite protection has been removed. This
1769 * implies that the if statement can be removed.
1770 */
1771 if (max > b->rlim - b->data)
1772 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001773 }
1774
1775 if (max == 0) { /* not anymore room to store data */
1776 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001777 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001778 }
1779
willy tarreau3242e862005-12-17 12:27:53 +01001780#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001781 {
1782 int skerr, lskerr;
1783
1784 lskerr = sizeof(skerr);
1785 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1786 if (skerr)
1787 ret = -1;
1788 else
1789 ret = recv(fd, b->r, max, 0);
1790 }
willy tarreau3242e862005-12-17 12:27:53 +01001791#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001792 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001793#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001794 if (ret > 0) {
1795 b->r += ret;
1796 b->l += ret;
1797 s->res_cr = RES_DATA;
1798
1799 if (b->r == b->data + BUFSIZE) {
1800 b->r = b->data; /* wrap around the buffer */
1801 }
willy tarreaua1598082005-12-17 13:08:06 +01001802
1803 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001804 /* we hope to read more data or to get a close on next round */
1805 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001806 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001807 else if (ret == 0) {
1808 s->res_cr = RES_NULL;
1809 break;
1810 }
1811 else if (errno == EAGAIN) {/* ignore EAGAIN */
1812 break;
1813 }
1814 else {
1815 s->res_cr = RES_ERROR;
1816 fdtab[fd].state = FD_STERROR;
1817 break;
1818 }
1819 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001820 }
1821 else {
1822 s->res_cr = RES_ERROR;
1823 fdtab[fd].state = FD_STERROR;
1824 }
1825
willy tarreau5cbea6f2005-12-17 12:48:26 +01001826 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001827 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001828 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1829 else
1830 tv_eternity(&s->crexpire);
1831
1832 task_wakeup(&rq, t);
1833 }
willy tarreau0f7af912005-12-17 12:21:26 +01001834
willy tarreau0f7af912005-12-17 12:21:26 +01001835 return 0;
1836}
1837
1838
1839/*
1840 * this function is called on a read event from a server socket.
1841 * It returns 0.
1842 */
1843int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001844 struct task *t = fdtab[fd].owner;
1845 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001846 struct buffer *b = s->rep;
1847 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001848
willy tarreau12350152005-12-18 01:03:27 +01001849#ifdef DEBUG_FULL
1850 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1851#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001852
willy tarreau0f7af912005-12-17 12:21:26 +01001853 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001854 while (1) {
1855 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1856 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001857 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001858 }
1859 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001860 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001861 }
1862 else {
1863 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001864 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1865 * since it means that the rewrite protection has been removed. This
1866 * implies that the if statement can be removed.
1867 */
1868 if (max > b->rlim - b->data)
1869 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001870 }
1871
1872 if (max == 0) { /* not anymore room to store data */
1873 FD_CLR(fd, StaticReadEvent);
1874 break;
1875 }
1876
willy tarreau3242e862005-12-17 12:27:53 +01001877#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 {
1879 int skerr, lskerr;
1880
1881 lskerr = sizeof(skerr);
1882 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1883 if (skerr)
1884 ret = -1;
1885 else
1886 ret = recv(fd, b->r, max, 0);
1887 }
willy tarreau3242e862005-12-17 12:27:53 +01001888#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001889 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001890#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001891 if (ret > 0) {
1892 b->r += ret;
1893 b->l += ret;
1894 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001895
willy tarreau5cbea6f2005-12-17 12:48:26 +01001896 if (b->r == b->data + BUFSIZE) {
1897 b->r = b->data; /* wrap around the buffer */
1898 }
willy tarreaua1598082005-12-17 13:08:06 +01001899
1900 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001901 /* we hope to read more data or to get a close on next round */
1902 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001903 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001904 else if (ret == 0) {
1905 s->res_sr = RES_NULL;
1906 break;
1907 }
1908 else if (errno == EAGAIN) {/* ignore EAGAIN */
1909 break;
1910 }
1911 else {
1912 s->res_sr = RES_ERROR;
1913 fdtab[fd].state = FD_STERROR;
1914 break;
1915 }
1916 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001917 }
1918 else {
1919 s->res_sr = RES_ERROR;
1920 fdtab[fd].state = FD_STERROR;
1921 }
1922
willy tarreau5cbea6f2005-12-17 12:48:26 +01001923 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001924 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001925 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1926 else
1927 tv_eternity(&s->srexpire);
1928
1929 task_wakeup(&rq, t);
1930 }
willy tarreau0f7af912005-12-17 12:21:26 +01001931
willy tarreau0f7af912005-12-17 12:21:26 +01001932 return 0;
1933}
1934
1935/*
1936 * this function is called on a write event from a client socket.
1937 * It returns 0.
1938 */
1939int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001940 struct task *t = fdtab[fd].owner;
1941 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001942 struct buffer *b = s->rep;
1943 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001944
willy tarreau12350152005-12-18 01:03:27 +01001945#ifdef DEBUG_FULL
1946 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1947#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001948
1949 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001950 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001951 // max = BUFSIZE; BUG !!!!
1952 max = 0;
1953 }
1954 else if (b->r > b->w) {
1955 max = b->r - b->w;
1956 }
1957 else
1958 max = b->data + BUFSIZE - b->w;
1959
willy tarreau0f7af912005-12-17 12:21:26 +01001960 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001961#ifndef MSG_NOSIGNAL
1962 int skerr, lskerr;
1963#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001964
1965 if (max == 0) {
1966 s->res_cw = RES_NULL;
1967 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01001968 tv_eternity(&s->cwexpire);
1969 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001970 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001971 }
1972
willy tarreau3242e862005-12-17 12:27:53 +01001973#ifndef MSG_NOSIGNAL
1974 lskerr=sizeof(skerr);
1975 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1976 if (skerr)
1977 ret = -1;
1978 else
1979 ret = send(fd, b->w, max, MSG_DONTWAIT);
1980#else
willy tarreau0f7af912005-12-17 12:21:26 +01001981 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001982#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001983
1984 if (ret > 0) {
1985 b->l -= ret;
1986 b->w += ret;
1987
1988 s->res_cw = RES_DATA;
1989
1990 if (b->w == b->data + BUFSIZE) {
1991 b->w = b->data; /* wrap around the buffer */
1992 }
1993 }
1994 else if (ret == 0) {
1995 /* nothing written, just make as if we were never called */
1996// s->res_cw = RES_NULL;
1997 return 0;
1998 }
1999 else if (errno == EAGAIN) /* ignore EAGAIN */
2000 return 0;
2001 else {
2002 s->res_cw = RES_ERROR;
2003 fdtab[fd].state = FD_STERROR;
2004 }
2005 }
2006 else {
2007 s->res_cw = RES_ERROR;
2008 fdtab[fd].state = FD_STERROR;
2009 }
2010
willy tarreaub1ff9db2005-12-17 13:51:03 +01002011 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002012 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002013 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2014 s->crexpire = s->cwexpire;
2015 }
willy tarreau0f7af912005-12-17 12:21:26 +01002016 else
2017 tv_eternity(&s->cwexpire);
2018
willy tarreau5cbea6f2005-12-17 12:48:26 +01002019 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002020 return 0;
2021}
2022
2023
2024/*
2025 * this function is called on a write event from a server socket.
2026 * It returns 0.
2027 */
2028int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002029 struct task *t = fdtab[fd].owner;
2030 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002031 struct buffer *b = s->req;
2032 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002033
willy tarreau12350152005-12-18 01:03:27 +01002034#ifdef DEBUG_FULL
2035 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2036#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002037
2038 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002039 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002040 // max = BUFSIZE; BUG !!!!
2041 max = 0;
2042 }
2043 else if (b->r > b->w) {
2044 max = b->r - b->w;
2045 }
2046 else
2047 max = b->data + BUFSIZE - b->w;
2048
willy tarreau0f7af912005-12-17 12:21:26 +01002049 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01002050#ifndef MSG_NOSIGNAL
2051 int skerr, lskerr;
2052#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002053 if (max == 0) {
2054 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01002055 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002056 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002057 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002058 tv_eternity(&s->swexpire);
2059 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002060 return 0;
2061 }
2062
willy tarreauef900ab2005-12-17 12:52:52 +01002063
willy tarreau3242e862005-12-17 12:27:53 +01002064#ifndef MSG_NOSIGNAL
2065 lskerr=sizeof(skerr);
2066 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2067 if (skerr)
2068 ret = -1;
2069 else
2070 ret = send(fd, b->w, max, MSG_DONTWAIT);
2071#else
willy tarreau0f7af912005-12-17 12:21:26 +01002072 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002073#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002074 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002075 if (ret > 0) {
2076 b->l -= ret;
2077 b->w += ret;
2078
2079 s->res_sw = RES_DATA;
2080
2081 if (b->w == b->data + BUFSIZE) {
2082 b->w = b->data; /* wrap around the buffer */
2083 }
2084 }
2085 else if (ret == 0) {
2086 /* nothing written, just make as if we were never called */
2087 // s->res_sw = RES_NULL;
2088 return 0;
2089 }
2090 else if (errno == EAGAIN) /* ignore EAGAIN */
2091 return 0;
2092 else {
2093 s->res_sw = RES_ERROR;
2094 fdtab[fd].state = FD_STERROR;
2095 }
2096 }
2097 else {
2098 s->res_sw = RES_ERROR;
2099 fdtab[fd].state = FD_STERROR;
2100 }
2101
willy tarreaub1ff9db2005-12-17 13:51:03 +01002102 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002103 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002104 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2105 s->srexpire = s->swexpire;
2106 }
willy tarreau0f7af912005-12-17 12:21:26 +01002107 else
2108 tv_eternity(&s->swexpire);
2109
willy tarreau5cbea6f2005-12-17 12:48:26 +01002110 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002111 return 0;
2112}
2113
2114
2115/*
willy tarreaue39cd132005-12-17 13:00:18 +01002116 * returns a message to the client ; the connection is shut down for read,
2117 * and the request is cleared so that no server connection can be initiated.
2118 * The client must be in a valid state for this (HEADER, DATA ...).
2119 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002120 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002121 */
2122void client_retnclose(struct session *s, int len, const char *msg) {
2123 FD_CLR(s->cli_fd, StaticReadEvent);
2124 FD_SET(s->cli_fd, StaticWriteEvent);
2125 tv_eternity(&s->crexpire);
2126 shutdown(s->cli_fd, SHUT_RD);
2127 s->cli_state = CL_STSHUTR;
2128 strcpy(s->rep->data, msg);
2129 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002130 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002131 s->rep->r += len;
2132 s->req->l = 0;
2133}
2134
2135
2136/*
2137 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002138 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002139 */
2140void client_return(struct session *s, int len, const char *msg) {
2141 strcpy(s->rep->data, msg);
2142 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002143 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002144 s->rep->r += len;
2145 s->req->l = 0;
2146}
2147
willy tarreau9fe663a2005-12-17 13:02:59 +01002148/*
2149 * send a log for the session when we have enough info about it
2150 */
2151void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002152 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002153 struct proxy *p = s->proxy;
2154 int log;
2155 char *uri;
2156 char *pxid;
2157 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002158 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002159
2160 /* This is a first attempt at a better logging system.
2161 * For now, we rely on send_log() to provide the date, although it obviously
2162 * is the date of the log and not of the request, and most fields are not
2163 * computed.
2164 */
2165
willy tarreaua1598082005-12-17 13:08:06 +01002166 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002167
willy tarreau8a86dbf2005-12-18 00:45:59 +01002168 if (s->cli_addr.ss_family == AF_INET)
2169 inet_ntop(AF_INET,
2170 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2171 pn, sizeof(pn));
2172 else
2173 inet_ntop(AF_INET6,
2174 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2175 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002176
willy tarreauc1cae632005-12-17 14:12:23 +01002177 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002178 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002179 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002180
willy tarreauc1cae632005-12-17 14:12:23 +01002181 tm = localtime(&s->logs.tv_accept.tv_sec);
2182 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002183 char tmpline[MAX_SYSLOG_LEN], *h;
2184 int hdr;
2185
2186 h = tmpline;
2187 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2188 *(h++) = ' ';
2189 *(h++) = '{';
2190 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2191 if (hdr)
2192 *(h++) = '|';
2193 if (s->req_cap[hdr] != NULL)
2194 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2195 }
2196 *(h++) = '}';
2197 }
2198
2199 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2200 *(h++) = ' ';
2201 *(h++) = '{';
2202 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2203 if (hdr)
2204 *(h++) = '|';
2205 if (s->rsp_cap[hdr] != NULL)
2206 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2207 }
2208 *(h++) = '}';
2209 }
2210
2211 if (h < tmpline + sizeof(tmpline) - 4) {
2212 *(h++) = ' ';
2213 *(h++) = '"';
2214 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2215 *(h++) = '"';
2216 }
2217 *h = '\0';
2218
2219 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002220 pn,
2221 (s->cli_addr.ss_family == AF_INET) ?
2222 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2223 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002224 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2225 tm->tm_hour, tm->tm_min, tm->tm_sec,
2226 pxid, srv,
2227 s->logs.t_request,
2228 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2229 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002230 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2231 s->logs.status,
2232 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002233 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2234 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002235 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2236 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2237 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2238 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau4302f492005-12-18 01:00:37 +01002239 tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002240 }
2241 else {
willy tarreau25c4ea52005-12-18 00:49:49 +01002242 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002243 pn,
2244 (s->cli_addr.ss_family == AF_INET) ?
2245 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2246 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002247 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2248 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002249 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002250 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002251 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2252 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002253 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01002254 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01002255 }
2256
2257 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002258}
2259
willy tarreaue39cd132005-12-17 13:00:18 +01002260
2261/*
willy tarreau0f7af912005-12-17 12:21:26 +01002262 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002263 * to an accept. It tries to accept as many connections as possible.
2264 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002265 */
2266int event_accept(int fd) {
2267 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002268 struct session *s;
2269 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002270 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002271
willy tarreau5cbea6f2005-12-17 12:48:26 +01002272 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002273 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002274 int laddr = sizeof(addr);
2275 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2276 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002277
willy tarreau5cbea6f2005-12-17 12:48:26 +01002278 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2279 Alert("out of memory in event_accept().\n");
2280 FD_CLR(fd, StaticReadEvent);
2281 p->state = PR_STIDLE;
2282 close(cfd);
2283 return 0;
2284 }
willy tarreau0f7af912005-12-17 12:21:26 +01002285
willy tarreau5cbea6f2005-12-17 12:48:26 +01002286 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2287 Alert("out of memory in event_accept().\n");
2288 FD_CLR(fd, StaticReadEvent);
2289 p->state = PR_STIDLE;
2290 close(cfd);
2291 pool_free(session, s);
2292 return 0;
2293 }
willy tarreau0f7af912005-12-17 12:21:26 +01002294
willy tarreau5cbea6f2005-12-17 12:48:26 +01002295 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002296 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002297 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2298 close(cfd);
2299 pool_free(task, t);
2300 pool_free(session, s);
2301 return 0;
2302 }
willy tarreau0f7af912005-12-17 12:21:26 +01002303
willy tarreau5cbea6f2005-12-17 12:48:26 +01002304 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2305 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2306 (char *) &one, sizeof(one)) == -1)) {
2307 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2308 close(cfd);
2309 pool_free(task, t);
2310 pool_free(session, s);
2311 return 0;
2312 }
willy tarreau0f7af912005-12-17 12:21:26 +01002313
willy tarreau9fe663a2005-12-17 13:02:59 +01002314 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2315 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2316 t->state = TASK_IDLE;
2317 t->process = process_session;
2318 t->context = s;
2319
2320 s->task = t;
2321 s->proxy = p;
2322 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2323 s->srv_state = SV_STIDLE;
2324 s->req = s->rep = NULL; /* will be allocated later */
2325 s->flags = 0;
willy tarreau97f58572005-12-18 00:53:44 +01002326
willy tarreau9fe663a2005-12-17 13:02:59 +01002327 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2328 s->cli_fd = cfd;
2329 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002330 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002331 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002332
2333 s->logs.logwait = p->to_log;
2334 s->logs.tv_accept = now;
2335 s->logs.t_request = -1;
2336 s->logs.t_connect = -1;
2337 s->logs.t_data = -1;
2338 s->logs.t_close = 0;
2339 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002340 s->logs.cli_cookie = NULL;
2341 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002342 s->logs.status = -1;
2343 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002344
willy tarreau2f6ba652005-12-17 13:57:42 +01002345 s->uniq_id = totalconn;
2346
willy tarreau4302f492005-12-18 01:00:37 +01002347 if (p->nb_req_cap > 0) {
2348 if ((s->req_cap =
2349 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2350 == NULL) { /* no memory */
2351 close(cfd); /* nothing can be done for this fd without memory */
2352 pool_free(task, t);
2353 pool_free(session, s);
2354 return 0;
2355 }
2356 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2357 }
2358 else
2359 s->req_cap = NULL;
2360
2361 if (p->nb_rsp_cap > 0) {
2362 if ((s->rsp_cap =
2363 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2364 == NULL) { /* no memory */
2365 if (s->req_cap != NULL)
2366 pool_free_to(p->req_cap_pool, s->req_cap);
2367 close(cfd); /* nothing can be done for this fd without memory */
2368 pool_free(task, t);
2369 pool_free(session, s);
2370 return 0;
2371 }
2372 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2373 }
2374 else
2375 s->rsp_cap = NULL;
2376
willy tarreau5cbea6f2005-12-17 12:48:26 +01002377 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2378 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002379 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002380 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002381
willy tarreau5cbea6f2005-12-17 12:48:26 +01002382 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002383 if (addr.ss_family != AF_INET ||
2384 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002385 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002386
willy tarreau9fe663a2005-12-17 13:02:59 +01002387 if (p->to_log) {
2388 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002389 if (s->logs.logwait & LW_CLIP)
2390 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002391 sess_log(s);
2392 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002393 else if (s->cli_addr.ss_family == AF_INET) {
2394 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2395 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2396 sn, sizeof(sn)) &&
2397 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2398 pn, sizeof(pn))) {
2399 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2400 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2401 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2402 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2403 }
2404 }
2405 else {
2406 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2407 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2408 sn, sizeof(sn)) &&
2409 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2410 pn, sizeof(pn))) {
2411 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2412 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2413 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2414 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2415 }
2416 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002417 }
willy tarreau0f7af912005-12-17 12:21:26 +01002418
willy tarreau982249e2005-12-18 00:57:06 +01002419 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002420 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002421 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002422 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002423 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002424 if (addr.ss_family != AF_INET ||
2425 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002426 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002427
willy tarreau8a86dbf2005-12-18 00:45:59 +01002428 if (s->cli_addr.ss_family == AF_INET) {
2429 char pn[INET_ADDRSTRLEN];
2430 inet_ntop(AF_INET,
2431 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2432 pn, sizeof(pn));
2433
2434 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2435 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2436 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2437 }
2438 else {
2439 char pn[INET6_ADDRSTRLEN];
2440 inet_ntop(AF_INET6,
2441 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2442 pn, sizeof(pn));
2443
2444 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2445 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2446 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2447 }
2448
willy tarreauef900ab2005-12-17 12:52:52 +01002449 write(1, trash, len);
2450 }
willy tarreau0f7af912005-12-17 12:21:26 +01002451
willy tarreau5cbea6f2005-12-17 12:48:26 +01002452 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002453 if (s->rsp_cap != NULL)
2454 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2455 if (s->req_cap != NULL)
2456 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002457 close(cfd); /* nothing can be done for this fd without memory */
2458 pool_free(task, t);
2459 pool_free(session, s);
2460 return 0;
2461 }
willy tarreau4302f492005-12-18 01:00:37 +01002462
willy tarreau5cbea6f2005-12-17 12:48:26 +01002463 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002464 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002465 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2466 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002467 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002468 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002469
willy tarreau5cbea6f2005-12-17 12:48:26 +01002470 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2471 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002472 if (s->rsp_cap != NULL)
2473 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2474 if (s->req_cap != NULL)
2475 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002476 close(cfd); /* nothing can be done for this fd without memory */
2477 pool_free(task, t);
2478 pool_free(session, s);
2479 return 0;
2480 }
2481 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002482 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002483 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 +01002484
willy tarreau5cbea6f2005-12-17 12:48:26 +01002485 fdtab[cfd].read = &event_cli_read;
2486 fdtab[cfd].write = &event_cli_write;
2487 fdtab[cfd].owner = t;
2488 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002489
willy tarreau5cbea6f2005-12-17 12:48:26 +01002490 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002491 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2492 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2493 else
2494 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002495 }
2496 else {
2497 FD_SET(cfd, StaticReadEvent);
2498 }
2499
2500 fd_insert(cfd);
2501
2502 tv_eternity(&s->cnexpire);
2503 tv_eternity(&s->srexpire);
2504 tv_eternity(&s->swexpire);
2505 tv_eternity(&s->cwexpire);
2506
2507 if (s->proxy->clitimeout)
2508 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2509 else
2510 tv_eternity(&s->crexpire);
2511
2512 t->expire = s->crexpire;
2513
2514 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002515
2516 if (p->mode != PR_MODE_HEALTH)
2517 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002518
2519 p->nbconn++;
2520 actconn++;
2521 totalconn++;
2522
2523 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2524 } /* end of while (p->nbconn < p->maxconn) */
2525 return 0;
2526}
willy tarreau0f7af912005-12-17 12:21:26 +01002527
willy tarreau0f7af912005-12-17 12:21:26 +01002528
willy tarreau5cbea6f2005-12-17 12:48:26 +01002529/*
2530 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002531 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2532 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002533 * or -1 if an error occured.
2534 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002535int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002536 struct task *t = fdtab[fd].owner;
2537 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002538
willy tarreau5cbea6f2005-12-17 12:48:26 +01002539 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002540 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002541 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002542 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002543 if (skerr)
2544 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002545 else {
2546 if (s->proxy->options & PR_O_HTTP_CHK) {
2547 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002548 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002549 * so we'll send the request, and won't wake the checker up now.
2550 */
2551#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002552 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002553#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002554 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002555#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002556 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002557 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2558 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2559 return 0;
2560 }
2561 else
2562 s->result = -1;
2563 }
2564 else {
2565 /* good TCP connection is enough */
2566 s->result = 1;
2567 }
2568 }
2569
2570 task_wakeup(&rq, t);
2571 return 0;
2572}
2573
willy tarreau0f7af912005-12-17 12:21:26 +01002574
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002575/*
2576 * This function is used only for server health-checks. It handles
2577 * the server's reply to an HTTP request. It returns 1 if the server replies
2578 * 2xx or 3xx (valid responses), or -1 in other cases.
2579 */
2580int event_srv_chk_r(int fd) {
2581 char reply[64];
2582 int len;
2583 struct task *t = fdtab[fd].owner;
2584 struct server *s = t->context;
2585
2586 int skerr, lskerr;
2587 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002588
2589 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002590#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002591 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2592 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002593 len = recv(fd, reply, sizeof(reply), 0);
2594#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002595 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2596 * but the connection was closed on the remote end. Fortunately, recv still
2597 * works correctly and we don't need to do the getsockopt() on linux.
2598 */
2599 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002600#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002601 if ((len >= sizeof("HTTP/1.0 000")) &&
2602 !memcmp(reply, "HTTP/1.", 7) &&
2603 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2604 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002605
2606 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002607 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002608 return 0;
2609}
2610
2611
2612/*
2613 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2614 * and moves <end> just after the end of <str>.
2615 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2616 * the shift value (positive or negative) is returned.
2617 * If there's no space left, the move is not done.
2618 *
2619 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002620int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002621 int delta;
2622 int len;
2623
2624 len = strlen(str);
2625 delta = len - (end - pos);
2626
2627 if (delta + b->r >= b->data + BUFSIZE)
2628 return 0; /* no space left */
2629
2630 /* first, protect the end of the buffer */
2631 memmove(end + delta, end, b->data + b->l - end);
2632
2633 /* now, copy str over pos */
2634 memcpy(pos, str,len);
2635
willy tarreau5cbea6f2005-12-17 12:48:26 +01002636 /* we only move data after the displaced zone */
2637 if (b->r > pos) b->r += delta;
2638 if (b->w > pos) b->w += delta;
2639 if (b->h > pos) b->h += delta;
2640 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002641 b->l += delta;
2642
2643 return delta;
2644}
2645
willy tarreau8337c6b2005-12-17 13:41:01 +01002646/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002647 * len is 0.
2648 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002649int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002650 int delta;
2651
2652 delta = len - (end - pos);
2653
2654 if (delta + b->r >= b->data + BUFSIZE)
2655 return 0; /* no space left */
2656
2657 /* first, protect the end of the buffer */
2658 memmove(end + delta, end, b->data + b->l - end);
2659
2660 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002661 if (len)
2662 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002663
willy tarreau5cbea6f2005-12-17 12:48:26 +01002664 /* we only move data after the displaced zone */
2665 if (b->r > pos) b->r += delta;
2666 if (b->w > pos) b->w += delta;
2667 if (b->h > pos) b->h += delta;
2668 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002669 b->l += delta;
2670
2671 return delta;
2672}
2673
2674
2675int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2676 char *old_dst = dst;
2677
2678 while (*str) {
2679 if (*str == '\\') {
2680 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002681 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002682 int len, num;
2683
2684 num = *str - '0';
2685 str++;
2686
willy tarreau8a86dbf2005-12-18 00:45:59 +01002687 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002688 len = matches[num].rm_eo - matches[num].rm_so;
2689 memcpy(dst, src + matches[num].rm_so, len);
2690 dst += len;
2691 }
2692
2693 }
2694 else if (*str == 'x') {
2695 unsigned char hex1, hex2;
2696 str++;
2697
2698 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
2699
2700 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2701 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2702 *dst++ = (hex1<<4) + hex2;
2703 }
2704 else
2705 *dst++ = *str++;
2706 }
2707 else
2708 *dst++ = *str++;
2709 }
2710 *dst = 0;
2711 return dst - old_dst;
2712}
2713
willy tarreau9fe663a2005-12-17 13:02:59 +01002714
willy tarreau0f7af912005-12-17 12:21:26 +01002715/*
2716 * manages the client FSM and its socket. BTW, it also tries to handle the
2717 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2718 * 0 else.
2719 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002720int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002721 int s = t->srv_state;
2722 int c = t->cli_state;
2723 struct buffer *req = t->req;
2724 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01002725 int method_checked = 0;
2726 appsess *asession_temp = NULL;
2727 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01002728
willy tarreau750a4722005-12-17 13:21:24 +01002729#ifdef DEBUG_FULL
2730 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2731#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002732 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2733 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2734 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2735 //);
2736 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002737 /* now parse the partial (or complete) headers */
2738 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2739 char *ptr;
2740 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01002741 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01002742
willy tarreau5cbea6f2005-12-17 12:48:26 +01002743 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002744
willy tarreau0f7af912005-12-17 12:21:26 +01002745 /* look for the end of the current header */
2746 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2747 ptr++;
2748
willy tarreau5cbea6f2005-12-17 12:48:26 +01002749 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002750 int line, len;
2751 /* we can only get here after an end of headers */
2752 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002753
willy tarreaue39cd132005-12-17 13:00:18 +01002754 if (t->flags & SN_CLDENY) {
2755 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002756 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002757 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002758 if (!(t->flags & SN_ERR_MASK))
2759 t->flags |= SN_ERR_PRXCOND;
2760 if (!(t->flags & SN_FINST_MASK))
2761 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002762 return 1;
2763 }
2764
willy tarreau5cbea6f2005-12-17 12:48:26 +01002765 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002766 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2767 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002768 }
willy tarreau0f7af912005-12-17 12:21:26 +01002769
willy tarreau9fe663a2005-12-17 13:02:59 +01002770 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002771 if (t->cli_addr.ss_family == AF_INET) {
2772 unsigned char *pn;
2773 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
2774 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2775 pn[0], pn[1], pn[2], pn[3]);
2776 buffer_replace2(req, req->h, req->h, trash, len);
2777 }
2778 else if (t->cli_addr.ss_family == AF_INET6) {
2779 char pn[INET6_ADDRSTRLEN];
2780 inet_ntop(AF_INET6,
2781 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2782 pn, sizeof(pn));
2783 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
2784 buffer_replace2(req, req->h, req->h, trash, len);
2785 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002786 }
2787
willy tarreau25c4ea52005-12-18 00:49:49 +01002788 /* add a "connection: close" line if needed */
2789 if (t->proxy->options & PR_O_HTTP_CLOSE)
2790 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
2791
willy tarreau982249e2005-12-18 00:57:06 +01002792 if (!memcmp(req->data, "POST ", 5)) {
2793 /* this is a POST request, which is not cacheable by default */
2794 t->flags |= SN_POST;
2795 }
willy tarreaucd878942005-12-17 13:27:43 +01002796
willy tarreau5cbea6f2005-12-17 12:48:26 +01002797 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002798 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002799
willy tarreau750a4722005-12-17 13:21:24 +01002800 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002801 /* FIXME: we'll set the client in a wait state while we try to
2802 * connect to the server. Is this really needed ? wouldn't it be
2803 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002804 //FD_CLR(t->cli_fd, StaticReadEvent);
2805 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002806
2807 /* FIXME: if we break here (as up to 1.1.23), having the client
2808 * shutdown its connection can lead to an abort further.
2809 * it's better to either return 1 or even jump directly to the
2810 * data state which will save one schedule.
2811 */
2812 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002813
2814 if (!t->proxy->clitimeout ||
2815 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2816 /* If the client has no timeout, or if the server is not ready yet,
2817 * and we know for sure that it can expire, then it's cleaner to
2818 * disable the timeout on the client side so that too low values
2819 * cannot make the sessions abort too early.
2820 */
2821 tv_eternity(&t->crexpire);
2822
willy tarreau197e8ec2005-12-17 14:10:59 +01002823 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002824 }
willy tarreau0f7af912005-12-17 12:21:26 +01002825
willy tarreau5cbea6f2005-12-17 12:48:26 +01002826 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2827 if (ptr > req->r - 2) {
2828 /* this is a partial header, let's wait for more to come */
2829 req->lr = ptr;
2830 break;
2831 }
willy tarreau0f7af912005-12-17 12:21:26 +01002832
willy tarreau5cbea6f2005-12-17 12:48:26 +01002833 /* now we know that *ptr is either \r or \n,
2834 * and that there are at least 1 char after it.
2835 */
2836 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2837 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2838 else
2839 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002840
willy tarreau5cbea6f2005-12-17 12:48:26 +01002841 /*
2842 * now we know that we have a full header ; we can do whatever
2843 * we want with these pointers :
2844 * req->h = beginning of header
2845 * ptr = end of header (first \r or \n)
2846 * req->lr = beginning of next line (next rep->h)
2847 * req->r = end of data (not used at this stage)
2848 */
willy tarreau0f7af912005-12-17 12:21:26 +01002849
willy tarreau12350152005-12-18 01:03:27 +01002850 if (!method_checked && (t->proxy->appsession_name != NULL) &&
2851 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
2852 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
2853
2854 /* skip ; */
2855 request_line++;
2856
2857 /* look if we have a jsessionid */
2858
2859 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
2860
2861 /* skip jsessionid= */
2862 request_line += t->proxy->appsession_name_len + 1;
2863
2864 /* First try if we allready have an appsession */
2865 asession_temp = &local_asession;
2866
2867 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2868 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
2869 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
2870 return 0;
2871 }
2872
2873 /* Copy the sessionid */
2874 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
2875 asession_temp->sessid[t->proxy->appsession_len] = 0;
2876 asession_temp->serverid = NULL;
2877
2878 /* only do insert, if lookup fails */
2879 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
2880 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2881 Alert("Not enough memory process_cli():asession:calloc().\n");
2882 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
2883 return 0;
2884 }
2885 asession_temp->sessid = local_asession.sessid;
2886 asession_temp->serverid = local_asession.serverid;
2887 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
2888 } /* end if(chtbl_lookup()) */
2889 else{
2890 /*free wasted memory;*/
2891 pool_free_to(apools.sessid, local_asession.sessid);
2892 }
2893
2894 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
2895 asession_temp->request_count++;
2896
2897#if defined(DEBUG_HASH)
2898 print_table(&(t->proxy->htbl_proxy));
2899#endif
2900
2901 if (asession_temp->serverid == NULL) {
2902 Alert("Found Application Session without matching server.\n");
2903 } else {
2904 struct server *srv = t->proxy->srv;
2905 while (srv) {
2906 if (strcmp(srv->id, asession_temp->serverid) == 0) {
2907 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
2908 /* we found the server and it's usable */
2909 t->flags &= ~SN_CK_MASK;
2910 t->flags |= SN_CK_VALID | SN_DIRECT;
2911 t->srv = srv;
2912 break;
2913 }else {
2914 t->flags &= ~SN_CK_MASK;
2915 t->flags |= SN_CK_DOWN;
2916 }
2917 }/* end if(strcmp()) */
2918 srv = srv->next;
2919 }/* end while(srv) */
2920 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreau12350152005-12-18 01:03:27 +01002921 }/* end if(strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
2922 else {
2923 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
2924 }
willy tarreau598da412005-12-18 01:07:29 +01002925 method_checked = 1;
willy tarreau12350152005-12-18 01:03:27 +01002926 }/* end if(!method_checked ...) */
2927 else{
2928 //printf("No Methode-Header with Session-String\n");
2929 }
2930
willy tarreau8337c6b2005-12-17 13:41:01 +01002931 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002932 /* we have a complete HTTP request that we must log */
2933 int urilen;
2934
willy tarreaua1598082005-12-17 13:08:06 +01002935 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01002936 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01002937 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01002938 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01002939 if (!(t->flags & SN_ERR_MASK))
2940 t->flags |= SN_ERR_PRXCOND;
2941 if (!(t->flags & SN_FINST_MASK))
2942 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01002943 return 1;
2944 }
2945
2946 urilen = ptr - req->h;
2947 if (urilen >= REQURI_LEN)
2948 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01002949 memcpy(t->logs.uri, req->h, urilen);
2950 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002951
willy tarreaua1598082005-12-17 13:08:06 +01002952 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01002953 sess_log(t);
2954 }
willy tarreau4302f492005-12-18 01:00:37 +01002955 else if (t->logs.logwait & LW_REQHDR) {
2956 struct cap_hdr *h;
2957 int len;
2958 for (h = t->proxy->req_cap; h; h = h->next) {
2959 if ((h->namelen + 2 <= ptr - req->h) &&
2960 (req->h[h->namelen] == ':') &&
2961 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
2962
2963 if (t->req_cap[h->index] == NULL)
2964 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
2965
2966 len = ptr - (req->h + h->namelen + 2);
2967 if (len > h->len)
2968 len = h->len;
2969
2970 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
2971 t->req_cap[h->index][len]=0;
2972 }
2973 }
2974
2975 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002976
willy tarreau5cbea6f2005-12-17 12:48:26 +01002977 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002978
willy tarreau982249e2005-12-18 00:57:06 +01002979 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002980 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01002981 len = sprintf(trash, "%08x:%s.clihdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002982 max = ptr - req->h;
2983 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01002984 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002985 trash[len++] = '\n';
2986 write(1, trash, len);
2987 }
willy tarreau0f7af912005-12-17 12:21:26 +01002988
willy tarreau25c4ea52005-12-18 00:49:49 +01002989
2990 /* remove "connection: " if needed */
2991 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
2992 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
2993 delete_header = 1;
2994 }
2995
willy tarreau5cbea6f2005-12-17 12:48:26 +01002996 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01002997 if (!delete_header && t->proxy->req_exp != NULL
2998 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01002999 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003000 char term;
3001
3002 term = *ptr;
3003 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003004 exp = t->proxy->req_exp;
3005 do {
3006 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3007 switch (exp->action) {
3008 case ACT_ALLOW:
3009 if (!(t->flags & SN_CLDENY))
3010 t->flags |= SN_CLALLOW;
3011 break;
3012 case ACT_REPLACE:
3013 if (!(t->flags & SN_CLDENY)) {
3014 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3015 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3016 }
3017 break;
3018 case ACT_REMOVE:
3019 if (!(t->flags & SN_CLDENY))
3020 delete_header = 1;
3021 break;
3022 case ACT_DENY:
3023 if (!(t->flags & SN_CLALLOW))
3024 t->flags |= SN_CLDENY;
3025 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003026 case ACT_PASS: /* we simply don't deny this one */
3027 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003028 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003029 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003030 }
willy tarreaue39cd132005-12-17 13:00:18 +01003031 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003032 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003033 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003034
willy tarreau240afa62005-12-17 13:14:35 +01003035 /* Now look for cookies. Conforming to RFC2109, we have to support
3036 * attributes whose name begin with a '$', and associate them with
3037 * the right cookie, if we want to delete this cookie.
3038 * So there are 3 cases for each cookie read :
3039 * 1) it's a special attribute, beginning with a '$' : ignore it.
3040 * 2) it's a server id cookie that we *MAY* want to delete : save
3041 * some pointers on it (last semi-colon, beginning of cookie...)
3042 * 3) it's an application cookie : we *MAY* have to delete a previous
3043 * "special" cookie.
3044 * At the end of loop, if a "special" cookie remains, we may have to
3045 * remove it. If no application cookie persists in the header, we
3046 * *MUST* delete it
3047 */
willy tarreau12350152005-12-18 01:03:27 +01003048 if (!delete_header &&
3049 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003050 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003051 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003052 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003053 char *del_colon, *del_cookie, *colon;
3054 int app_cookies;
3055
willy tarreau5cbea6f2005-12-17 12:48:26 +01003056 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003057 colon = p1;
3058 /* del_cookie == NULL => nothing to be deleted */
3059 del_colon = del_cookie = NULL;
3060 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003061
3062 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003063 /* skip spaces and colons, but keep an eye on these ones */
3064 while (p1 < ptr) {
3065 if (*p1 == ';' || *p1 == ',')
3066 colon = p1;
3067 else if (!isspace((int)*p1))
3068 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003069 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003070 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003071
3072 if (p1 == ptr)
3073 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003074
3075 /* p1 is at the beginning of the cookie name */
3076 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003077 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003078 p2++;
3079
3080 if (p2 == ptr)
3081 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003082
3083 p3 = p2 + 1; /* skips the '=' sign */
3084 if (p3 == ptr)
3085 break;
3086
willy tarreau240afa62005-12-17 13:14:35 +01003087 p4 = p3;
3088 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003089 p4++;
3090
3091 /* here, we have the cookie name between p1 and p2,
3092 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003093 * we can process it :
3094 *
3095 * Cookie: NAME=VALUE;
3096 * | || || |
3097 * | || || +--> p4
3098 * | || |+-------> p3
3099 * | || +--------> p2
3100 * | |+------------> p1
3101 * | +-------------> colon
3102 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103 */
3104
willy tarreau240afa62005-12-17 13:14:35 +01003105 if (*p1 == '$') {
3106 /* skip this one */
3107 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003108 else {
3109 /* first, let's see if we want to capture it */
3110 if (t->proxy->capture_name != NULL &&
3111 t->logs.cli_cookie == NULL &&
3112 (p4 - p1 >= t->proxy->capture_namelen) &&
3113 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3114 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003115
willy tarreau8337c6b2005-12-17 13:41:01 +01003116 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3117 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003118 } else {
3119 if (log_len > t->proxy->capture_len)
3120 log_len = t->proxy->capture_len;
3121 memcpy(t->logs.cli_cookie, p1, log_len);
3122 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003123 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003124 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003125
3126 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3127 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3128 /* Cool... it's the right one */
3129 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003130 char *delim;
3131
3132 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3133 * have the server ID betweek p3 and delim, and the original cookie between
3134 * delim+1 and p4. Otherwise, delim==p4 :
3135 *
3136 * Cookie: NAME=SRV~VALUE;
3137 * | || || | |
3138 * | || || | +--> p4
3139 * | || || +--------> delim
3140 * | || |+-----------> p3
3141 * | || +------------> p2
3142 * | |+----------------> p1
3143 * | +-----------------> colon
3144 * +------------------------> req->h
3145 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003146
willy tarreau0174f312005-12-18 01:02:42 +01003147 if (t->proxy->options & PR_O_COOK_PFX) {
3148 for (delim = p3; delim < p4; delim++)
3149 if (*delim == COOKIE_DELIM)
3150 break;
3151 }
3152 else
3153 delim = p4;
3154
3155
3156 /* Here, we'll look for the first running server which supports the cookie.
3157 * This allows to share a same cookie between several servers, for example
3158 * to dedicate backup servers to specific servers only.
3159 */
3160 while (srv) {
3161 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3162 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3163 /* we found the server and it's usable */
3164 t->flags &= ~SN_CK_MASK;
3165 t->flags |= SN_CK_VALID | SN_DIRECT;
3166 t->srv = srv;
3167 break;
willy tarreau12350152005-12-18 01:03:27 +01003168 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003169 /* we found a server, but it's down */
3170 t->flags &= ~SN_CK_MASK;
3171 t->flags |= SN_CK_DOWN;
3172 }
3173 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003174 srv = srv->next;
3175 }
3176
willy tarreau0174f312005-12-18 01:02:42 +01003177 if (!srv && !(t->flags & SN_CK_DOWN)) {
3178 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003179 t->flags &= ~SN_CK_MASK;
3180 t->flags |= SN_CK_INVALID;
3181 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003182
willy tarreau0174f312005-12-18 01:02:42 +01003183 /* depending on the cookie mode, we may have to either :
3184 * - delete the complete cookie if we're in insert+indirect mode, so that
3185 * the server never sees it ;
3186 * - remove the server id from the cookie value, and tag the cookie as an
3187 * application cookie so that it does not get accidentely removed later,
3188 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003189 */
willy tarreau0174f312005-12-18 01:02:42 +01003190 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3191 buffer_replace2(req, p3, delim + 1, NULL, 0);
3192 p4 -= (delim + 1 - p3);
3193 ptr -= (delim + 1 - p3);
3194 del_cookie = del_colon = NULL;
3195 app_cookies++; /* protect the header from deletion */
3196 }
3197 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003198 (t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
willy tarreau240afa62005-12-17 13:14:35 +01003199 del_cookie = p1;
3200 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003201 }
willy tarreau12350152005-12-18 01:03:27 +01003202 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003203 /* now we know that we must keep this cookie since it's
3204 * not ours. But if we wanted to delete our cookie
3205 * earlier, we cannot remove the complete header, but we
3206 * can remove the previous block itself.
3207 */
3208 app_cookies++;
3209
3210 if (del_cookie != NULL) {
3211 buffer_replace2(req, del_cookie, p1, NULL, 0);
3212 p4 -= (p1 - del_cookie);
3213 ptr -= (p1 - del_cookie);
3214 del_cookie = del_colon = NULL;
3215 }
willy tarreau240afa62005-12-17 13:14:35 +01003216 }
willy tarreau12350152005-12-18 01:03:27 +01003217
3218 if ((t->proxy->appsession_name != NULL) &&
3219 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3220 /* first, let's see if the cookie is our appcookie*/
3221
3222 /* Cool... it's the right one */
3223
3224 asession_temp = &local_asession;
3225
3226 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3227 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3228 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3229 return 0;
3230 }
3231
3232 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3233 asession_temp->sessid[t->proxy->appsession_len] = 0;
3234 asession_temp->serverid = NULL;
3235
3236 /* only do insert, if lookup fails */
3237 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3238 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3239 Alert("Not enough memory process_cli():asession:calloc().\n");
3240 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3241 return 0;
3242 }
3243
3244 asession_temp->sessid = local_asession.sessid;
3245 asession_temp->serverid = local_asession.serverid;
3246 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3247 }
3248 else{
3249 /* free wasted memory */
3250 pool_free_to(apools.sessid, local_asession.sessid);
3251 }
3252
3253 if (asession_temp->serverid == NULL) {
3254 Alert("Found Application Session without matching server.\n");
3255 } else {
3256 struct server *srv = t->proxy->srv;
3257 while (srv) {
3258 if(strcmp(srv->id, asession_temp->serverid) == 0) {
3259 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3260 /* we found the server and it's usable */
3261 t->flags &= ~SN_CK_MASK;
3262 t->flags |= SN_CK_VALID | SN_DIRECT;
3263 t->srv = srv;
3264 break;
3265 } else {
3266 t->flags &= ~SN_CK_MASK;
3267 t->flags |= SN_CK_DOWN;
3268 }
3269 }
3270 srv = srv->next;
3271 }/* end while(srv) */
3272 }/* end else if server == NULL */
3273
3274 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003275 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003276 }
willy tarreau240afa62005-12-17 13:14:35 +01003277
willy tarreau5cbea6f2005-12-17 12:48:26 +01003278 /* we'll have to look for another cookie ... */
3279 p1 = p4;
3280 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003281
3282 /* There's no more cookie on this line.
3283 * We may have marked the last one(s) for deletion.
3284 * We must do this now in two ways :
3285 * - if there is no app cookie, we simply delete the header ;
3286 * - if there are app cookies, we must delete the end of the
3287 * string properly, including the colon/semi-colon before
3288 * the cookie name.
3289 */
3290 if (del_cookie != NULL) {
3291 if (app_cookies) {
3292 buffer_replace2(req, del_colon, ptr, NULL, 0);
3293 /* WARNING! <ptr> becomes invalid for now. If some code
3294 * below needs to rely on it before the end of the global
3295 * header loop, we need to correct it with this code :
3296 * ptr = del_colon;
3297 */
3298 }
3299 else
3300 delete_header = 1;
3301 }
3302 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003303
3304 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003305 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003306 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003307 }
willy tarreau240afa62005-12-17 13:14:35 +01003308 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3309
willy tarreau5cbea6f2005-12-17 12:48:26 +01003310 req->h = req->lr;
3311 } /* while (req->lr < req->r) */
3312
3313 /* end of header processing (even if incomplete) */
3314
willy tarreauef900ab2005-12-17 12:52:52 +01003315 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3316 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3317 * full. We cannot loop here since event_cli_read will disable it only if
3318 * req->l == rlim-data
3319 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003320 FD_SET(t->cli_fd, StaticReadEvent);
3321 if (t->proxy->clitimeout)
3322 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3323 else
3324 tv_eternity(&t->crexpire);
3325 }
3326
willy tarreaue39cd132005-12-17 13:00:18 +01003327 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003328 * won't be able to free more later, so the session will never terminate.
3329 */
willy tarreaue39cd132005-12-17 13:00:18 +01003330 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003331 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003332 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003333 if (!(t->flags & SN_ERR_MASK))
3334 t->flags |= SN_ERR_PRXCOND;
3335 if (!(t->flags & SN_FINST_MASK))
3336 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003337 return 1;
3338 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003339 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003340 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003341 tv_eternity(&t->crexpire);
3342 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003343 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003344 if (!(t->flags & SN_ERR_MASK))
3345 t->flags |= SN_ERR_CLICL;
3346 if (!(t->flags & SN_FINST_MASK))
3347 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003348 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003349 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003350 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3351
3352 /* read timeout : give up with an error message.
3353 */
3354 t->logs.status = 408;
3355 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003356 if (!(t->flags & SN_ERR_MASK))
3357 t->flags |= SN_ERR_CLITO;
3358 if (!(t->flags & SN_FINST_MASK))
3359 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003360 return 1;
3361 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003362
3363 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003364 }
3365 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003366 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003367 /* FIXME: this error handling is partly buggy because we always report
3368 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3369 * or HEADER phase. BTW, it's not logical to expire the client while
3370 * we're waiting for the server to connect.
3371 */
willy tarreau0f7af912005-12-17 12:21:26 +01003372 /* read or write error */
3373 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003374 tv_eternity(&t->crexpire);
3375 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003376 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003377 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003378 if (!(t->flags & SN_ERR_MASK))
3379 t->flags |= SN_ERR_CLICL;
3380 if (!(t->flags & SN_FINST_MASK))
3381 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003382 return 1;
3383 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003384 /* last read, or end of server write */
3385 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003386 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003387 tv_eternity(&t->crexpire);
3388 shutdown(t->cli_fd, SHUT_RD);
3389 t->cli_state = CL_STSHUTR;
3390 return 1;
3391 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003392 /* last server read and buffer empty */
3393 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003394 FD_CLR(t->cli_fd, StaticWriteEvent);
3395 tv_eternity(&t->cwexpire);
3396 shutdown(t->cli_fd, SHUT_WR);
3397 t->cli_state = CL_STSHUTW;
3398 return 1;
3399 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003400 /* read timeout */
3401 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3402 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003403 tv_eternity(&t->crexpire);
3404 shutdown(t->cli_fd, SHUT_RD);
3405 t->cli_state = CL_STSHUTR;
3406 if (!(t->flags & SN_ERR_MASK))
3407 t->flags |= SN_ERR_CLITO;
3408 if (!(t->flags & SN_FINST_MASK))
3409 t->flags |= SN_FINST_D;
3410 return 1;
3411 }
3412 /* write timeout */
3413 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3414 FD_CLR(t->cli_fd, StaticWriteEvent);
3415 tv_eternity(&t->cwexpire);
3416 shutdown(t->cli_fd, SHUT_WR);
3417 t->cli_state = CL_STSHUTW;
3418 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003419 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003420 if (!(t->flags & SN_FINST_MASK))
3421 t->flags |= SN_FINST_D;
3422 return 1;
3423 }
willy tarreau0f7af912005-12-17 12:21:26 +01003424
willy tarreauc58fc692005-12-17 14:13:08 +01003425 if (req->l >= req->rlim - req->data) {
3426 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003427 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003428 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003429 FD_CLR(t->cli_fd, StaticReadEvent);
3430 tv_eternity(&t->crexpire);
3431 }
3432 }
3433 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003434 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003435 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3436 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003437 if (!t->proxy->clitimeout ||
3438 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3439 /* If the client has no timeout, or if the server not ready yet, and we
3440 * know for sure that it can expire, then it's cleaner to disable the
3441 * timeout on the client side so that too low values cannot make the
3442 * sessions abort too early.
3443 */
willy tarreau0f7af912005-12-17 12:21:26 +01003444 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003445 else
3446 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003447 }
3448 }
3449
3450 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003451 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003452 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3453 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3454 tv_eternity(&t->cwexpire);
3455 }
3456 }
3457 else { /* buffer not empty */
3458 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3459 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003460 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003461 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003462 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3463 t->crexpire = t->cwexpire;
3464 }
willy tarreau0f7af912005-12-17 12:21:26 +01003465 else
3466 tv_eternity(&t->cwexpire);
3467 }
3468 }
3469 return 0; /* other cases change nothing */
3470 }
3471 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003472 if (t->res_cw == RES_ERROR) {
3473 tv_eternity(&t->cwexpire);
3474 fd_delete(t->cli_fd);
3475 t->cli_state = CL_STCLOSE;
3476 if (!(t->flags & SN_ERR_MASK))
3477 t->flags |= SN_ERR_CLICL;
3478 if (!(t->flags & SN_FINST_MASK))
3479 t->flags |= SN_FINST_D;
3480 return 1;
3481 }
3482 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003483 tv_eternity(&t->cwexpire);
3484 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003485 t->cli_state = CL_STCLOSE;
3486 return 1;
3487 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003488 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3489 tv_eternity(&t->cwexpire);
3490 fd_delete(t->cli_fd);
3491 t->cli_state = CL_STCLOSE;
3492 if (!(t->flags & SN_ERR_MASK))
3493 t->flags |= SN_ERR_CLITO;
3494 if (!(t->flags & SN_FINST_MASK))
3495 t->flags |= SN_FINST_D;
3496 return 1;
3497 }
willy tarreau0f7af912005-12-17 12:21:26 +01003498 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003499 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003500 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3501 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3502 tv_eternity(&t->cwexpire);
3503 }
3504 }
3505 else { /* buffer not empty */
3506 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3507 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003508 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003509 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003510 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3511 t->crexpire = t->cwexpire;
3512 }
willy tarreau0f7af912005-12-17 12:21:26 +01003513 else
3514 tv_eternity(&t->cwexpire);
3515 }
3516 }
3517 return 0;
3518 }
3519 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003520 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003521 tv_eternity(&t->crexpire);
3522 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003523 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003524 if (!(t->flags & SN_ERR_MASK))
3525 t->flags |= SN_ERR_CLICL;
3526 if (!(t->flags & SN_FINST_MASK))
3527 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003528 return 1;
3529 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003530 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3531 tv_eternity(&t->crexpire);
3532 fd_delete(t->cli_fd);
3533 t->cli_state = CL_STCLOSE;
3534 return 1;
3535 }
3536 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3537 tv_eternity(&t->crexpire);
3538 fd_delete(t->cli_fd);
3539 t->cli_state = CL_STCLOSE;
3540 if (!(t->flags & SN_ERR_MASK))
3541 t->flags |= SN_ERR_CLITO;
3542 if (!(t->flags & SN_FINST_MASK))
3543 t->flags |= SN_FINST_D;
3544 return 1;
3545 }
willy tarreauef900ab2005-12-17 12:52:52 +01003546 else if (req->l >= req->rlim - req->data) {
3547 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003548 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003549 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003550 FD_CLR(t->cli_fd, StaticReadEvent);
3551 tv_eternity(&t->crexpire);
3552 }
3553 }
3554 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003555 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003556 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3557 FD_SET(t->cli_fd, StaticReadEvent);
3558 if (t->proxy->clitimeout)
3559 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3560 else
3561 tv_eternity(&t->crexpire);
3562 }
3563 }
3564 return 0;
3565 }
3566 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003567 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003568 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003569 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003570 write(1, trash, len);
3571 }
3572 return 0;
3573 }
3574 return 0;
3575}
3576
3577
3578/*
3579 * manages the server FSM and its socket. It returns 1 if a state has changed
3580 * (and a resync may be needed), 0 else.
3581 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003582int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003583 int s = t->srv_state;
3584 int c = t->cli_state;
3585 struct buffer *req = t->req;
3586 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003587 appsess *asession_temp = NULL;
3588 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003589
willy tarreau750a4722005-12-17 13:21:24 +01003590#ifdef DEBUG_FULL
3591 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3592#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003593 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3594 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3595 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3596 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003597 if (s == SV_STIDLE) {
3598 if (c == CL_STHEADERS)
3599 return 0; /* stay in idle, waiting for data to reach the client side */
3600 else if (c == CL_STCLOSE ||
3601 c == CL_STSHUTW ||
3602 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3603 tv_eternity(&t->cnexpire);
3604 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003605 if (!(t->flags & SN_ERR_MASK))
3606 t->flags |= SN_ERR_CLICL;
3607 if (!(t->flags & SN_FINST_MASK))
3608 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003609 return 1;
3610 }
3611 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003612 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003613 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3614 t->srv_state = SV_STCONN;
3615 }
3616 else { /* try again */
3617 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003618 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003619 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003620 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003621 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3622 t->flags &= ~SN_CK_MASK;
3623 t->flags |= SN_CK_DOWN;
3624 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003625 }
3626
3627 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003628 t->srv_state = SV_STCONN;
3629 break;
3630 }
3631 }
3632 if (t->conn_retries < 0) {
3633 /* if conn_retries < 0 or other error, let's abort */
3634 tv_eternity(&t->cnexpire);
3635 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003636 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003637 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003638 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003639 if (!(t->flags & SN_ERR_MASK))
3640 t->flags |= SN_ERR_SRVCL;
3641 if (!(t->flags & SN_FINST_MASK))
3642 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003643 }
3644 }
3645 return 1;
3646 }
3647 }
3648 else if (s == SV_STCONN) { /* connection in progress */
3649 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3650 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3651 return 0; /* nothing changed */
3652 }
3653 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3654 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3655 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003656 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003657 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003658 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003659 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003660 if (t->conn_retries >= 0) {
3661 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003662 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003663 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003664 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3665 t->flags &= ~SN_CK_MASK;
3666 t->flags |= SN_CK_DOWN;
3667 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003668 }
3669 if (connect_server(t) == 0)
3670 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003671 }
3672 /* if conn_retries < 0 or other error, let's abort */
3673 tv_eternity(&t->cnexpire);
3674 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003675 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003676 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003677 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003678 if (!(t->flags & SN_ERR_MASK))
3679 t->flags |= SN_ERR_SRVCL;
3680 if (!(t->flags & SN_FINST_MASK))
3681 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003682 return 1;
3683 }
3684 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003685 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003686
willy tarreau0f7af912005-12-17 12:21:26 +01003687 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003688 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003689 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003690 tv_eternity(&t->swexpire);
3691 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003692 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003693 if (t->proxy->srvtimeout) {
3694 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3695 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3696 t->srexpire = t->swexpire;
3697 }
3698 else
3699 tv_eternity(&t->swexpire);
3700 }
willy tarreau0f7af912005-12-17 12:21:26 +01003701
3702 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3703 FD_SET(t->srv_fd, StaticReadEvent);
3704 if (t->proxy->srvtimeout)
3705 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3706 else
3707 tv_eternity(&t->srexpire);
3708
3709 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003710 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01003711
3712 /* if the user wants to log as soon as possible, without counting
3713 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003714 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003715 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
3716 sess_log(t);
3717 }
willy tarreau0f7af912005-12-17 12:21:26 +01003718 }
willy tarreauef900ab2005-12-17 12:52:52 +01003719 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003720 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003721 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3722 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003723 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003724 return 1;
3725 }
3726 }
3727 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003728 /* now parse the partial (or complete) headers */
3729 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3730 char *ptr;
3731 int delete_header;
3732
3733 ptr = rep->lr;
3734
3735 /* look for the end of the current header */
3736 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3737 ptr++;
3738
3739 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003740 int line, len;
3741
3742 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01003743
3744 /* first, we'll block if security checks have caught nasty things */
3745 if (t->flags & SN_CACHEABLE) {
3746 if ((t->flags & SN_CACHE_COOK) &&
3747 (t->flags & SN_SCK_ANY) &&
3748 (t->proxy->options & PR_O_CHK_CACHE)) {
3749
3750 /* we're in presence of a cacheable response containing
3751 * a set-cookie header. We'll block it as requested by
3752 * the 'checkcache' option, and send an alert.
3753 */
3754 tv_eternity(&t->srexpire);
3755 tv_eternity(&t->swexpire);
3756 fd_delete(t->srv_fd);
3757 t->srv_state = SV_STCLOSE;
3758 t->logs.status = 502;
3759 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3760 if (!(t->flags & SN_ERR_MASK))
3761 t->flags |= SN_ERR_PRXCOND;
3762 if (!(t->flags & SN_FINST_MASK))
3763 t->flags |= SN_FINST_H;
3764
3765 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3766 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3767
3768 return 1;
3769 }
3770 }
3771
willy tarreau982249e2005-12-18 00:57:06 +01003772 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
3773 if (t->flags & SN_SVDENY) {
3774 tv_eternity(&t->srexpire);
3775 tv_eternity(&t->swexpire);
3776 fd_delete(t->srv_fd);
3777 t->srv_state = SV_STCLOSE;
3778 t->logs.status = 502;
3779 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3780 if (!(t->flags & SN_ERR_MASK))
3781 t->flags |= SN_ERR_PRXCOND;
3782 if (!(t->flags & SN_FINST_MASK))
3783 t->flags |= SN_FINST_H;
3784 return 1;
3785 }
3786
willy tarreau5cbea6f2005-12-17 12:48:26 +01003787 /* we'll have something else to do here : add new headers ... */
3788
willy tarreaucd878942005-12-17 13:27:43 +01003789 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3790 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003791 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003792 * insert a set-cookie here, except if we want to insert only on POST
3793 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003794 */
willy tarreau750a4722005-12-17 13:21:24 +01003795 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003796 t->proxy->cookie_name,
3797 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003798
willy tarreau036e1ce2005-12-17 13:46:33 +01003799 t->flags |= SN_SCK_INSERTED;
3800
willy tarreau750a4722005-12-17 13:21:24 +01003801 /* Here, we will tell an eventual cache on the client side that we don't
3802 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3803 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3804 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3805 */
willy tarreau240afa62005-12-17 13:14:35 +01003806 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003807 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3808 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003809
willy tarreau750a4722005-12-17 13:21:24 +01003810 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003811 }
3812
3813 /* headers to be added */
3814 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003815 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3816 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003817 }
3818
willy tarreau25c4ea52005-12-18 00:49:49 +01003819 /* add a "connection: close" line if needed */
3820 if (t->proxy->options & PR_O_HTTP_CLOSE)
3821 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
3822
willy tarreau5cbea6f2005-12-17 12:48:26 +01003823 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003824 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003825 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01003826
3827 /* if the user wants to log as soon as possible, without counting
3828 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003829 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003830 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
3831 t->logs.bytes = rep->h - rep->data;
3832 sess_log(t);
3833 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003834 break;
3835 }
3836
3837 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3838 if (ptr > rep->r - 2) {
3839 /* this is a partial header, let's wait for more to come */
3840 rep->lr = ptr;
3841 break;
3842 }
3843
3844 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3845 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3846
3847 /* now we know that *ptr is either \r or \n,
3848 * and that there are at least 1 char after it.
3849 */
3850 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3851 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3852 else
3853 rep->lr = ptr + 2; /* \r\n or \n\r */
3854
3855 /*
3856 * now we know that we have a full header ; we can do whatever
3857 * we want with these pointers :
3858 * rep->h = beginning of header
3859 * ptr = end of header (first \r or \n)
3860 * rep->lr = beginning of next line (next rep->h)
3861 * rep->r = end of data (not used at this stage)
3862 */
3863
willy tarreaua1598082005-12-17 13:08:06 +01003864
willy tarreau982249e2005-12-18 00:57:06 +01003865 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01003866 t->logs.logwait &= ~LW_RESP;
3867 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01003868 switch (t->logs.status) {
3869 case 200:
3870 case 203:
3871 case 206:
3872 case 300:
3873 case 301:
3874 case 410:
3875 /* RFC2616 @13.4:
3876 * "A response received with a status code of
3877 * 200, 203, 206, 300, 301 or 410 MAY be stored
3878 * by a cache (...) unless a cache-control
3879 * directive prohibits caching."
3880 *
3881 * RFC2616 @9.5: POST method :
3882 * "Responses to this method are not cacheable,
3883 * unless the response includes appropriate
3884 * Cache-Control or Expires header fields."
3885 */
3886 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
3887 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
3888 break;
3889 default:
3890 break;
3891 }
willy tarreau4302f492005-12-18 01:00:37 +01003892 }
3893 else if (t->logs.logwait & LW_RSPHDR) {
3894 struct cap_hdr *h;
3895 int len;
3896 for (h = t->proxy->rsp_cap; h; h = h->next) {
3897 if ((h->namelen + 2 <= ptr - rep->h) &&
3898 (rep->h[h->namelen] == ':') &&
3899 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
3900
3901 if (t->rsp_cap[h->index] == NULL)
3902 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3903
3904 len = ptr - (rep->h + h->namelen + 2);
3905 if (len > h->len)
3906 len = h->len;
3907
3908 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
3909 t->rsp_cap[h->index][len]=0;
3910 }
3911 }
3912
willy tarreaua1598082005-12-17 13:08:06 +01003913 }
3914
willy tarreau5cbea6f2005-12-17 12:48:26 +01003915 delete_header = 0;
3916
willy tarreau982249e2005-12-18 00:57:06 +01003917 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003918 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003919 len = sprintf(trash, "%08x:%s.srvhdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003920 max = ptr - rep->h;
3921 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003922 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003923 trash[len++] = '\n';
3924 write(1, trash, len);
3925 }
3926
willy tarreau25c4ea52005-12-18 00:49:49 +01003927 /* remove "connection: " if needed */
3928 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3929 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
3930 delete_header = 1;
3931 }
3932
willy tarreau5cbea6f2005-12-17 12:48:26 +01003933 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003934 if (!delete_header && t->proxy->rsp_exp != NULL
3935 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003936 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003937 char term;
3938
3939 term = *ptr;
3940 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003941 exp = t->proxy->rsp_exp;
3942 do {
3943 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
3944 switch (exp->action) {
3945 case ACT_ALLOW:
3946 if (!(t->flags & SN_SVDENY))
3947 t->flags |= SN_SVALLOW;
3948 break;
3949 case ACT_REPLACE:
3950 if (!(t->flags & SN_SVDENY)) {
3951 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
3952 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
3953 }
3954 break;
3955 case ACT_REMOVE:
3956 if (!(t->flags & SN_SVDENY))
3957 delete_header = 1;
3958 break;
3959 case ACT_DENY:
3960 if (!(t->flags & SN_SVALLOW))
3961 t->flags |= SN_SVDENY;
3962 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003963 case ACT_PASS: /* we simply don't deny this one */
3964 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003965 }
3966 break;
3967 }
willy tarreaue39cd132005-12-17 13:00:18 +01003968 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003969 *ptr = term; /* restore the string terminator */
3970 }
3971
willy tarreau97f58572005-12-18 00:53:44 +01003972 /* check for cache-control: or pragma: headers */
3973 if (!delete_header && (t->flags & SN_CACHEABLE)) {
3974 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
3975 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3976 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
3977 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01003978 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01003979 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3980 else {
3981 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01003982 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01003983 t->flags &= ~SN_CACHE_COOK;
3984 }
3985 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003986 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01003987 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003988 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01003989 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3990 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01003991 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01003992 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01003993 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
3994 (rep->h + 25 == ptr || rep->h[25] == ',')) {
3995 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
3996 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
3997 (rep->h + 21 == ptr || rep->h[21] == ',')) {
3998 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01003999 }
4000 }
4001 }
4002
willy tarreau5cbea6f2005-12-17 12:48:26 +01004003 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004004 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004005 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004006 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004007 char *p1, *p2, *p3, *p4;
4008
willy tarreau97f58572005-12-18 00:53:44 +01004009 t->flags |= SN_SCK_ANY;
4010
willy tarreau5cbea6f2005-12-17 12:48:26 +01004011 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4012
4013 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004014 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004015 p1++;
4016
4017 if (p1 == ptr || *p1 == ';') /* end of cookie */
4018 break;
4019
4020 /* p1 is at the beginning of the cookie name */
4021 p2 = p1;
4022
4023 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4024 p2++;
4025
4026 if (p2 == ptr || *p2 == ';') /* next cookie */
4027 break;
4028
4029 p3 = p2 + 1; /* skips the '=' sign */
4030 if (p3 == ptr)
4031 break;
4032
4033 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004034 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004035 p4++;
4036
4037 /* here, we have the cookie name between p1 and p2,
4038 * and its value between p3 and p4.
4039 * we can process it.
4040 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004041
4042 /* first, let's see if we want to capture it */
4043 if (t->proxy->capture_name != NULL &&
4044 t->logs.srv_cookie == NULL &&
4045 (p4 - p1 >= t->proxy->capture_namelen) &&
4046 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4047 int log_len = p4 - p1;
4048
4049 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4050 Alert("HTTP logging : out of memory.\n");
4051 }
4052
4053 if (log_len > t->proxy->capture_len)
4054 log_len = t->proxy->capture_len;
4055 memcpy(t->logs.srv_cookie, p1, log_len);
4056 t->logs.srv_cookie[log_len] = 0;
4057 }
4058
4059 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4060 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004061 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004062 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004063
4064 /* If the cookie is in insert mode on a known server, we'll delete
4065 * this occurrence because we'll insert another one later.
4066 * We'll delete it too if the "indirect" option is set and we're in
4067 * a direct access. */
4068 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004069 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004070 /* this header must be deleted */
4071 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004072 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004073 }
4074 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4075 /* replace bytes p3->p4 with the cookie name associated
4076 * with this server since we know it.
4077 */
4078 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004079 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004080 }
willy tarreau0174f312005-12-18 01:02:42 +01004081 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4082 /* insert the cookie name associated with this server
4083 * before existing cookie, and insert a delimitor between them..
4084 */
4085 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4086 p3[t->srv->cklen] = COOKIE_DELIM;
4087 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4088 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004089 break;
4090 }
willy tarreau12350152005-12-18 01:03:27 +01004091
4092 /* first, let's see if the cookie is our appcookie*/
4093 if ((t->proxy->appsession_name != NULL) &&
4094 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4095
4096 /* Cool... it's the right one */
4097
4098 size_t server_id_len = strlen(t->srv->id)+1;
4099 asession_temp = &local_asession;
4100
4101 if((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL){
4102 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4103 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4104 }
4105 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4106 asession_temp->sessid[t->proxy->appsession_len] = 0;
4107 asession_temp->serverid = NULL;
4108
4109 /* only do insert, if lookup fails */
4110 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4111 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4112 Alert("Not enought Memory process_srv():asession:calloc().\n");
4113 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4114 return 0;
4115 }
4116 asession_temp->sessid = local_asession.sessid;
4117 asession_temp->serverid = local_asession.serverid;
4118 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4119 }/* end if(chtbl_lookup()) */
4120 else
4121 {
4122 /* free wasted memory */
4123 pool_free_to(apools.sessid, local_asession.sessid);
4124 } /* end else from if(chtbl_lookup()) */
4125
4126 if(asession_temp->serverid == NULL){
4127 if((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL){
4128 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4129 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4130 }
4131 asession_temp->serverid[0] = '\0';
4132 }
4133
4134 if(asession_temp->serverid[0] == '\0') memcpy(asession_temp->serverid,t->srv->id,server_id_len);
4135
4136 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4137
4138#if defined(DEBUG_HASH)
4139 print_table(&(t->proxy->htbl_proxy));
4140#endif
4141 break;
4142 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004143 else {
4144 // fprintf(stderr,"Ignoring unknown cookie : ");
4145 // write(2, p1, p2-p1);
4146 // fprintf(stderr," = ");
4147 // write(2, p3, p4-p3);
4148 // fprintf(stderr,"\n");
4149 }
4150 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4151 } /* we're now at the end of the cookie value */
4152 } /* end of cookie processing */
4153
willy tarreau97f58572005-12-18 00:53:44 +01004154 /* check for any set-cookie in case we check for cacheability */
4155 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4156 (t->proxy->options & PR_O_CHK_CACHE) &&
4157 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4158 t->flags |= SN_SCK_ANY;
4159 }
4160
willy tarreau5cbea6f2005-12-17 12:48:26 +01004161 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004162 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004163 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004164
willy tarreau5cbea6f2005-12-17 12:48:26 +01004165 rep->h = rep->lr;
4166 } /* while (rep->lr < rep->r) */
4167
4168 /* end of header processing (even if incomplete) */
4169
willy tarreauef900ab2005-12-17 12:52:52 +01004170 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4171 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4172 * full. We cannot loop here since event_srv_read will disable it only if
4173 * rep->l == rlim-data
4174 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004175 FD_SET(t->srv_fd, StaticReadEvent);
4176 if (t->proxy->srvtimeout)
4177 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4178 else
4179 tv_eternity(&t->srexpire);
4180 }
willy tarreau0f7af912005-12-17 12:21:26 +01004181
willy tarreau8337c6b2005-12-17 13:41:01 +01004182 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004183 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004184 tv_eternity(&t->srexpire);
4185 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004186 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004187 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004188 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004189 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004190 if (!(t->flags & SN_ERR_MASK))
4191 t->flags |= SN_ERR_SRVCL;
4192 if (!(t->flags & SN_FINST_MASK))
4193 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004194 return 1;
4195 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004196 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004197 * since we are in header mode, if there's no space left for headers, we
4198 * won't be able to free more later, so the session will never terminate.
4199 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004200 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE || rep->l >= rep->rlim - rep->data) {
willy tarreau0f7af912005-12-17 12:21:26 +01004201 FD_CLR(t->srv_fd, StaticReadEvent);
4202 tv_eternity(&t->srexpire);
4203 shutdown(t->srv_fd, SHUT_RD);
4204 t->srv_state = SV_STSHUTR;
4205 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004206 }
4207 /* read timeout : return a 504 to the client.
4208 */
4209 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4210 tv_eternity(&t->srexpire);
4211 tv_eternity(&t->swexpire);
4212 fd_delete(t->srv_fd);
4213 t->srv_state = SV_STCLOSE;
4214 t->logs.status = 504;
4215 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004216 if (!(t->flags & SN_ERR_MASK))
4217 t->flags |= SN_ERR_SRVTO;
4218 if (!(t->flags & SN_FINST_MASK))
4219 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004220 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004221
4222 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004223 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004224 /* FIXME!!! here, we don't want to switch to SHUTW if the
4225 * client shuts read too early, because we may still have
4226 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004227 * The side-effect is that if the client completely closes its
4228 * connection during SV_STHEADER, the connection to the server
4229 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004230 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004231 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004232 FD_CLR(t->srv_fd, StaticWriteEvent);
4233 tv_eternity(&t->swexpire);
4234 shutdown(t->srv_fd, SHUT_WR);
4235 t->srv_state = SV_STSHUTW;
4236 return 1;
4237 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004238 /* write timeout */
4239 /* FIXME!!! here, we don't want to switch to SHUTW if the
4240 * client shuts read too early, because we may still have
4241 * some work to do on the headers.
4242 */
4243 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4244 FD_CLR(t->srv_fd, StaticWriteEvent);
4245 tv_eternity(&t->swexpire);
4246 shutdown(t->srv_fd, SHUT_WR);
4247 t->srv_state = SV_STSHUTW;
4248 if (!(t->flags & SN_ERR_MASK))
4249 t->flags |= SN_ERR_SRVTO;
4250 if (!(t->flags & SN_FINST_MASK))
4251 t->flags |= SN_FINST_H;
4252 return 1;
4253 }
willy tarreau0f7af912005-12-17 12:21:26 +01004254
4255 if (req->l == 0) {
4256 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4257 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4258 tv_eternity(&t->swexpire);
4259 }
4260 }
4261 else { /* client buffer not empty */
4262 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4263 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004264 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004265 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004266 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4267 t->srexpire = t->swexpire;
4268 }
willy tarreau0f7af912005-12-17 12:21:26 +01004269 else
4270 tv_eternity(&t->swexpire);
4271 }
4272 }
4273
willy tarreau5cbea6f2005-12-17 12:48:26 +01004274 /* be nice with the client side which would like to send a complete header
4275 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4276 * would read all remaining data at once ! The client should not write past rep->lr
4277 * when the server is in header state.
4278 */
4279 //return header_processed;
4280 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004281 }
4282 else if (s == SV_STDATA) {
4283 /* read or write error */
4284 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004285 tv_eternity(&t->srexpire);
4286 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004287 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004288 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004289 if (!(t->flags & SN_ERR_MASK))
4290 t->flags |= SN_ERR_SRVCL;
4291 if (!(t->flags & SN_FINST_MASK))
4292 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004293 return 1;
4294 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004295 /* last read, or end of client write */
4296 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004297 FD_CLR(t->srv_fd, StaticReadEvent);
4298 tv_eternity(&t->srexpire);
4299 shutdown(t->srv_fd, SHUT_RD);
4300 t->srv_state = SV_STSHUTR;
4301 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004302 }
4303 /* end of client read and no more data to send */
4304 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4305 FD_CLR(t->srv_fd, StaticWriteEvent);
4306 tv_eternity(&t->swexpire);
4307 shutdown(t->srv_fd, SHUT_WR);
4308 t->srv_state = SV_STSHUTW;
4309 return 1;
4310 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004311 /* read timeout */
4312 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4313 FD_CLR(t->srv_fd, StaticReadEvent);
4314 tv_eternity(&t->srexpire);
4315 shutdown(t->srv_fd, SHUT_RD);
4316 t->srv_state = SV_STSHUTR;
4317 if (!(t->flags & SN_ERR_MASK))
4318 t->flags |= SN_ERR_SRVTO;
4319 if (!(t->flags & SN_FINST_MASK))
4320 t->flags |= SN_FINST_D;
4321 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004322 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004323 /* write timeout */
4324 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004325 FD_CLR(t->srv_fd, StaticWriteEvent);
4326 tv_eternity(&t->swexpire);
4327 shutdown(t->srv_fd, SHUT_WR);
4328 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004329 if (!(t->flags & SN_ERR_MASK))
4330 t->flags |= SN_ERR_SRVTO;
4331 if (!(t->flags & SN_FINST_MASK))
4332 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004333 return 1;
4334 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004335
4336 /* recompute request time-outs */
4337 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004338 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4339 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4340 tv_eternity(&t->swexpire);
4341 }
4342 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004343 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004344 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4345 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004346 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004347 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004348 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4349 t->srexpire = t->swexpire;
4350 }
willy tarreau0f7af912005-12-17 12:21:26 +01004351 else
4352 tv_eternity(&t->swexpire);
4353 }
4354 }
4355
willy tarreaub1ff9db2005-12-17 13:51:03 +01004356 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004357 if (rep->l == BUFSIZE) { /* no room to read more data */
4358 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4359 FD_CLR(t->srv_fd, StaticReadEvent);
4360 tv_eternity(&t->srexpire);
4361 }
4362 }
4363 else {
4364 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4365 FD_SET(t->srv_fd, StaticReadEvent);
4366 if (t->proxy->srvtimeout)
4367 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4368 else
4369 tv_eternity(&t->srexpire);
4370 }
4371 }
4372
4373 return 0; /* other cases change nothing */
4374 }
4375 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004376 if (t->res_sw == RES_ERROR) {
4377 //FD_CLR(t->srv_fd, StaticWriteEvent);
4378 tv_eternity(&t->swexpire);
4379 fd_delete(t->srv_fd);
4380 //close(t->srv_fd);
4381 t->srv_state = SV_STCLOSE;
4382 if (!(t->flags & SN_ERR_MASK))
4383 t->flags |= SN_ERR_SRVCL;
4384 if (!(t->flags & SN_FINST_MASK))
4385 t->flags |= SN_FINST_D;
4386 return 1;
4387 }
4388 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004389 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004390 tv_eternity(&t->swexpire);
4391 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004392 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004393 t->srv_state = SV_STCLOSE;
4394 return 1;
4395 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004396 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4397 //FD_CLR(t->srv_fd, StaticWriteEvent);
4398 tv_eternity(&t->swexpire);
4399 fd_delete(t->srv_fd);
4400 //close(t->srv_fd);
4401 t->srv_state = SV_STCLOSE;
4402 if (!(t->flags & SN_ERR_MASK))
4403 t->flags |= SN_ERR_SRVTO;
4404 if (!(t->flags & SN_FINST_MASK))
4405 t->flags |= SN_FINST_D;
4406 return 1;
4407 }
willy tarreau0f7af912005-12-17 12:21:26 +01004408 else if (req->l == 0) {
4409 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4410 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4411 tv_eternity(&t->swexpire);
4412 }
4413 }
4414 else { /* buffer not empty */
4415 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4416 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004417 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004418 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004419 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4420 t->srexpire = t->swexpire;
4421 }
willy tarreau0f7af912005-12-17 12:21:26 +01004422 else
4423 tv_eternity(&t->swexpire);
4424 }
4425 }
4426 return 0;
4427 }
4428 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004429 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004430 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004431 tv_eternity(&t->srexpire);
4432 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004433 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004434 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004435 if (!(t->flags & SN_ERR_MASK))
4436 t->flags |= SN_ERR_SRVCL;
4437 if (!(t->flags & SN_FINST_MASK))
4438 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004439 return 1;
4440 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004441 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4442 //FD_CLR(t->srv_fd, StaticReadEvent);
4443 tv_eternity(&t->srexpire);
4444 fd_delete(t->srv_fd);
4445 //close(t->srv_fd);
4446 t->srv_state = SV_STCLOSE;
4447 return 1;
4448 }
4449 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4450 //FD_CLR(t->srv_fd, StaticReadEvent);
4451 tv_eternity(&t->srexpire);
4452 fd_delete(t->srv_fd);
4453 //close(t->srv_fd);
4454 t->srv_state = SV_STCLOSE;
4455 if (!(t->flags & SN_ERR_MASK))
4456 t->flags |= SN_ERR_SRVTO;
4457 if (!(t->flags & SN_FINST_MASK))
4458 t->flags |= SN_FINST_D;
4459 return 1;
4460 }
willy tarreau0f7af912005-12-17 12:21:26 +01004461 else if (rep->l == BUFSIZE) { /* no room to read more data */
4462 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4463 FD_CLR(t->srv_fd, StaticReadEvent);
4464 tv_eternity(&t->srexpire);
4465 }
4466 }
4467 else {
4468 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4469 FD_SET(t->srv_fd, StaticReadEvent);
4470 if (t->proxy->srvtimeout)
4471 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4472 else
4473 tv_eternity(&t->srexpire);
4474 }
4475 }
4476 return 0;
4477 }
4478 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004479 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004480 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004481 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004482 write(1, trash, len);
4483 }
4484 return 0;
4485 }
4486 return 0;
4487}
4488
4489
willy tarreau5cbea6f2005-12-17 12:48:26 +01004490/* Processes the client and server jobs of a session task, then
4491 * puts it back to the wait queue in a clean state, or
4492 * cleans up its resources if it must be deleted. Returns
4493 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01004494 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004495int process_session(struct task *t) {
4496 struct session *s = t->context;
4497 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004498
willy tarreau5cbea6f2005-12-17 12:48:26 +01004499 do {
4500 fsm_resync = 0;
4501 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4502 fsm_resync |= process_cli(s);
4503 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4504 fsm_resync |= process_srv(s);
4505 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4506 } while (fsm_resync);
4507
4508 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004509 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004510 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004511
willy tarreau5cbea6f2005-12-17 12:48:26 +01004512 tv_min(&min1, &s->crexpire, &s->cwexpire);
4513 tv_min(&min2, &s->srexpire, &s->swexpire);
4514 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004515 tv_min(&t->expire, &min1, &min2);
4516
4517 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004518 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004519
willy tarreau5cbea6f2005-12-17 12:48:26 +01004520 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004521 }
4522
willy tarreau5cbea6f2005-12-17 12:48:26 +01004523 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004524 actconn--;
4525
willy tarreau982249e2005-12-18 00:57:06 +01004526 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004527 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004528 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n", s->uniq_id, s->proxy->id, (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004529 write(1, trash, len);
4530 }
4531
willy tarreau750a4722005-12-17 13:21:24 +01004532 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004533 if (s->rep != NULL)
4534 s->logs.bytes = s->rep->total;
4535
willy tarreau9fe663a2005-12-17 13:02:59 +01004536 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004537 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004538 sess_log(s);
4539
willy tarreau0f7af912005-12-17 12:21:26 +01004540 /* the task MUST not be in the run queue anymore */
4541 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004542 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004543 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004544 return -1; /* rest in peace for eternity */
4545}
4546
4547
4548
4549/*
4550 * manages a server health-check. Returns
4551 * the time the task accepts to wait, or -1 for infinity.
4552 */
4553int process_chk(struct task *t) {
4554 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004555 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004556 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004557
willy tarreauef900ab2005-12-17 12:52:52 +01004558 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004559
4560 if (fd < 0) { /* no check currently running */
4561 //fprintf(stderr, "process_chk: 2\n");
4562 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4563 task_queue(t); /* restore t to its place in the task list */
4564 return tv_remain(&now, &t->expire);
4565 }
4566
4567 /* we'll initiate a new check */
4568 s->result = 0; /* no result yet */
4569 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004570 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004571 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4572 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4573 //fprintf(stderr, "process_chk: 3\n");
4574
willy tarreaua41a8b42005-12-17 14:02:24 +01004575 /* we'll connect to the check port on the server */
4576 sa = s->addr;
4577 sa.sin_port = htons(s->check_port);
4578
willy tarreau0174f312005-12-18 01:02:42 +01004579 /* allow specific binding :
4580 * - server-specific at first
4581 * - proxy-specific next
4582 */
4583 if (s->state & SRV_BIND_SRC) {
4584 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4585 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
4586 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
4587 s->proxy->id, s->id);
4588 s->result = -1;
4589 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004590 }
willy tarreau0174f312005-12-18 01:02:42 +01004591 else if (s->proxy->options & PR_O_BIND_SRC) {
4592 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4593 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4594 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
4595 s->proxy->id);
4596 s->result = -1;
4597 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004598 }
willy tarreau0174f312005-12-18 01:02:42 +01004599
4600 if (!s->result) {
4601 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
4602 /* OK, connection in progress or established */
4603
4604 //fprintf(stderr, "process_chk: 4\n");
4605
4606 s->curfd = fd; /* that's how we know a test is in progress ;-) */
4607 fdtab[fd].owner = t;
4608 fdtab[fd].read = &event_srv_chk_r;
4609 fdtab[fd].write = &event_srv_chk_w;
4610 fdtab[fd].state = FD_STCONN; /* connection in progress */
4611 FD_SET(fd, StaticWriteEvent); /* for connect status */
4612 fd_insert(fd);
4613 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4614 tv_delayfrom(&t->expire, &now, s->inter);
4615 task_queue(t); /* restore t to its place in the task list */
4616 return tv_remain(&now, &t->expire);
4617 }
4618 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
4619 s->result = -1; /* a real error */
4620 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004621 }
4622 }
4623 //fprintf(stderr, "process_chk: 5\n");
4624 close(fd);
4625 }
4626
4627 if (!s->result) { /* nothing done */
4628 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004629 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004630 task_queue(t); /* restore t to its place in the task list */
4631 return tv_remain(&now, &t->expire);
4632 }
4633
4634 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01004635 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004636 s->health--; /* still good */
4637 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004638 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01004639 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004640 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004641 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01004642
willy tarreaudd07e972005-12-18 00:48:48 +01004643 if (find_server(s->proxy) == NULL) {
4644 Alert("Proxy %s has no server available !\n", s->proxy->id);
4645 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4646 }
4647 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004648 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004649 }
4650
4651 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004652 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4653 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004654 }
4655 else {
4656 //fprintf(stderr, "process_chk: 8\n");
4657 /* there was a test running */
4658 if (s->result > 0) { /* good server detected */
4659 //fprintf(stderr, "process_chk: 9\n");
4660 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01004661 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004662 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004663 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004664 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004665 }
willy tarreauef900ab2005-12-17 12:52:52 +01004666
willy tarreaue47c8d72005-12-17 12:55:52 +01004667 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004668 s->state |= SRV_RUNNING;
4669 }
willy tarreauef900ab2005-12-17 12:52:52 +01004670 s->curfd = -1; /* no check running anymore */
4671 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004672 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004673 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004674 }
4675 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
4676 //fprintf(stderr, "process_chk: 10\n");
4677 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01004678 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004679 s->health--; /* still good */
4680 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004681 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01004682
willy tarreaudd07e972005-12-18 00:48:48 +01004683 if (s->health == s->rise) {
4684 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004685 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01004686
4687 if (find_server(s->proxy) == NULL) {
4688 Alert("Proxy %s has no server available !\n", s->proxy->id);
4689 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4690 }
willy tarreau535ae7a2005-12-17 12:58:00 +01004691 }
willy tarreauef900ab2005-12-17 12:52:52 +01004692
willy tarreau5cbea6f2005-12-17 12:48:26 +01004693 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004694 }
4695 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01004696 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004697 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004698 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004699 }
4700 /* if result is 0 and there's no timeout, we have to wait again */
4701 }
4702 //fprintf(stderr, "process_chk: 11\n");
4703 s->result = 0;
4704 task_queue(t); /* restore t to its place in the task list */
4705 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01004706}
4707
4708
willy tarreau5cbea6f2005-12-17 12:48:26 +01004709
willy tarreau0f7af912005-12-17 12:21:26 +01004710#if STATTIME > 0
4711int stats(void);
4712#endif
4713
4714/*
4715 * Main select() loop.
4716 */
4717
4718void select_loop() {
4719 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01004720 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01004721 int status;
4722 int fd,i;
4723 struct timeval delta;
4724 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004725 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01004726
willy tarreau5cbea6f2005-12-17 12:48:26 +01004727 tv_now(&now);
4728
4729 while (1) {
4730 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01004731
willy tarreau5cbea6f2005-12-17 12:48:26 +01004732 /* look for expired tasks and add them to the run queue.
4733 */
4734 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4735 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4736 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01004737 if (t->state & TASK_RUNNING)
4738 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004739
4740 /* wakeup expired entries. It doesn't matter if they are
4741 * already running because of a previous event
4742 */
4743 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01004744 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004745 task_wakeup(&rq, t);
4746 }
4747 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004748 /* first non-runnable task. Use its expiration date as an upper bound */
4749 int temp_time = tv_remain(&now, &t->expire);
4750 if (temp_time)
4751 next_time = temp_time;
4752 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004753 break;
4754 }
4755 }
4756
4757 /* process each task in the run queue now. Each task may be deleted
4758 * since we only use tnext.
4759 */
4760 tnext = rq;
4761 while ((t = tnext) != NULL) {
4762 int temp_time;
4763
4764 tnext = t->rqnext;
4765 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01004766 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004767 temp_time = t->process(t);
4768 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01004769 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004770 }
4771
willy tarreauef900ab2005-12-17 12:52:52 +01004772 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01004773
4774 /* maintain all proxies in a consistent state. This should quickly become a task */
4775 time2 = maintain_proxies();
4776 next_time = MINTIME(time2, next_time);
4777
4778 /* stop when there's no connection left and we don't allow them anymore */
4779 if (!actconn && listeners == 0)
4780 break;
4781
willy tarreau0f7af912005-12-17 12:21:26 +01004782
4783#if STATTIME > 0
4784 time2 = stats();
4785 // fprintf(stderr," stats = %d\n", time2);
4786 next_time = MINTIME(time2, next_time);
4787#endif
4788
willy tarreau5cbea6f2005-12-17 12:48:26 +01004789 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01004790 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004791 /* to avoid eventual select loops due to timer precision */
4792 next_time += SCHEDULER_RESOLUTION;
4793 delta.tv_sec = next_time / 1000;
4794 delta.tv_usec = (next_time % 1000) * 1000;
4795 }
4796 else if (next_time == 0) { /* allow select to return immediately when needed */
4797 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004798 }
4799
4800
4801 /* let's restore fdset state */
4802
4803 readnotnull = 0; writenotnull = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01004804 for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01004805 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
4806 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
4807 }
4808
4809// /* just a verification code, needs to be removed for performance */
4810// for (i=0; i<maxfd; i++) {
4811// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
4812// abort();
4813// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
4814// abort();
4815//
4816// }
4817
willy tarreau197e8ec2005-12-17 14:10:59 +01004818 status = select(maxfd,
4819 readnotnull ? ReadEvent : NULL,
4820 writenotnull ? WriteEvent : NULL,
4821 NULL,
4822 (next_time >= 0) ? &delta : NULL);
willy tarreau0f7af912005-12-17 12:21:26 +01004823
willy tarreau5cbea6f2005-12-17 12:48:26 +01004824 /* this is an experiment on the separation of the select work */
4825 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4826 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
4827
willy tarreau0f7af912005-12-17 12:21:26 +01004828 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004829
willy tarreau0f7af912005-12-17 12:21:26 +01004830 if (status > 0) { /* must proceed with events */
4831
4832 int fds;
4833 char count;
4834
4835 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
4836 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
4837 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
4838
willy tarreau5cbea6f2005-12-17 12:48:26 +01004839 /* if we specify read first, the accepts and zero reads will be
4840 * seen first. Moreover, system buffers will be flushed faster.
4841 */
willy tarreau0f7af912005-12-17 12:21:26 +01004842 if (fdtab[fd].state == FD_STCLOSE)
4843 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01004844
4845 if (FD_ISSET(fd, ReadEvent))
4846 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004847
willy tarreau5cbea6f2005-12-17 12:48:26 +01004848 if (FD_ISSET(fd, WriteEvent))
4849 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004850 }
4851 }
4852 else {
4853 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
4854 }
willy tarreau0f7af912005-12-17 12:21:26 +01004855 }
4856}
4857
4858
4859#if STATTIME > 0
4860/*
4861 * Display proxy statistics regularly. It is designed to be called from the
4862 * select_loop().
4863 */
4864int stats(void) {
4865 static int lines;
4866 static struct timeval nextevt;
4867 static struct timeval lastevt;
4868 static struct timeval starttime = {0,0};
4869 unsigned long totaltime, deltatime;
4870 int ret;
4871
willy tarreau750a4722005-12-17 13:21:24 +01004872 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01004873 deltatime = (tv_diff(&lastevt, &now)?:1);
4874 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01004875
willy tarreau9fe663a2005-12-17 13:02:59 +01004876 if (global.mode & MODE_STATS) {
4877 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004878 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01004879 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
4880 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004881 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01004882 actconn, totalconn,
4883 stats_tsk_new, stats_tsk_good,
4884 stats_tsk_left, stats_tsk_right,
4885 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
4886 }
4887 }
4888
4889 tv_delayfrom(&nextevt, &now, STATTIME);
4890
4891 lastevt=now;
4892 }
4893 ret = tv_remain(&now, &nextevt);
4894 return ret;
4895}
4896#endif
4897
4898
4899/*
4900 * this function enables proxies when there are enough free sessions,
4901 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01004902 * select_loop(). It returns the time left before next expiration event
4903 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01004904 */
4905static int maintain_proxies(void) {
4906 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01004907 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004908 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01004909
4910 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004911 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01004912
4913 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01004914 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01004915 while (p) {
4916 if (p->nbconn < p->maxconn) {
4917 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004918 for (l = p->listen; l != NULL; l = l->next) {
4919 FD_SET(l->fd, StaticReadEvent);
4920 }
willy tarreau0f7af912005-12-17 12:21:26 +01004921 p->state = PR_STRUN;
4922 }
4923 }
4924 else {
4925 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004926 for (l = p->listen; l != NULL; l = l->next) {
4927 FD_CLR(l->fd, StaticReadEvent);
4928 }
willy tarreau0f7af912005-12-17 12:21:26 +01004929 p->state = PR_STIDLE;
4930 }
4931 }
4932 p = p->next;
4933 }
4934 }
4935 else { /* block all proxies */
4936 while (p) {
4937 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01004938 for (l = p->listen; l != NULL; l = l->next) {
4939 FD_CLR(l->fd, StaticReadEvent);
4940 }
willy tarreau0f7af912005-12-17 12:21:26 +01004941 p->state = PR_STIDLE;
4942 }
4943 p = p->next;
4944 }
4945 }
4946
willy tarreau5cbea6f2005-12-17 12:48:26 +01004947 if (stopping) {
4948 p = proxy;
4949 while (p) {
4950 if (p->state != PR_STDISABLED) {
4951 int t;
4952 t = tv_remain(&now, &p->stop_time);
4953 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004954 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004955 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004956
willy tarreaua41a8b42005-12-17 14:02:24 +01004957 for (l = p->listen; l != NULL; l = l->next) {
4958 fd_delete(l->fd);
4959 listeners--;
4960 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004961 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004962 }
4963 else {
4964 tleft = MINTIME(t, tleft);
4965 }
4966 }
4967 p = p->next;
4968 }
4969 }
4970 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01004971}
4972
4973/*
4974 * this function disables health-check servers so that the process will quickly be ignored
4975 * by load balancers.
4976 */
4977static void soft_stop(void) {
4978 struct proxy *p;
4979
4980 stopping = 1;
4981 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004982 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01004983 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004984 if (p->state != PR_STDISABLED) {
4985 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01004986 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01004987 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01004988 }
willy tarreau0f7af912005-12-17 12:21:26 +01004989 p = p->next;
4990 }
4991}
4992
4993/*
4994 * upon SIGUSR1, let's have a soft stop.
4995 */
4996void sig_soft_stop(int sig) {
4997 soft_stop();
4998 signal(sig, SIG_IGN);
4999}
5000
5001
willy tarreau8337c6b2005-12-17 13:41:01 +01005002/*
5003 * this function dumps every server's state when the process receives SIGHUP.
5004 */
5005void sig_dump_state(int sig) {
5006 struct proxy *p = proxy;
5007
5008 Warning("SIGHUP received, dumping servers states.\n");
5009 while (p) {
5010 struct server *s = p->srv;
5011
5012 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5013 while (s) {
5014 if (s->state & SRV_RUNNING) {
5015 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5016 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5017 }
5018 else {
5019 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5020 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5021 }
5022 s = s->next;
5023 }
willy tarreaudd07e972005-12-18 00:48:48 +01005024
5025 if (find_server(p) == NULL) {
5026 Warning("SIGHUP: proxy %s has no server available !\n", p);
5027 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5028 }
5029
willy tarreau8337c6b2005-12-17 13:41:01 +01005030 p = p->next;
5031 }
5032 signal(sig, sig_dump_state);
5033}
5034
willy tarreau0f7af912005-12-17 12:21:26 +01005035void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005036 struct task *t, *tnext;
5037 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005038
willy tarreau5cbea6f2005-12-17 12:48:26 +01005039 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5040 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5041 tnext = t->next;
5042 s = t->context;
5043 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5044 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5045 "req=%d, rep=%d, clifd=%d\n",
5046 s, tv_remain(&now, &t->expire),
5047 s->cli_state,
5048 s->srv_state,
5049 FD_ISSET(s->cli_fd, StaticReadEvent),
5050 FD_ISSET(s->cli_fd, StaticWriteEvent),
5051 FD_ISSET(s->srv_fd, StaticReadEvent),
5052 FD_ISSET(s->srv_fd, StaticWriteEvent),
5053 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5054 );
willy tarreau0f7af912005-12-17 12:21:26 +01005055 }
willy tarreau12350152005-12-18 01:03:27 +01005056}
5057
5058static void fast_stop(void)
5059{
5060 struct proxy *p;
5061 p = proxy;
5062 while (p) {
5063 p->grace = 0;
5064 p = p->next;
5065 }
5066 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005067}
5068
willy tarreau12350152005-12-18 01:03:27 +01005069void sig_int(int sig) {
5070 /* This would normally be a hard stop,
5071 but we want to be sure about deallocation,
5072 and so on, so we do a soft stop with
5073 0 GRACE time
5074 */
5075 fast_stop();
5076 /* If we are killed twice, we decide to die*/
5077 signal(sig, SIG_DFL);
5078}
5079
5080void sig_term(int sig) {
5081 /* This would normally be a hard stop,
5082 but we want to be sure about deallocation,
5083 and so on, so we do a soft stop with
5084 0 GRACE time
5085 */
5086 fast_stop();
5087 /* If we are killed twice, we decide to die*/
5088 signal(sig, SIG_DFL);
5089}
5090
willy tarreaue39cd132005-12-17 13:00:18 +01005091void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
5092 struct hdr_exp *exp;
5093
5094 while (*head != NULL)
5095 head = &(*head)->next;
5096
5097 exp = calloc(1, sizeof(struct hdr_exp));
5098
5099 exp->preg = preg;
5100 exp->replace = replace;
5101 exp->action = action;
5102 *head = exp;
5103}
5104
willy tarreau9fe663a2005-12-17 13:02:59 +01005105
willy tarreau0f7af912005-12-17 12:21:26 +01005106/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005107 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005108 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005109int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005110
willy tarreau9fe663a2005-12-17 13:02:59 +01005111 if (!strcmp(args[0], "global")) { /* new section */
5112 /* no option, nothing special to do */
5113 return 0;
5114 }
5115 else if (!strcmp(args[0], "daemon")) {
5116 global.mode |= MODE_DAEMON;
5117 }
5118 else if (!strcmp(args[0], "debug")) {
5119 global.mode |= MODE_DEBUG;
5120 }
5121 else if (!strcmp(args[0], "quiet")) {
5122 global.mode |= MODE_QUIET;
5123 }
5124 else if (!strcmp(args[0], "stats")) {
5125 global.mode |= MODE_STATS;
5126 }
5127 else if (!strcmp(args[0], "uid")) {
5128 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005129 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005130 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005131 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005132 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005133 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005134 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005135 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005136 global.uid = atol(args[1]);
5137 }
5138 else if (!strcmp(args[0], "gid")) {
5139 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005140 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005141 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005142 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005143 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005144 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005145 return -1;
5146 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005147 global.gid = atol(args[1]);
5148 }
5149 else if (!strcmp(args[0], "nbproc")) {
5150 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005151 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005152 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005153 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005154 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005155 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005156 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005157 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005158 global.nbproc = atol(args[1]);
5159 }
5160 else if (!strcmp(args[0], "maxconn")) {
5161 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005162 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005163 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005164 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005165 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005166 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005167 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005168 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005169 global.maxconn = atol(args[1]);
5170 }
5171 else if (!strcmp(args[0], "chroot")) {
5172 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005173 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005174 return 0;
5175 }
5176 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005177 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005178 return -1;
5179 }
5180 global.chroot = strdup(args[1]);
5181 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005182 else if (!strcmp(args[0], "pidfile")) {
5183 if (global.pidfile != NULL) {
5184 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5185 return 0;
5186 }
5187 if (*(args[1]) == 0) {
5188 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5189 return -1;
5190 }
5191 global.pidfile = strdup(args[1]);
5192 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005193 else if (!strcmp(args[0], "log")) { /* syslog server address */
5194 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005195 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005196
5197 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005198 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005199 return -1;
5200 }
5201
5202 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5203 if (!strcmp(log_facilities[facility], args[2]))
5204 break;
5205
5206 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005207 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005208 exit(1);
5209 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005210
5211 level = 7; /* max syslog level = debug */
5212 if (*(args[3])) {
5213 while (level >= 0 && strcmp(log_levels[level], args[3]))
5214 level--;
5215 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005216 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005217 exit(1);
5218 }
5219 }
5220
willy tarreau9fe663a2005-12-17 13:02:59 +01005221 sa = str2sa(args[1]);
5222 if (!sa->sin_port)
5223 sa->sin_port = htons(SYSLOG_PORT);
5224
5225 if (global.logfac1 == -1) {
5226 global.logsrv1 = *sa;
5227 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005228 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005229 }
5230 else if (global.logfac2 == -1) {
5231 global.logsrv2 = *sa;
5232 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005233 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005234 }
5235 else {
5236 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
5237 return -1;
5238 }
5239
5240 }
5241 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005242 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01005243 return -1;
5244 }
5245 return 0;
5246}
5247
5248
willy tarreaua41a8b42005-12-17 14:02:24 +01005249void init_default_instance() {
5250 memset(&defproxy, 0, sizeof(defproxy));
5251 defproxy.mode = PR_MODE_TCP;
5252 defproxy.state = PR_STNEW;
5253 defproxy.maxconn = cfg_maxpconn;
5254 defproxy.conn_retries = CONN_RETRIES;
5255 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
5256}
5257
willy tarreau9fe663a2005-12-17 13:02:59 +01005258/*
5259 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
5260 */
5261int cfg_parse_listen(char *file, int linenum, char **args) {
5262 static struct proxy *curproxy = NULL;
5263 struct server *newsrv = NULL;
willy tarreau12350152005-12-18 01:03:27 +01005264 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01005265
5266 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01005267 if (!*args[1]) {
5268 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
5269 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005270 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005271 return -1;
5272 }
5273
5274 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005275 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005276 return -1;
5277 }
5278 curproxy->next = proxy;
5279 proxy = curproxy;
5280 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01005281 if (strchr(args[2], ':') != NULL)
5282 curproxy->listen = str2listener(args[2], curproxy->listen);
5283
willy tarreau9fe663a2005-12-17 13:02:59 +01005284 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01005285 curproxy->state = defproxy.state;
5286 curproxy->maxconn = defproxy.maxconn;
5287 curproxy->conn_retries = defproxy.conn_retries;
5288 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005289
5290 if (defproxy.check_req)
5291 curproxy->check_req = strdup(defproxy.check_req);
5292 curproxy->check_len = defproxy.check_len;
5293
5294 if (defproxy.cookie_name)
5295 curproxy->cookie_name = strdup(defproxy.cookie_name);
5296 curproxy->cookie_len = defproxy.cookie_len;
5297
5298 if (defproxy.capture_name)
5299 curproxy->capture_name = strdup(defproxy.capture_name);
5300 curproxy->capture_namelen = defproxy.capture_namelen;
5301 curproxy->capture_len = defproxy.capture_len;
5302
5303 if (defproxy.errmsg.msg400)
5304 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
5305 curproxy->errmsg.len400 = defproxy.errmsg.len400;
5306
5307 if (defproxy.errmsg.msg403)
5308 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
5309 curproxy->errmsg.len403 = defproxy.errmsg.len403;
5310
5311 if (defproxy.errmsg.msg408)
5312 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
5313 curproxy->errmsg.len408 = defproxy.errmsg.len408;
5314
5315 if (defproxy.errmsg.msg500)
5316 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
5317 curproxy->errmsg.len500 = defproxy.errmsg.len500;
5318
5319 if (defproxy.errmsg.msg502)
5320 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
5321 curproxy->errmsg.len502 = defproxy.errmsg.len502;
5322
5323 if (defproxy.errmsg.msg503)
5324 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
5325 curproxy->errmsg.len503 = defproxy.errmsg.len503;
5326
5327 if (defproxy.errmsg.msg504)
5328 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
5329 curproxy->errmsg.len504 = defproxy.errmsg.len504;
5330
willy tarreaua41a8b42005-12-17 14:02:24 +01005331 curproxy->clitimeout = defproxy.clitimeout;
5332 curproxy->contimeout = defproxy.contimeout;
5333 curproxy->srvtimeout = defproxy.srvtimeout;
5334 curproxy->mode = defproxy.mode;
5335 curproxy->logfac1 = defproxy.logfac1;
5336 curproxy->logsrv1 = defproxy.logsrv1;
5337 curproxy->loglev1 = defproxy.loglev1;
5338 curproxy->logfac2 = defproxy.logfac2;
5339 curproxy->logsrv2 = defproxy.logsrv2;
5340 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01005341 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01005342 curproxy->grace = defproxy.grace;
5343 curproxy->source_addr = defproxy.source_addr;
5344 return 0;
5345 }
5346 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005347 /* some variables may have already been initialized earlier */
5348 if (defproxy.check_req) free(defproxy.check_req);
5349 if (defproxy.cookie_name) free(defproxy.cookie_name);
5350 if (defproxy.capture_name) free(defproxy.capture_name);
5351 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
5352 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
5353 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
5354 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
5355 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
5356 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
5357 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
5358
5359 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01005360 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01005361 return 0;
5362 }
5363 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005364 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005365 return -1;
5366 }
5367
willy tarreaua41a8b42005-12-17 14:02:24 +01005368 if (!strcmp(args[0], "bind")) { /* new listen addresses */
5369 if (curproxy == &defproxy) {
5370 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5371 return -1;
5372 }
5373
5374 if (strchr(args[1], ':') == NULL) {
5375 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
5376 file, linenum, args[0]);
5377 return -1;
5378 }
5379 curproxy->listen = str2listener(args[1], curproxy->listen);
5380 return 0;
5381 }
5382 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01005383 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
5384 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
5385 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
5386 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005387 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005388 return -1;
5389 }
5390 }
5391 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
5392 curproxy->state = PR_STDISABLED;
5393 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005394 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
5395 curproxy->state = PR_STNEW;
5396 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005397 else if (!strcmp(args[0], "cookie")) { /* cookie name */
5398 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005399// if (curproxy == &defproxy) {
5400// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5401// return -1;
5402// }
willy tarreaua41a8b42005-12-17 14:02:24 +01005403
willy tarreau9fe663a2005-12-17 13:02:59 +01005404 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005405// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
5406// file, linenum);
5407// return 0;
5408 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005409 }
5410
5411 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005412 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
5413 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005414 return -1;
5415 }
5416 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005417 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005418
5419 cur_arg = 2;
5420 while (*(args[cur_arg])) {
5421 if (!strcmp(args[cur_arg], "rewrite")) {
5422 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01005423 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005424 else if (!strcmp(args[cur_arg], "indirect")) {
5425 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01005426 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005427 else if (!strcmp(args[cur_arg], "insert")) {
5428 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01005429 }
willy tarreau240afa62005-12-17 13:14:35 +01005430 else if (!strcmp(args[cur_arg], "nocache")) {
5431 curproxy->options |= PR_O_COOK_NOC;
5432 }
willy tarreaucd878942005-12-17 13:27:43 +01005433 else if (!strcmp(args[cur_arg], "postonly")) {
5434 curproxy->options |= PR_O_COOK_POST;
5435 }
willy tarreau0174f312005-12-18 01:02:42 +01005436 else if (!strcmp(args[cur_arg], "prefix")) {
5437 curproxy->options |= PR_O_COOK_PFX;
5438 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005439 else {
willy tarreau0174f312005-12-18 01:02:42 +01005440 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005441 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005442 return -1;
5443 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005444 cur_arg++;
5445 }
willy tarreau0174f312005-12-18 01:02:42 +01005446 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
5447 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
5448 file, linenum);
5449 return -1;
5450 }
5451
5452 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
5453 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005454 file, linenum);
5455 return -1;
5456 }
willy tarreau12350152005-12-18 01:03:27 +01005457 }/* end else if (!strcmp(args[0], "cookie")) */
5458 else if (!strcmp(args[0], "appsession")) { /* cookie name */
5459// if (curproxy == &defproxy) {
5460// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5461// return -1;
5462// }
5463
5464 if (curproxy->appsession_name != NULL) {
5465// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
5466// file, linenum);
5467// return 0;
5468 free(curproxy->appsession_name);
5469 }
5470
5471 if (*(args[5]) == 0) {
5472 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
5473 file, linenum, args[0]);
5474 return -1;
5475 }
5476 have_appsession = 1;
5477 curproxy->appsession_name = strdup(args[1]);
5478 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
5479 curproxy->appsession_len = atoi(args[3]);
5480 curproxy->appsession_timeout = atoi(args[5]);
5481 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
5482 if (rc) {
5483 Alert("Error Init Appsession Hashtable.\n");
5484 return -1;
5485 }
5486 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01005487 else if (!strcmp(args[0], "capture")) {
5488 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
5489 // if (curproxy == &defproxy) {
5490 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5491 // return -1;
5492 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005493
willy tarreau4302f492005-12-18 01:00:37 +01005494 if (curproxy->capture_name != NULL) {
5495 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
5496 // file, linenum, args[0]);
5497 // return 0;
5498 free(curproxy->capture_name);
5499 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005500
willy tarreau4302f492005-12-18 01:00:37 +01005501 if (*(args[4]) == 0) {
5502 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
5503 file, linenum, args[0]);
5504 return -1;
5505 }
5506 curproxy->capture_name = strdup(args[2]);
5507 curproxy->capture_namelen = strlen(curproxy->capture_name);
5508 curproxy->capture_len = atol(args[4]);
5509 if (curproxy->capture_len >= CAPTURE_LEN) {
5510 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
5511 file, linenum, CAPTURE_LEN - 1);
5512 curproxy->capture_len = CAPTURE_LEN - 1;
5513 }
5514 curproxy->to_log |= LW_COOKIE;
5515 }
5516 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
5517 struct cap_hdr *hdr;
5518
5519 if (curproxy == &defproxy) {
5520 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5521 return -1;
5522 }
5523
5524 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5525 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5526 file, linenum, args[0], args[1]);
5527 return -1;
5528 }
5529
5530 hdr = calloc(sizeof(struct cap_hdr), 1);
5531 hdr->next = curproxy->req_cap;
5532 hdr->name = strdup(args[3]);
5533 hdr->namelen = strlen(args[3]);
5534 hdr->len = atol(args[5]);
5535 hdr->index = curproxy->nb_req_cap++;
5536 curproxy->req_cap = hdr;
5537 curproxy->to_log |= LW_REQHDR;
5538 }
5539 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
5540 struct cap_hdr *hdr;
5541
5542 if (curproxy == &defproxy) {
5543 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5544 return -1;
5545 }
5546
5547 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5548 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5549 file, linenum, args[0], args[1]);
5550 return -1;
5551 }
5552 hdr = calloc(sizeof(struct cap_hdr), 1);
5553 hdr->next = curproxy->rsp_cap;
5554 hdr->name = strdup(args[3]);
5555 hdr->namelen = strlen(args[3]);
5556 hdr->len = atol(args[5]);
5557 hdr->index = curproxy->nb_rsp_cap++;
5558 curproxy->rsp_cap = hdr;
5559 curproxy->to_log |= LW_RSPHDR;
5560 }
5561 else {
5562 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005563 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005564 return -1;
5565 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005566 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005567 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005568 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005569 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005570 return 0;
5571 }
5572 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005573 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5574 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005575 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005576 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005577 curproxy->contimeout = atol(args[1]);
5578 }
5579 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005580 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005581 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
5582 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005583 return 0;
5584 }
5585 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005586 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5587 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005588 return -1;
5589 }
5590 curproxy->clitimeout = atol(args[1]);
5591 }
5592 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005593 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005594 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005595 return 0;
5596 }
5597 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005598 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5599 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005600 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005601 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005602 curproxy->srvtimeout = atol(args[1]);
5603 }
5604 else if (!strcmp(args[0], "retries")) { /* connection retries */
5605 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005606 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
5607 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005608 return -1;
5609 }
5610 curproxy->conn_retries = atol(args[1]);
5611 }
5612 else if (!strcmp(args[0], "option")) {
5613 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005614 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005615 return -1;
5616 }
5617 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005618 /* enable reconnections to dispatch */
5619 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01005620#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01005621 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005622 /* enable transparent proxy connections */
5623 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01005624#endif
5625 else if (!strcmp(args[1], "keepalive"))
5626 /* enable keep-alive */
5627 curproxy->options |= PR_O_KEEPALIVE;
5628 else if (!strcmp(args[1], "forwardfor"))
5629 /* insert x-forwarded-for field */
5630 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01005631 else if (!strcmp(args[1], "logasap"))
5632 /* log as soon as possible, without waiting for the session to complete */
5633 curproxy->options |= PR_O_LOGASAP;
5634 else if (!strcmp(args[1], "httpclose"))
5635 /* force connection: close in both directions in HTTP mode */
5636 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01005637 else if (!strcmp(args[1], "checkcache"))
5638 /* require examination of cacheability of the 'set-cookie' field */
5639 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01005640 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01005641 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01005642 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01005643 else if (!strcmp(args[1], "tcplog"))
5644 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01005645 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01005646 else if (!strcmp(args[1], "dontlognull")) {
5647 /* don't log empty requests */
5648 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005649 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005650 else if (!strcmp(args[1], "httpchk")) {
5651 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005652 if (curproxy->check_req != NULL) {
5653 free(curproxy->check_req);
5654 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005655 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005656 if (!*args[2]) { /* no argument */
5657 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
5658 curproxy->check_len = strlen(DEF_CHECK_REQ);
5659 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01005660 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
5661 curproxy->check_req = (char *)malloc(reqlen);
5662 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
5663 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005664 } else { /* more arguments : METHOD URI [HTTP_VER] */
5665 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
5666 if (*args[4])
5667 reqlen += strlen(args[4]);
5668 else
5669 reqlen += strlen("HTTP/1.0");
5670
5671 curproxy->check_req = (char *)malloc(reqlen);
5672 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
5673 "%s %s %s\r\n\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
willy tarreau2f6ba652005-12-17 13:57:42 +01005674 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01005675 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005676 else if (!strcmp(args[1], "persist")) {
5677 /* persist on using the server specified by the cookie, even when it's down */
5678 curproxy->options |= PR_O_PERSIST;
5679 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005680 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005681 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005682 return -1;
5683 }
5684 return 0;
5685 }
5686 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
5687 /* enable reconnections to dispatch */
5688 curproxy->options |= PR_O_REDISP;
5689 }
willy tarreaua1598082005-12-17 13:08:06 +01005690#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01005691 else if (!strcmp(args[0], "transparent")) {
5692 /* enable transparent proxy connections */
5693 curproxy->options |= PR_O_TRANSP;
5694 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005695#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01005696 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
5697 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005698 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005699 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005700 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005701 curproxy->maxconn = atol(args[1]);
5702 }
5703 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
5704 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005705 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005706 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005707 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005708 curproxy->grace = atol(args[1]);
5709 }
5710 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01005711 if (curproxy == &defproxy) {
5712 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5713 return -1;
5714 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005715 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005716 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005717 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005718 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005719 curproxy->dispatch_addr = *str2sa(args[1]);
5720 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005721 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01005722 if (*(args[1])) {
5723 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005724 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01005725 }
5726 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005727 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005728 return -1;
5729 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005730 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005731 else /* if no option is set, use round-robin by default */
5732 curproxy->options |= PR_O_BALANCE_RR;
5733 }
5734 else if (!strcmp(args[0], "server")) { /* server address */
5735 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005736 char *rport;
5737 char *raddr;
5738 short realport;
5739 int do_check;
5740
5741 if (curproxy == &defproxy) {
5742 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5743 return -1;
5744 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005745
willy tarreaua41a8b42005-12-17 14:02:24 +01005746 if (!*args[2]) {
5747 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005748 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005749 return -1;
5750 }
5751 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
5752 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
5753 return -1;
5754 }
willy tarreau0174f312005-12-18 01:02:42 +01005755
5756 if (curproxy->srv == NULL)
5757 curproxy->srv = newsrv;
5758 else
5759 curproxy->cursrv->next = newsrv;
5760 curproxy->cursrv = newsrv;
5761
5762 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01005763 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01005764
5765 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01005766 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01005767 newsrv->id = strdup(args[1]);
5768
5769 /* several ways to check the port component :
5770 * - IP => port=+0, relative
5771 * - IP: => port=+0, relative
5772 * - IP:N => port=N, absolute
5773 * - IP:+N => port=+N, relative
5774 * - IP:-N => port=-N, relative
5775 */
5776 raddr = strdup(args[2]);
5777 rport = strchr(raddr, ':');
5778 if (rport) {
5779 *rport++ = 0;
5780 realport = atol(rport);
5781 if (!isdigit((int)*rport))
5782 newsrv->state |= SRV_MAPPORTS;
5783 } else {
5784 realport = 0;
5785 newsrv->state |= SRV_MAPPORTS;
5786 }
5787
5788 newsrv->addr = *str2sa(raddr);
5789 newsrv->addr.sin_port = htons(realport);
5790 free(raddr);
5791
willy tarreau9fe663a2005-12-17 13:02:59 +01005792 newsrv->curfd = -1; /* no health-check in progress */
5793 newsrv->inter = DEF_CHKINTR;
5794 newsrv->rise = DEF_RISETIME;
5795 newsrv->fall = DEF_FALLTIME;
5796 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
5797 cur_arg = 3;
5798 while (*args[cur_arg]) {
5799 if (!strcmp(args[cur_arg], "cookie")) {
5800 newsrv->cookie = strdup(args[cur_arg + 1]);
5801 newsrv->cklen = strlen(args[cur_arg + 1]);
5802 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01005803 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005804 else if (!strcmp(args[cur_arg], "rise")) {
5805 newsrv->rise = atol(args[cur_arg + 1]);
5806 newsrv->health = newsrv->rise;
5807 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01005808 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005809 else if (!strcmp(args[cur_arg], "fall")) {
5810 newsrv->fall = atol(args[cur_arg + 1]);
5811 cur_arg += 2;
5812 }
5813 else if (!strcmp(args[cur_arg], "inter")) {
5814 newsrv->inter = atol(args[cur_arg + 1]);
5815 cur_arg += 2;
5816 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005817 else if (!strcmp(args[cur_arg], "port")) {
5818 newsrv->check_port = atol(args[cur_arg + 1]);
5819 cur_arg += 2;
5820 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005821 else if (!strcmp(args[cur_arg], "backup")) {
5822 newsrv->state |= SRV_BACKUP;
5823 cur_arg ++;
5824 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005825 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005826 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005827 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005828 }
willy tarreau0174f312005-12-18 01:02:42 +01005829 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
5830 if (!*args[cur_arg + 1]) {
5831 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
5832 file, linenum, "source");
5833 return -1;
5834 }
5835 newsrv->state |= SRV_BIND_SRC;
5836 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
5837 cur_arg += 2;
5838 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005839 else {
willy tarreau0174f312005-12-18 01:02:42 +01005840 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port' and 'source'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01005841 file, linenum, newsrv->id);
5842 return -1;
5843 }
5844 }
5845
5846 if (do_check) {
5847 struct task *t;
5848
5849 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
5850 newsrv->check_port = realport; /* by default */
5851 if (!newsrv->check_port) {
5852 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005853 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01005854 return -1;
5855 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005856
5857 if ((t = pool_alloc(task)) == NULL) {
5858 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
5859 return -1;
5860 }
5861
5862 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
5863 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
5864 t->state = TASK_IDLE;
5865 t->process = process_chk;
5866 t->context = newsrv;
5867
5868 if (curproxy->state != PR_STDISABLED) {
5869 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
5870 task_queue(t);
5871 task_wakeup(&rq, t);
5872 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005873 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005874
willy tarreau9fe663a2005-12-17 13:02:59 +01005875 curproxy->nbservers++;
5876 }
5877 else if (!strcmp(args[0], "log")) { /* syslog server address */
5878 struct sockaddr_in *sa;
5879 int facility;
5880
5881 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
5882 curproxy->logfac1 = global.logfac1;
5883 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005884 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01005885 curproxy->logfac2 = global.logfac2;
5886 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01005887 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01005888 }
5889 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01005890 int level;
5891
willy tarreau0f7af912005-12-17 12:21:26 +01005892 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5893 if (!strcmp(log_facilities[facility], args[2]))
5894 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01005895
willy tarreau0f7af912005-12-17 12:21:26 +01005896 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005897 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01005898 exit(1);
5899 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005900
willy tarreau8337c6b2005-12-17 13:41:01 +01005901 level = 7; /* max syslog level = debug */
5902 if (*(args[3])) {
5903 while (level >= 0 && strcmp(log_levels[level], args[3]))
5904 level--;
5905 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005906 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005907 exit(1);
5908 }
5909 }
5910
willy tarreau0f7af912005-12-17 12:21:26 +01005911 sa = str2sa(args[1]);
5912 if (!sa->sin_port)
5913 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01005914
willy tarreau0f7af912005-12-17 12:21:26 +01005915 if (curproxy->logfac1 == -1) {
5916 curproxy->logsrv1 = *sa;
5917 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005918 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005919 }
5920 else if (curproxy->logfac2 == -1) {
5921 curproxy->logsrv2 = *sa;
5922 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005923 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01005924 }
5925 else {
5926 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005927 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005928 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005929 }
5930 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005931 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005932 file, linenum);
5933 return -1;
5934 }
5935 }
willy tarreaua1598082005-12-17 13:08:06 +01005936 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01005937 if (!*args[1]) {
5938 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005939 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01005940 return -1;
5941 }
5942
5943 curproxy->source_addr = *str2sa(args[1]);
5944 curproxy->options |= PR_O_BIND_SRC;
5945 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005946 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
5947 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005948 if (curproxy == &defproxy) {
5949 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5950 return -1;
5951 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005952
5953 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005954 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
5955 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005956 return -1;
5957 }
5958
5959 preg = calloc(1, sizeof(regex_t));
5960 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005961 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005962 return -1;
5963 }
5964
5965 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
5966 }
5967 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
5968 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005969 if (curproxy == &defproxy) {
5970 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5971 return -1;
5972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005973
5974 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005975 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005976 return -1;
5977 }
5978
5979 preg = calloc(1, sizeof(regex_t));
5980 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005981 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005982 return -1;
5983 }
5984
5985 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
5986 }
5987 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
5988 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01005989 if (curproxy == &defproxy) {
5990 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5991 return -1;
5992 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005993
5994 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005995 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005996 return -1;
5997 }
5998
5999 preg = calloc(1, sizeof(regex_t));
6000 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006001 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006002 return -1;
6003 }
6004
6005 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6006 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006007 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6008 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006009 if (curproxy == &defproxy) {
6010 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6011 return -1;
6012 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006013
6014 if (*(args[1]) == 0) {
6015 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6016 return -1;
6017 }
6018
6019 preg = calloc(1, sizeof(regex_t));
6020 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6021 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6022 return -1;
6023 }
6024
6025 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6026 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006027 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6028 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006029 if (curproxy == &defproxy) {
6030 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6031 return -1;
6032 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006033
6034 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006035 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006036 return -1;
6037 }
6038
6039 preg = calloc(1, sizeof(regex_t));
6040 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006041 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006042 return -1;
6043 }
6044
6045 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6046 }
6047 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6048 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006049 if (curproxy == &defproxy) {
6050 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6051 return -1;
6052 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006053
6054 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006055 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6056 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006057 return -1;
6058 }
6059
6060 preg = calloc(1, sizeof(regex_t));
6061 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006062 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006063 return -1;
6064 }
6065
6066 chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6067 }
6068 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6069 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006070 if (curproxy == &defproxy) {
6071 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6072 return -1;
6073 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006074
6075 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006076 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006077 return -1;
6078 }
6079
6080 preg = calloc(1, sizeof(regex_t));
6081 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006082 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006083 return -1;
6084 }
6085
6086 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6087 }
6088 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6089 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006090 if (curproxy == &defproxy) {
6091 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6092 return -1;
6093 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006094
6095 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006096 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006097 return -1;
6098 }
6099
6100 preg = calloc(1, sizeof(regex_t));
6101 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006102 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006103 return -1;
6104 }
6105
6106 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6107 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006108 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6109 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006110 if (curproxy == &defproxy) {
6111 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6112 return -1;
6113 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006114
6115 if (*(args[1]) == 0) {
6116 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6117 return -1;
6118 }
6119
6120 preg = calloc(1, sizeof(regex_t));
6121 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6122 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6123 return -1;
6124 }
6125
6126 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6127 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006128 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6129 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006130 if (curproxy == &defproxy) {
6131 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6132 return -1;
6133 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006134
6135 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006136 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006137 return -1;
6138 }
6139
6140 preg = calloc(1, sizeof(regex_t));
6141 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006142 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006143 return -1;
6144 }
6145
6146 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6147 }
6148 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006149 if (curproxy == &defproxy) {
6150 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6151 return -1;
6152 }
6153
willy tarreau9fe663a2005-12-17 13:02:59 +01006154 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006155 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006156 return 0;
6157 }
6158
6159 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006160 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006161 return -1;
6162 }
6163
willy tarreau4302f492005-12-18 01:00:37 +01006164 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
6165 }
6166 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
6167 regex_t *preg;
6168
6169 if (*(args[1]) == 0 || *(args[2]) == 0) {
6170 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6171 file, linenum, args[0]);
6172 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006173 }
willy tarreau4302f492005-12-18 01:00:37 +01006174
6175 preg = calloc(1, sizeof(regex_t));
6176 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6177 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6178 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006179 }
willy tarreau4302f492005-12-18 01:00:37 +01006180
6181 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6182 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006183 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
6184 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006185 if (curproxy == &defproxy) {
6186 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6187 return -1;
6188 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006189
6190 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006191 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006192 return -1;
6193 }
willy tarreaue39cd132005-12-17 13:00:18 +01006194
willy tarreau9fe663a2005-12-17 13:02:59 +01006195 preg = calloc(1, sizeof(regex_t));
6196 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006197 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006198 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006199 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006200
6201 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6202 }
willy tarreau982249e2005-12-18 00:57:06 +01006203 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
6204 regex_t *preg;
6205 if (curproxy == &defproxy) {
6206 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6207 return -1;
6208 }
6209
6210 if (*(args[1]) == 0) {
6211 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6212 return -1;
6213 }
6214
6215 preg = calloc(1, sizeof(regex_t));
6216 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6217 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6218 return -1;
6219 }
6220
6221 chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6222 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006223 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01006224 regex_t *preg;
6225 if (curproxy == &defproxy) {
6226 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6227 return -1;
6228 }
willy tarreaue39cd132005-12-17 13:00:18 +01006229
willy tarreaua41a8b42005-12-17 14:02:24 +01006230 if (*(args[1]) == 0 || *(args[2]) == 0) {
6231 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6232 file, linenum, args[0]);
6233 return -1;
6234 }
willy tarreaue39cd132005-12-17 13:00:18 +01006235
willy tarreaua41a8b42005-12-17 14:02:24 +01006236 preg = calloc(1, sizeof(regex_t));
6237 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6238 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6239 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006240 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006241
6242 chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6243 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006244 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
6245 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006246 if (curproxy == &defproxy) {
6247 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6248 return -1;
6249 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006250
6251 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006252 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006253 return -1;
6254 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006255
willy tarreau9fe663a2005-12-17 13:02:59 +01006256 preg = calloc(1, sizeof(regex_t));
6257 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006258 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006259 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006260 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006261
6262 chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6263 }
willy tarreau982249e2005-12-18 00:57:06 +01006264 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
6265 regex_t *preg;
6266 if (curproxy == &defproxy) {
6267 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6268 return -1;
6269 }
6270
6271 if (*(args[1]) == 0) {
6272 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6273 return -1;
6274 }
6275
6276 preg = calloc(1, sizeof(regex_t));
6277 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6278 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6279 return -1;
6280 }
6281
6282 chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6283 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006284 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006285 if (curproxy == &defproxy) {
6286 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6287 return -1;
6288 }
6289
willy tarreau9fe663a2005-12-17 13:02:59 +01006290 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006291 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006292 return 0;
6293 }
6294
6295 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006296 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006297 return -1;
6298 }
6299
6300 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
6301 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006302 else if (!strcmp(args[0], "errorloc")) { /* error location */
6303 int errnum;
6304 char *err;
6305
willy tarreaueedaa9f2005-12-17 14:08:03 +01006306 // if (curproxy == &defproxy) {
6307 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6308 // return -1;
6309 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006310
willy tarreau8337c6b2005-12-17 13:41:01 +01006311 if (*(args[2]) == 0) {
6312 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
6313 return -1;
6314 }
6315
6316 errnum = atol(args[1]);
6317 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
6318 sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
6319
6320 if (errnum == 400) {
6321 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006322 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006323 free(curproxy->errmsg.msg400);
6324 }
6325 curproxy->errmsg.msg400 = err;
6326 curproxy->errmsg.len400 = strlen(err);
6327 }
6328 else if (errnum == 403) {
6329 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006330 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006331 free(curproxy->errmsg.msg403);
6332 }
6333 curproxy->errmsg.msg403 = err;
6334 curproxy->errmsg.len403 = strlen(err);
6335 }
6336 else if (errnum == 408) {
6337 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006338 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006339 free(curproxy->errmsg.msg408);
6340 }
6341 curproxy->errmsg.msg408 = err;
6342 curproxy->errmsg.len408 = strlen(err);
6343 }
6344 else if (errnum == 500) {
6345 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006346 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006347 free(curproxy->errmsg.msg500);
6348 }
6349 curproxy->errmsg.msg500 = err;
6350 curproxy->errmsg.len500 = strlen(err);
6351 }
6352 else if (errnum == 502) {
6353 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006354 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006355 free(curproxy->errmsg.msg502);
6356 }
6357 curproxy->errmsg.msg502 = err;
6358 curproxy->errmsg.len502 = strlen(err);
6359 }
6360 else if (errnum == 503) {
6361 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006362 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006363 free(curproxy->errmsg.msg503);
6364 }
6365 curproxy->errmsg.msg503 = err;
6366 curproxy->errmsg.len503 = strlen(err);
6367 }
6368 else if (errnum == 504) {
6369 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006370 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006371 free(curproxy->errmsg.msg504);
6372 }
6373 curproxy->errmsg.msg504 = err;
6374 curproxy->errmsg.len504 = strlen(err);
6375 }
6376 else {
6377 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
6378 free(err);
6379 }
6380 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006381 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006382 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01006383 return -1;
6384 }
6385 return 0;
6386}
willy tarreaue39cd132005-12-17 13:00:18 +01006387
willy tarreau5cbea6f2005-12-17 12:48:26 +01006388
willy tarreau9fe663a2005-12-17 13:02:59 +01006389/*
6390 * This function reads and parses the configuration file given in the argument.
6391 * returns 0 if OK, -1 if error.
6392 */
6393int readcfgfile(char *file) {
6394 char thisline[256];
6395 char *line;
6396 FILE *f;
6397 int linenum = 0;
6398 char *end;
6399 char *args[MAX_LINE_ARGS];
6400 int arg;
6401 int cfgerr = 0;
6402 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01006403
willy tarreau9fe663a2005-12-17 13:02:59 +01006404 struct proxy *curproxy = NULL;
6405 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006406
willy tarreau9fe663a2005-12-17 13:02:59 +01006407 if ((f=fopen(file,"r")) == NULL)
6408 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006409
willy tarreaueedaa9f2005-12-17 14:08:03 +01006410 init_default_instance();
6411
willy tarreau9fe663a2005-12-17 13:02:59 +01006412 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
6413 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006414
willy tarreau9fe663a2005-12-17 13:02:59 +01006415 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006416
willy tarreau9fe663a2005-12-17 13:02:59 +01006417 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01006418 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01006419 line++;
6420
6421 arg = 0;
6422 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01006423
willy tarreau9fe663a2005-12-17 13:02:59 +01006424 while (*line && arg < MAX_LINE_ARGS) {
6425 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
6426 * C equivalent value. Other combinations left unchanged (eg: \1).
6427 */
6428 if (*line == '\\') {
6429 int skip = 0;
6430 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
6431 *line = line[1];
6432 skip = 1;
6433 }
6434 else if (line[1] == 'r') {
6435 *line = '\r';
6436 skip = 1;
6437 }
6438 else if (line[1] == 'n') {
6439 *line = '\n';
6440 skip = 1;
6441 }
6442 else if (line[1] == 't') {
6443 *line = '\t';
6444 skip = 1;
6445 }
6446 else if (line[1] == 'x' && (line + 3 < end )) {
6447 unsigned char hex1, hex2;
6448 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
6449 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
6450 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
6451 *line = (hex1<<4) + hex2;
6452 skip = 3;
6453 }
6454 if (skip) {
6455 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
6456 end -= skip;
6457 }
6458 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006459 }
willy tarreaua1598082005-12-17 13:08:06 +01006460 else if (*line == '#' || *line == '\n' || *line == '\r') {
6461 /* end of string, end of loop */
6462 *line = 0;
6463 break;
6464 }
willy tarreauc29948c2005-12-17 13:10:27 +01006465 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006466 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01006467 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01006468 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01006469 line++;
6470 args[++arg] = line;
6471 }
6472 else {
6473 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006474 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006475 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006476
willy tarreau9fe663a2005-12-17 13:02:59 +01006477 /* empty line */
6478 if (!**args)
6479 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01006480
willy tarreau9fe663a2005-12-17 13:02:59 +01006481 /* zero out remaining args */
6482 while (++arg < MAX_LINE_ARGS) {
6483 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006484 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006485
willy tarreaua41a8b42005-12-17 14:02:24 +01006486 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01006487 confsect = CFG_LISTEN;
6488 else if (!strcmp(args[0], "global")) /* global config */
6489 confsect = CFG_GLOBAL;
6490 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006491
willy tarreau9fe663a2005-12-17 13:02:59 +01006492 switch (confsect) {
6493 case CFG_LISTEN:
6494 if (cfg_parse_listen(file, linenum, args) < 0)
6495 return -1;
6496 break;
6497 case CFG_GLOBAL:
6498 if (cfg_parse_global(file, linenum, args) < 0)
6499 return -1;
6500 break;
6501 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01006502 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006503 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006504 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006505
6506
willy tarreau0f7af912005-12-17 12:21:26 +01006507 }
6508 fclose(f);
6509
6510 /*
6511 * Now, check for the integrity of all that we have collected.
6512 */
6513
6514 if ((curproxy = proxy) == NULL) {
6515 Alert("parsing %s : no <listen> line. Nothing to do !\n",
6516 file);
6517 return -1;
6518 }
6519
6520 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01006521 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01006522 if (curproxy->state == PR_STDISABLED) {
6523 curproxy = curproxy->next;
6524 continue;
6525 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006526 if ((curproxy->mode != PR_MODE_HEALTH) &&
6527 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01006528 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006529 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
6530 file, curproxy->id);
6531 cfgerr++;
6532 }
6533 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
6534 if (curproxy->options & PR_O_TRANSP) {
6535 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
6536 file, curproxy->id);
6537 cfgerr++;
6538 }
6539 else if (curproxy->srv == NULL) {
6540 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
6541 file, curproxy->id);
6542 cfgerr++;
6543 }
willy tarreaua1598082005-12-17 13:08:06 +01006544 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006545 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
6546 file, curproxy->id);
6547 }
6548 }
6549 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01006550 if (curproxy->cookie_name != NULL) {
6551 Warning("parsing %s : cookie will be ignored for listener %s.\n",
6552 file, curproxy->id);
6553 }
6554 if ((newsrv = curproxy->srv) != NULL) {
6555 Warning("parsing %s : servers will be ignored for listener %s.\n",
6556 file, curproxy->id);
6557 }
willy tarreaue39cd132005-12-17 13:00:18 +01006558 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01006559 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
6560 file, curproxy->id);
6561 }
willy tarreaue39cd132005-12-17 13:00:18 +01006562 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01006563 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
6564 file, curproxy->id);
6565 }
6566 }
6567 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
6568 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
6569 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
6570 file, curproxy->id);
6571 cfgerr++;
6572 }
6573 else {
6574 while (newsrv != NULL) {
6575 /* nothing to check for now */
6576 newsrv = newsrv->next;
6577 }
6578 }
6579 }
willy tarreau25c4ea52005-12-18 00:49:49 +01006580
6581 if (curproxy->options & PR_O_LOGASAP)
6582 curproxy->to_log &= ~LW_BYTES;
6583
willy tarreau8337c6b2005-12-17 13:41:01 +01006584 if (curproxy->errmsg.msg400 == NULL) {
6585 curproxy->errmsg.msg400 = (char *)HTTP_400;
6586 curproxy->errmsg.len400 = strlen(HTTP_400);
6587 }
6588 if (curproxy->errmsg.msg403 == NULL) {
6589 curproxy->errmsg.msg403 = (char *)HTTP_403;
6590 curproxy->errmsg.len403 = strlen(HTTP_403);
6591 }
6592 if (curproxy->errmsg.msg408 == NULL) {
6593 curproxy->errmsg.msg408 = (char *)HTTP_408;
6594 curproxy->errmsg.len408 = strlen(HTTP_408);
6595 }
6596 if (curproxy->errmsg.msg500 == NULL) {
6597 curproxy->errmsg.msg500 = (char *)HTTP_500;
6598 curproxy->errmsg.len500 = strlen(HTTP_500);
6599 }
6600 if (curproxy->errmsg.msg502 == NULL) {
6601 curproxy->errmsg.msg502 = (char *)HTTP_502;
6602 curproxy->errmsg.len502 = strlen(HTTP_502);
6603 }
6604 if (curproxy->errmsg.msg503 == NULL) {
6605 curproxy->errmsg.msg503 = (char *)HTTP_503;
6606 curproxy->errmsg.len503 = strlen(HTTP_503);
6607 }
6608 if (curproxy->errmsg.msg504 == NULL) {
6609 curproxy->errmsg.msg504 = (char *)HTTP_504;
6610 curproxy->errmsg.len504 = strlen(HTTP_504);
6611 }
willy tarreau0f7af912005-12-17 12:21:26 +01006612 curproxy = curproxy->next;
6613 }
6614 if (cfgerr > 0) {
6615 Alert("Errors found in configuration file, aborting.\n");
6616 return -1;
6617 }
6618 else
6619 return 0;
6620}
6621
6622
6623/*
6624 * This function initializes all the necessary variables. It only returns
6625 * if everything is OK. If something fails, it exits.
6626 */
6627void init(int argc, char **argv) {
6628 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01006630 char *old_argv = *argv;
6631 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006632 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006633 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01006634
6635 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01006636 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006637 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01006638 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01006639 exit(1);
6640 }
6641
willy tarreau4302f492005-12-18 01:00:37 +01006642 /* initialize the log header encoding map : '{|}"#' should be encoded with
6643 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
6644 * URL encoding only requires '"', '#' to be encoded as well as non-
6645 * printable characters above.
6646 */
6647 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
6648 memset(url_encode_map, 0, sizeof(url_encode_map));
6649 for (i = 0; i < 32; i++) {
6650 FD_SET(i, hdr_encode_map);
6651 FD_SET(i, url_encode_map);
6652 }
6653 for (i = 127; i < 256; i++) {
6654 FD_SET(i, hdr_encode_map);
6655 FD_SET(i, url_encode_map);
6656 }
6657
6658 tmp = "\"#{|}";
6659 while (*tmp) {
6660 FD_SET(*tmp, hdr_encode_map);
6661 tmp++;
6662 }
6663
6664 tmp = "\"#";
6665 while (*tmp) {
6666 FD_SET(*tmp, url_encode_map);
6667 tmp++;
6668 }
6669
willy tarreau0f7af912005-12-17 12:21:26 +01006670 pid = getpid();
6671 progname = *argv;
6672 while ((tmp = strchr(progname, '/')) != NULL)
6673 progname = tmp + 1;
6674
6675 argc--; argv++;
6676 while (argc > 0) {
6677 char *flag;
6678
6679 if (**argv == '-') {
6680 flag = *argv+1;
6681
6682 /* 1 arg */
6683 if (*flag == 'v') {
6684 display_version();
6685 exit(0);
6686 }
willy tarreau982249e2005-12-18 00:57:06 +01006687 else if (*flag == 'V')
6688 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01006689 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01006690 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01006691 else if (*flag == 'c')
6692 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01006693 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01006694 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006695 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01006696 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01006697#if STATTIME > 0
6698 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01006699 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01006700 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01006701 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01006702#endif
6703 else { /* >=2 args */
6704 argv++; argc--;
6705 if (argc == 0)
6706 usage(old_argv);
6707
6708 switch (*flag) {
6709 case 'n' : cfg_maxconn = atol(*argv); break;
6710 case 'N' : cfg_maxpconn = atol(*argv); break;
6711 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01006712 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01006713 default: usage(old_argv);
6714 }
6715 }
6716 }
6717 else
6718 usage(old_argv);
6719 argv++; argc--;
6720 }
6721
willy tarreau982249e2005-12-18 00:57:06 +01006722 global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01006723
willy tarreau0f7af912005-12-17 12:21:26 +01006724 if (!cfg_cfgfile)
6725 usage(old_argv);
6726
6727 gethostname(hostname, MAX_HOSTNAME_LEN);
6728
willy tarreau12350152005-12-18 01:03:27 +01006729 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006730 if (readcfgfile(cfg_cfgfile) < 0) {
6731 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
6732 exit(1);
6733 }
willy tarreau12350152005-12-18 01:03:27 +01006734 if (have_appsession)
6735 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01006736
willy tarreau982249e2005-12-18 00:57:06 +01006737 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01006738 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
6739 exit(0);
6740 }
6741
willy tarreau9fe663a2005-12-17 13:02:59 +01006742 if (cfg_maxconn > 0)
6743 global.maxconn = cfg_maxconn;
6744
willy tarreaufe2c5c12005-12-17 14:14:34 +01006745 if (cfg_pidfile) {
6746 if (global.pidfile)
6747 free(global.pidfile);
6748 global.pidfile = strdup(cfg_pidfile);
6749 }
6750
willy tarreau9fe663a2005-12-17 13:02:59 +01006751 if (global.maxconn == 0)
6752 global.maxconn = DEFAULT_MAXCONN;
6753
6754 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
6755
6756 if (arg_mode & MODE_DEBUG) {
6757 /* command line debug mode inhibits configuration mode */
6758 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
6759 }
willy tarreau982249e2005-12-18 00:57:06 +01006760 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
6761 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01006762
6763 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
6764 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
6765 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
6766 }
6767
6768 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
6769 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
6770 global.nbproc = 1;
6771 }
6772
6773 if (global.nbproc < 1)
6774 global.nbproc = 1;
6775
willy tarreau0f7af912005-12-17 12:21:26 +01006776 ReadEvent = (fd_set *)calloc(1,
6777 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006778 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006779 WriteEvent = (fd_set *)calloc(1,
6780 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006781 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006782 StaticReadEvent = (fd_set *)calloc(1,
6783 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006784 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006785 StaticWriteEvent = (fd_set *)calloc(1,
6786 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01006787 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01006788
6789 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01006790 sizeof(struct fdtab) * (global.maxsock));
6791 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01006792 fdtab[i].state = FD_STCLOSE;
6793 }
6794}
6795
6796/*
6797 * this function starts all the proxies. It returns 0 if OK, -1 if not.
6798 */
6799int start_proxies() {
6800 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006801 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01006802 int fd;
6803
6804 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01006805 if (curproxy->state == PR_STDISABLED)
6806 continue;
6807
willy tarreaua41a8b42005-12-17 14:02:24 +01006808 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
6809 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01006810 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006811 Alert("cannot create listening socket for proxy %s. Aborting.\n",
6812 curproxy->id);
6813 return -1;
6814 }
willy tarreau0f7af912005-12-17 12:21:26 +01006815
willy tarreaua41a8b42005-12-17 14:02:24 +01006816 if (fd >= global.maxsock) {
6817 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
6818 curproxy->id);
6819 close(fd);
6820 return -1;
6821 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006822
willy tarreaua41a8b42005-12-17 14:02:24 +01006823 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
6824 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
6825 (char *) &one, sizeof(one)) == -1)) {
6826 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
6827 curproxy->id);
6828 close(fd);
6829 return -1;
6830 }
willy tarreau0f7af912005-12-17 12:21:26 +01006831
willy tarreaua41a8b42005-12-17 14:02:24 +01006832 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
6833 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
6834 curproxy->id);
6835 }
willy tarreau0f7af912005-12-17 12:21:26 +01006836
willy tarreaua41a8b42005-12-17 14:02:24 +01006837 if (bind(fd,
6838 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01006839 listener->addr.ss_family == AF_INET6 ?
6840 sizeof(struct sockaddr_in6) :
6841 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006842 Alert("cannot bind socket for proxy %s. Aborting.\n",
6843 curproxy->id);
6844 close(fd);
6845 return -1;
6846 }
willy tarreau0f7af912005-12-17 12:21:26 +01006847
willy tarreaua41a8b42005-12-17 14:02:24 +01006848 if (listen(fd, curproxy->maxconn) == -1) {
6849 Alert("cannot listen to socket for proxy %s. Aborting.\n",
6850 curproxy->id);
6851 close(fd);
6852 return -1;
6853 }
willy tarreau0f7af912005-12-17 12:21:26 +01006854
willy tarreaua41a8b42005-12-17 14:02:24 +01006855 /* the function for the accept() event */
6856 fdtab[fd].read = &event_accept;
6857 fdtab[fd].write = NULL; /* never called */
6858 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
6859 curproxy->state = PR_STRUN;
6860 fdtab[fd].state = FD_STLISTEN;
6861 FD_SET(fd, StaticReadEvent);
6862 fd_insert(fd);
6863 listeners++;
6864 }
willy tarreaua1598082005-12-17 13:08:06 +01006865 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006866 }
6867 return 0;
6868}
6869
willy tarreau12350152005-12-18 01:03:27 +01006870int match_str(const void *key1, const void *key2){
6871
6872 appsess *temp1,*temp2;
6873 temp1 = (appsess *)key1;
6874 temp2 = (appsess *)key2;
6875
6876 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
6877 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
6878
6879 return (strcmp(temp1->sessid,temp2->sessid) == 0);
6880}/* end match_str */
6881
6882void destroy(void *data){
6883 appsess *temp1;
6884
6885 //printf("destroy called\n");
6886 temp1 = (appsess *)data;
6887
6888 if (temp1->sessid)
6889 pool_free_to(apools.sessid, temp1->sessid);
6890
6891 if (temp1->serverid)
6892 pool_free_to(apools.serverid, temp1->serverid);
6893
6894 pool_free(appsess, temp1);
6895} /* end destroy */
6896
6897void appsession_cleanup( void )
6898{
6899 struct proxy *p = proxy;
6900
6901 while(p) {
6902 chtbl_destroy(&(p->htbl_proxy));
6903 p = p->next;
6904 }
6905}/* end appsession_cleanup() */
6906
6907void pool_destroy(void **pool)
6908{
6909 void *temp, *next;
6910 next = pool;
6911 while (next) {
6912 temp = next;
6913 next = *(void **)temp;
6914 free(temp);
6915 }
6916}/* end pool_destroy() */
6917
6918void deinit(void){
6919 struct proxy *p = proxy;
6920 struct cap_hdr *h,*h_next;
6921 struct server *s,*s_next;
6922 struct listener *l,*l_next;
6923
6924 while (p) {
6925 if (p->id)
6926 free(p->id);
6927
6928 if (p->check_req)
6929 free(p->check_req);
6930
6931 if (p->cookie_name)
6932 free(p->cookie_name);
6933
6934 if (p->capture_name)
6935 free(p->capture_name);
6936
6937 /* only strup if the user have set in config.
6938 When should we free it?!
6939 if(p->errmsg.msg400) free(p->errmsg.msg400);
6940 if(p->errmsg.msg403) free(p->errmsg.msg403);
6941 if(p->errmsg.msg408) free(p->errmsg.msg408);
6942 if(p->errmsg.msg500) free(p->errmsg.msg500);
6943 if(p->errmsg.msg502) free(p->errmsg.msg502);
6944 if(p->errmsg.msg503) free(p->errmsg.msg503);
6945 if(p->errmsg.msg504) free(p->errmsg.msg504);
6946 */
6947 if (p->appsession_name)
6948 free(p->appsession_name);
6949
6950 h = p->req_cap;
6951 while (h) {
6952 h_next = h->next;
6953 if (h->name)
6954 free(h->name);
6955 pool_destroy(h->pool);
6956 free(h);
6957 h = h_next;
6958 }/* end while(h) */
6959
6960 h = p->rsp_cap;
6961 while (h) {
6962 h_next = h->next;
6963 if (h->name)
6964 free(h->name);
6965
6966 pool_destroy(h->pool);
6967 free(h);
6968 h = h_next;
6969 }/* end while(h) */
6970
6971 s = p->srv;
6972 while (s) {
6973 s_next = s->next;
6974 if(s->id)
6975 free(s->id);
6976
6977 if(s->cookie)
6978 free(s->cookie);
6979
6980 free(s);
6981 s = s_next;
6982 }/* end while(s) */
6983
6984 l = p->listen;
6985 while (l) {
6986 l_next = l->next;
6987 free(l);
6988 l = l_next;
6989 }/* end while(l) */
6990
6991 pool_destroy((void **) p->req_cap_pool);
6992 pool_destroy((void **) p->rsp_cap_pool);
6993 p = p->next;
6994 }/* end while(p) */
6995
6996 if (global.chroot) free(global.chroot);
6997 if (global.pidfile) free(global.pidfile);
6998
6999 if (ReadEvent) free(ReadEvent);
7000 if (WriteEvent) free(WriteEvent);
7001 if (StaticReadEvent) free(StaticReadEvent);
7002 if (StaticWriteEvent) free(StaticWriteEvent);
7003 if (fdtab) free(fdtab);
7004
7005 pool_destroy(pool_session);
7006 pool_destroy(pool_buffer);
7007 pool_destroy(pool_fdtab);
7008 pool_destroy(pool_requri);
7009 pool_destroy(pool_task);
7010 pool_destroy(pool_capture);
7011 pool_destroy(pool_appsess);
7012
7013 if (have_appsession) {
7014 pool_destroy(apools.serverid);
7015 pool_destroy(apools.sessid);
7016 }
7017} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007018
7019int main(int argc, char **argv) {
willy tarreaufe2c5c12005-12-17 14:14:34 +01007020 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007021 init(argc, argv);
7022
willy tarreau9fe663a2005-12-17 13:02:59 +01007023 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01007024 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007025 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01007026 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01007027 }
7028
7029 signal(SIGQUIT, dump);
7030 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007031 signal(SIGHUP, sig_dump_state);
willy tarreau12350152005-12-18 01:03:27 +01007032 signal(SIGINT, sig_int);
7033 signal(SIGTERM, sig_term);
willy tarreau0f7af912005-12-17 12:21:26 +01007034
7035 /* on very high loads, a sigpipe sometimes happen just between the
7036 * getsockopt() which tells "it's OK to write", and the following write :-(
7037 */
willy tarreau3242e862005-12-17 12:27:53 +01007038#ifndef MSG_NOSIGNAL
7039 signal(SIGPIPE, SIG_IGN);
7040#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007041
7042 if (start_proxies() < 0)
7043 exit(1);
7044
willy tarreaufe2c5c12005-12-17 14:14:34 +01007045 /* open log & pid files before the chroot */
7046 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7047 int pidfd;
7048 unlink(global.pidfile);
7049 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7050 if (pidfd < 0) {
7051 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7052 exit(1);
7053 }
7054 pidfile = fdopen(pidfd, "w");
7055 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007056
7057 /* chroot if needed */
7058 if (global.chroot != NULL) {
7059 if (chroot(global.chroot) == -1) {
7060 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7061 exit(1);
7062 }
7063 chdir("/");
7064 }
7065
7066 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007067 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007068 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7069 exit(1);
7070 }
7071
willy tarreau036e1ce2005-12-17 13:46:33 +01007072 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007073 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7074 exit(1);
7075 }
7076
7077 if (global.mode & MODE_DAEMON) {
7078 int ret = 0;
7079 int proc;
7080
7081 /* the father launches the required number of processes */
7082 for (proc = 0; proc < global.nbproc; proc++) {
7083 ret = fork();
7084 if (ret < 0) {
7085 Alert("[%s.main()] Cannot fork.\n", argv[0]);
7086 exit(1); /* there has been an error */
7087 }
7088 else if (ret == 0) /* child breaks here */
7089 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007090 if (pidfile != NULL) {
7091 fprintf(pidfile, "%d\n", ret);
7092 fflush(pidfile);
7093 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007094 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007095 /* close the pidfile both in children and father */
7096 if (pidfile != NULL)
7097 fclose(pidfile);
7098 free(global.pidfile);
7099
willy tarreau9fe663a2005-12-17 13:02:59 +01007100 if (proc == global.nbproc)
7101 exit(0); /* parent must leave */
7102
willy tarreau750a4722005-12-17 13:21:24 +01007103 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
7104 * that we can detach from the TTY. We MUST NOT do it in other cases since
7105 * it would have already be done, and 0-2 would have been affected to listening
7106 * sockets
7107 */
7108 if (!(global.mode & MODE_QUIET)) {
7109 /* detach from the tty */
7110 fclose(stdin); fclose(stdout); fclose(stderr);
7111 close(0); close(1); close(2); /* close all fd's */
7112 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
7113 }
willy tarreaua1598082005-12-17 13:08:06 +01007114 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01007115 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01007116 }
7117
willy tarreau0f7af912005-12-17 12:21:26 +01007118 select_loop();
7119
willy tarreau12350152005-12-18 01:03:27 +01007120 /* Free all Hash Keys and all Hash elements */
7121 appsession_cleanup();
7122 /* Do some cleanup */
7123 deinit();
7124
willy tarreau0f7af912005-12-17 12:21:26 +01007125 exit(0);
7126}
willy tarreau12350152005-12-18 01:03:27 +01007127
7128#if defined(DEBUG_HASH)
7129static void print_table(const CHTbl *htbl) {
7130
7131 ListElmt *element;
7132 int i;
7133 appsess *asession;
7134
7135 /*****************************************************************************
7136 * *
7137 * Display the chained hash table. *
7138 * *
7139 *****************************************************************************/
7140
7141 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
7142
7143 for (i = 0; i < TBLSIZ; i++) {
7144 fprintf(stdout, "Bucket[%03d]\n", i);
7145
7146 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
7147 //fprintf(stdout, "%c", *(char *)list_data(element));
7148 asession = (appsess *)list_data(element);
7149 fprintf(stdout, "ELEM :%s:", asession->sessid);
7150 fprintf(stdout, " Server :%s: \n", asession->serverid);
7151 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
7152 }
7153
7154 fprintf(stdout, "\n");
7155 }
7156 return;
7157} /* end print_table */
7158#endif
7159
7160static int appsession_init(void)
7161{
7162 static int initialized = 0;
7163 int idlen;
7164 struct server *s;
7165 struct proxy *p = proxy;
7166
7167 if (!initialized) {
7168 if (!appsession_task_init()) {
7169 apools.sessid = NULL;
7170 apools.serverid = NULL;
7171 apools.ser_waste = 0;
7172 apools.ser_use = 0;
7173 apools.ser_msize = sizeof(void *);
7174 apools.ses_waste = 0;
7175 apools.ses_use = 0;
7176 apools.ses_msize = sizeof(void *);
7177 while (p) {
7178 s = p->srv;
7179 if (apools.ses_msize < p->appsession_len)
7180 apools.ses_msize = p->appsession_len;
7181 while (s) {
7182 idlen = strlen(s->id);
7183 if (apools.ser_msize < idlen)
7184 apools.ser_msize = idlen;
7185 s = s->next;
7186 }
7187 p = p->next;
7188 }
7189 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
7190 apools.ses_msize ++;
7191 }
7192 else {
7193 fprintf(stderr, "appsession_task_init failed\n");
7194 return -1;
7195 }
7196 initialized ++;
7197 }
7198 return 0;
7199}
7200
7201static int appsession_task_init(void)
7202{
7203 static int initialized = 0;
7204 struct task *t;
7205 if (!initialized) {
7206 if ((t = pool_alloc(task)) == NULL)
7207 return -1;
7208 t->next = t->prev = t->rqnext = NULL;
7209 t->wq = LIST_HEAD(wait_queue);
7210 t->state = TASK_IDLE;
7211 t->context = NULL;
7212 tv_delayfrom(&t->expire, &now, TBLCHKINT);
7213 task_queue(t);
7214 t->process = appsession_refresh;
7215 initialized ++;
7216 }
7217 return 0;
7218}
7219
7220static int appsession_refresh(struct task *t) {
7221 struct proxy *p = proxy;
7222 CHTbl *htbl;
7223 ListElmt *element, *last;
7224 int i;
7225 appsess *asession;
7226 void *data;
7227
7228 while (p) {
7229 if (p->appsession_name != NULL) {
7230 htbl = &p->htbl_proxy;
7231 /* if we ever give up the use of TBLSIZ, we need to change this */
7232 for (i = 0; i < TBLSIZ; i++) {
7233 last = NULL;
7234 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
7235 asession = (appsess *)list_data(element);
7236 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
7237 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
7238 int len;
7239 /*
7240 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
7241 */
7242 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
7243 asession->sessid, asession->serverid?asession->serverid:"(null)");
7244 write(1, trash, len);
7245 }
7246 /* delete the expired element from within the hash table */
7247 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
7248 && (htbl->table[i].destroy != NULL)) {
7249 htbl->table[i].destroy(data);
7250 }
7251 if (last == NULL) {/* patient lost his head, get a new one */
7252 element = list_head(&htbl->table[i]);
7253 if (element == NULL) break; /* no heads left, go to next patient */
7254 }
7255 else
7256 element = last;
7257 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
7258 else
7259 last = element;
7260 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
7261 }
7262 }
7263 p = p->next;
7264 }
7265 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
7266 return TBLCHKINT;
7267} /* end appsession_refresh */
7268