blob: daf6bbeaa95f5d66b9368f01c8bd6e02b99b00e9 [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 tarreau726618c2006-01-29 22:42:06 +01003 * 2000-2006 - 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 tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
willy tarreau0f7af912005-12-17 12:21:26 +010055#include <syslog.h>
willy tarreau77bc8542005-12-18 01:31:43 +010056
57#ifdef USE_PCRE
58#include <pcre.h>
59#include <pcreposix.h>
60#else
61#include <regex.h>
62#endif
63
willy tarreaua1598082005-12-17 13:08:06 +010064#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010065#include <linux/netfilter_ipv4.h>
66#endif
willy tarreau0f7af912005-12-17 12:21:26 +010067
willy tarreau12350152005-12-18 01:03:27 +010068#if defined(__dietlibc__)
69#include <strings.h>
70#endif
71
willy tarreau1c2ad212005-12-18 01:11:29 +010072#if defined(ENABLE_POLL)
73#include <sys/poll.h>
74#endif
75
76#if defined(ENABLE_EPOLL)
77#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010078#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010079#else
80#include "include/epoll.h"
81#endif
82#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010083
willy tarreau779dc892006-03-19 19:32:29 +010084#ifdef DEBUG_FULL
85#include <assert.h>
86#endif
87
willy tarreau598da412005-12-18 01:07:29 +010088#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010089
willy tarreaubfad5742006-03-23 14:19:11 +010090#ifndef HAPROXY_VERSION
91#define HAPROXY_VERSION "1.2.10.1"
92#endif
93
94#ifndef HAPROXY_DATE
95#define HAPROXY_DATE "2006/03/23"
96#endif
willy tarreau0f7af912005-12-17 12:21:26 +010097
98/* this is for libc5 for example */
99#ifndef TCP_NODELAY
100#define TCP_NODELAY 1
101#endif
102
103#ifndef SHUT_RD
104#define SHUT_RD 0
105#endif
106
107#ifndef SHUT_WR
108#define SHUT_WR 1
109#endif
110
willy tarreau0174f312005-12-18 01:02:42 +0100111/*
112 * BUFSIZE defines the size of a read and write buffer. It is the maximum
113 * amount of bytes which can be stored by the proxy for each session. However,
114 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
115 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
116 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
117 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
118 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
119 */
120#ifndef BUFSIZE
121#define BUFSIZE 16384
122#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100123
124// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100125#ifndef MAXREWRITE
126#define MAXREWRITE (BUFSIZE / 2)
127#endif
128
willy tarreau9fe663a2005-12-17 13:02:59 +0100129#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100130#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100131
willy tarreau5cbea6f2005-12-17 12:48:26 +0100132// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100133#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100134
willy tarreaue39cd132005-12-17 13:00:18 +0100135// max # of added headers per request
136#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100137
138// max # of matches per regexp
139#define MAX_MATCH 10
140
willy tarreau0174f312005-12-18 01:02:42 +0100141// cookie delimitor in "prefix" mode. This character is inserted between the
142// persistence cookie and the original value. The '~' is allowed by RFC2965,
143// and should not be too common in server names.
144#ifndef COOKIE_DELIM
145#define COOKIE_DELIM '~'
146#endif
147
willy tarreau0f7af912005-12-17 12:21:26 +0100148#define CONN_RETRIES 3
149
willy tarreau5cbea6f2005-12-17 12:48:26 +0100150#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100151#define DEF_CHKINTR 2000
152#define DEF_FALLTIME 3
153#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100154#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100155
Willy TARREAU13032e72006-03-12 17:31:45 +0100156/* Default connections limit.
157 *
158 * A system limit can be enforced at build time in order to avoid using haproxy
159 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
160 * absolute limit accepted by the system. If the configuration specifies a
161 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
162 * emitted. The only way to override this limit will be to set it via the
163 * command-line '-n' argument.
164 */
165#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100166#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100167#else
168#define DEFAULT_MAXCONN SYSTEM_MAXCONN
169#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100170
willy tarreau0f7af912005-12-17 12:21:26 +0100171/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
172#define INTBITS 5
173
174/* show stats this every millisecond, 0 to disable */
175#ifndef STATTIME
176#define STATTIME 2000
177#endif
178
willy tarreau5cbea6f2005-12-17 12:48:26 +0100179/* this reduces the number of calls to select() by choosing appropriate
180 * sheduler precision in milliseconds. It should be near the minimum
181 * time that is needed by select() to collect all events. All timeouts
182 * are rounded up by adding this value prior to pass it to select().
183 */
184#define SCHEDULER_RESOLUTION 9
185
willy tarreaub952e1d2005-12-18 01:31:20 +0100186#define TIME_ETERNITY -1
187/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100188#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
189#define SETNOW(a) (*a=now)
190
willy tarreau9da061b2005-12-17 12:29:56 +0100191/****** string-specific macros and functions ******/
192/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
193#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
194
195/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
196#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
197
willy tarreau0174f312005-12-18 01:02:42 +0100198/* returns 1 only if only zero or one bit is set in X, which means that X is a
199 * power of 2, and 0 otherwise */
200#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100201/*
202 * copies at most <size-1> chars from <src> to <dst>. Last char is always
203 * set to 0, unless <size> is 0. The number of chars copied is returned
204 * (excluding the terminating zero).
205 * This code has been optimized for size and speed : on x86, it's 45 bytes
206 * long, uses only registers, and consumes only 4 cycles per char.
207 */
willy tarreau750a4722005-12-17 13:21:24 +0100208int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100209 char *orig = dst;
210 if (size) {
211 while (--size && (*dst = *src)) {
212 src++; dst++;
213 }
214 *dst = 0;
215 }
216 return dst - orig;
217}
willy tarreau9da061b2005-12-17 12:29:56 +0100218
willy tarreau4302f492005-12-18 01:00:37 +0100219/*
220 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
221 * dynamically allocated. In the first case, <__pool> is updated to point to
222 * the next element in the list.
223 */
224#define pool_alloc_from(__pool, __len) ({ \
225 void *__p; \
226 if ((__p = (__pool)) == NULL) \
227 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
228 else { \
229 __pool = *(void **)(__pool); \
230 } \
231 __p; \
232})
233
234/*
235 * Puts a memory area back to the corresponding pool.
236 * Items are chained directly through a pointer that
237 * is written in the beginning of the memory area, so
238 * there's no need for any carrier cell. This implies
239 * that each memory area is at least as big as one
240 * pointer.
241 */
242#define pool_free_to(__pool, __ptr) ({ \
243 *(void **)(__ptr) = (void *)(__pool); \
244 __pool = (void *)(__ptr); \
245})
246
247
willy tarreau0f7af912005-12-17 12:21:26 +0100248#define MEM_OPTIM
249#ifdef MEM_OPTIM
250/*
251 * Returns a pointer to type <type> taken from the
252 * pool <pool_type> or dynamically allocated. In the
253 * first case, <pool_type> is updated to point to the
254 * next element in the list.
255 */
256#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100257 void *__p; \
258 if ((__p = pool_##type) == NULL) \
259 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100260 else { \
261 pool_##type = *(void **)pool_##type; \
262 } \
willy tarreau4302f492005-12-18 01:00:37 +0100263 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100264})
265
266/*
267 * Puts a memory area back to the corresponding pool.
268 * Items are chained directly through a pointer that
269 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100270 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100271 * that each memory area is at least as big as one
272 * pointer.
273 */
274#define pool_free(type, ptr) ({ \
275 *(void **)ptr = (void *)pool_##type; \
276 pool_##type = (void *)ptr; \
277})
278
279#else
280#define pool_alloc(type) (calloc(1,sizeof_##type));
281#define pool_free(type, ptr) (free(ptr));
282#endif /* MEM_OPTIM */
283
willy tarreau5cbea6f2005-12-17 12:48:26 +0100284#define sizeof_task sizeof(struct task)
285#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100286#define sizeof_buffer sizeof(struct buffer)
287#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100288#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100289#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100290#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100291#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100292
willy tarreau5cbea6f2005-12-17 12:48:26 +0100293/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100294#define FD_STCLOSE 0
295#define FD_STLISTEN 1
296#define FD_STCONN 2
297#define FD_STREADY 3
298#define FD_STERROR 4
299
willy tarreau5cbea6f2005-12-17 12:48:26 +0100300/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100301#define TASK_IDLE 0
302#define TASK_RUNNING 1
303
willy tarreau5cbea6f2005-12-17 12:48:26 +0100304/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100305#define PR_STNEW 0
306#define PR_STIDLE 1
307#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100308#define PR_STSTOPPED 3
309#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100310
willy tarreau5cbea6f2005-12-17 12:48:26 +0100311/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100312#define PR_MODE_TCP 0
313#define PR_MODE_HTTP 1
314#define PR_MODE_HEALTH 2
315
willy tarreau1c2ad212005-12-18 01:11:29 +0100316/* possible actions for the *poll() loops */
317#define POLL_LOOP_ACTION_INIT 0
318#define POLL_LOOP_ACTION_RUN 1
319#define POLL_LOOP_ACTION_CLEAN 2
320
willy tarreau64a3cc32005-12-18 01:13:11 +0100321/* poll mechanisms available */
322#define POLL_USE_SELECT (1<<0)
323#define POLL_USE_POLL (1<<1)
324#define POLL_USE_EPOLL (1<<2)
325
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100327#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
328#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
329#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
330#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
331#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
332#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
333#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
334#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100335#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
336#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
337#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
338#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
339#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
340#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
341#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
342#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
343#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
344#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
345#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100346#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
347#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100348#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100349#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100350#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
351#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100352
willy tarreaue39cd132005-12-17 13:00:18 +0100353/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100354#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
355#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
356#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
357#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
358#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
359#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100360#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100361
362#define SN_CK_NONE 0x00000000 /* this session had no cookie */
363#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
364#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
365#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
366#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
367#define SN_CK_SHIFT 6 /* bit shift */
368
willy tarreaub1285d52005-12-18 01:20:14 +0100369#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100370#define SN_ERR_CLITO 0x00000100 /* client time-out */
371#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
372#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
373#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
374#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100375#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
376#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100377#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
378#define SN_ERR_SHIFT 8 /* bit shift */
379
380#define SN_FINST_R 0x00001000 /* session ended during client request */
381#define SN_FINST_C 0x00002000 /* session ended during server connect */
382#define SN_FINST_H 0x00003000 /* session ended during server headers */
383#define SN_FINST_D 0x00004000 /* session ended during data phase */
384#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
385#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
386#define SN_FINST_SHIFT 12 /* bit shift */
387
388#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
389#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
390#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
391#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
392#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100393#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100394#define SN_SCK_SHIFT 16 /* bit shift */
395
willy tarreau97f58572005-12-18 00:53:44 +0100396#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
397#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
398#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100399
400/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100401#define CL_STHEADERS 0
402#define CL_STDATA 1
403#define CL_STSHUTR 2
404#define CL_STSHUTW 3
405#define CL_STCLOSE 4
406
willy tarreau5cbea6f2005-12-17 12:48:26 +0100407/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100408#define SV_STIDLE 0
409#define SV_STCONN 1
410#define SV_STHEADERS 2
411#define SV_STDATA 3
412#define SV_STSHUTR 4
413#define SV_STSHUTW 5
414#define SV_STCLOSE 6
415
416/* result of an I/O event */
417#define RES_SILENT 0 /* didn't happen */
418#define RES_DATA 1 /* data were sent or received */
419#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
420#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
421
willy tarreau9fe663a2005-12-17 13:02:59 +0100422/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100423#define MODE_DEBUG 1
424#define MODE_STATS 2
425#define MODE_LOG 4
426#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100427#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100428#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100429#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100430#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100431#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100432
433/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100434#define SRV_RUNNING 1 /* the server is UP */
435#define SRV_BACKUP 2 /* this server is a backup server */
436#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100437#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100438#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100439
willy tarreaue39cd132005-12-17 13:00:18 +0100440/* what to do when a header matches a regex */
441#define ACT_ALLOW 0 /* allow the request */
442#define ACT_REPLACE 1 /* replace the matching header */
443#define ACT_REMOVE 2 /* remove the matching header */
444#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100445#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100446
willy tarreau9fe663a2005-12-17 13:02:59 +0100447/* configuration sections */
448#define CFG_NONE 0
449#define CFG_GLOBAL 1
450#define CFG_LISTEN 2
451
willy tarreaua1598082005-12-17 13:08:06 +0100452/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100453#define LW_DATE 1 /* date */
454#define LW_CLIP 2 /* CLient IP */
455#define LW_SVIP 4 /* SerVer IP */
456#define LW_SVID 8 /* server ID */
457#define LW_REQ 16 /* http REQuest */
458#define LW_RESP 32 /* http RESPonse */
459#define LW_PXIP 64 /* proxy IP */
460#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100461#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100462#define LW_COOKIE 512 /* captured cookie */
463#define LW_REQHDR 1024 /* request header(s) */
464#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100465
willy tarreau41310e72006-03-25 18:17:56 +0100466#define ERR_NONE 0 /* no error */
467#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
468#define ERR_FATAL 2 /* fatal error, may be cumulated */
469
willy tarreau0f7af912005-12-17 12:21:26 +0100470/*********************************************************************/
471
472#define LIST_HEAD(a) ((void *)(&(a)))
473
474/*********************************************************************/
475
willy tarreau4302f492005-12-18 01:00:37 +0100476struct cap_hdr {
477 struct cap_hdr *next;
478 char *name; /* header name, case insensitive */
479 int namelen; /* length of the header name, to speed-up lookups */
480 int len; /* capture length, not including terminal zero */
481 int index; /* index in the output array */
482 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
483};
484
willy tarreau0f7af912005-12-17 12:21:26 +0100485struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100486 struct hdr_exp *next;
487 regex_t *preg; /* expression to look for */
488 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
489 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100490};
491
492struct buffer {
493 unsigned int l; /* data length */
494 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100495 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100496 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100497 char data[BUFSIZE];
498};
499
500struct server {
501 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100502 int state; /* server state (SRV_*) */
503 int cklen; /* the len of the cookie, to speed up checks */
504 char *cookie; /* the id set in the cookie */
505 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100506 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100507 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100508 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100509 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100510 int rise, fall; /* time in iterations */
511 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100512 int result; /* 0 = connect OK, -1 = connect KO */
513 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100514 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100515};
516
willy tarreau5cbea6f2005-12-17 12:48:26 +0100517/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100518struct task {
519 struct task *next, *prev; /* chaining ... */
520 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100521 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100522 int state; /* task state : IDLE or RUNNING */
523 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100524 int (*process)(struct task *t); /* the function which processes the task */
525 void *context; /* the task's context */
526};
527
528/* WARNING: if new fields are added, they must be initialized in event_accept() */
529struct session {
530 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100531 /* application specific below */
532 struct timeval crexpire; /* expiration date for a client read */
533 struct timeval cwexpire; /* expiration date for a client write */
534 struct timeval srexpire; /* expiration date for a server read */
535 struct timeval swexpire; /* expiration date for a server write */
536 struct timeval cnexpire; /* expiration date for a connect */
537 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
538 struct proxy *proxy; /* the proxy this socket belongs to */
539 int cli_fd; /* the client side fd */
540 int srv_fd; /* the server side fd */
541 int cli_state; /* state of the client side */
542 int srv_state; /* state of the server side */
543 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100544 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100545 struct buffer *req; /* request buffer */
546 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100547 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100548 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100549 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100550 char **req_cap; /* array of captured request headers (may be NULL) */
551 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100552 struct {
553 int logwait; /* log fields waiting to be collected : LW_* */
554 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
555 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
556 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
557 long t_data; /* delay before the first data byte from the server ... */
558 unsigned long t_close; /* total session duration */
559 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100560 char *cli_cookie; /* cookie presented by the client, in capture mode */
561 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100562 int status; /* HTTP status from the server, negative if from proxy */
563 long long bytes; /* number of bytes transferred from the server */
564 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100565 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100566};
567
willy tarreaua41a8b42005-12-17 14:02:24 +0100568struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100569 int fd; /* the listen socket */
570 struct sockaddr_storage addr; /* the address we listen to */
571 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100572};
573
574
willy tarreau0f7af912005-12-17 12:21:26 +0100575struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100576 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100577 struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */
willy tarreau0f7af912005-12-17 12:21:26 +0100578 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100579 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100580 struct server *srv, *cursrv; /* known servers, current server */
willy tarreau62084d42006-03-24 18:57:41 +0100581 int srv_act, srv_bck; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100582 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100583 int cookie_len; /* strlen(cookie_name), computed only once */
584 char *appsession_name; /* name of the cookie to look for */
585 int appsession_name_len; /* strlen(appsession_name), computed only once */
586 int appsession_len; /* length of the appsession cookie value to be used */
587 int appsession_timeout;
588 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100589 char *capture_name; /* beginning of the name of the cookie to capture */
590 int capture_namelen; /* length of the cookie name to match */
591 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100592 int clitimeout; /* client I/O timeout (in milliseconds) */
593 int srvtimeout; /* server I/O timeout (in milliseconds) */
594 int contimeout; /* connect timeout (in milliseconds) */
595 char *id; /* proxy id */
596 int nbconn; /* # of active sessions */
597 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100598 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100599 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100600 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100601 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100602 struct proxy *next;
603 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100604 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100605 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100606 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100607 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100608 int nb_reqadd, nb_rspadd;
609 struct hdr_exp *req_exp; /* regular expressions for request headers */
610 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100611 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
612 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
613 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
614 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100615 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100616 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100617 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
618 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100619 struct {
620 char *msg400; /* message for error 400 */
621 int len400; /* message length for error 400 */
622 char *msg403; /* message for error 403 */
623 int len403; /* message length for error 403 */
624 char *msg408; /* message for error 408 */
625 int len408; /* message length for error 408 */
626 char *msg500; /* message for error 500 */
627 int len500; /* message length for error 500 */
628 char *msg502; /* message for error 502 */
629 int len502; /* message length for error 502 */
630 char *msg503; /* message for error 503 */
631 int len503; /* message length for error 503 */
632 char *msg504; /* message for error 504 */
633 int len504; /* message length for error 504 */
634 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100635};
636
637/* info about one given fd */
638struct fdtab {
639 int (*read)(int fd); /* read function */
640 int (*write)(int fd); /* write function */
641 struct task *owner; /* the session (or proxy) associated with this fd */
642 int state; /* the state of this fd */
643};
644
645/*********************************************************************/
646
willy tarreaub952e1d2005-12-18 01:31:20 +0100647int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100648int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100649char *cfg_cfgfile = NULL; /* configuration file */
650char *progname = NULL; /* program name */
651int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100652
653/* global options */
654static struct {
655 int uid;
656 int gid;
657 int nbproc;
658 int maxconn;
659 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100660 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100661 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100662 int mode;
663 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100664 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100665 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100666 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100667 struct sockaddr_in logsrv1, logsrv2;
668} global = {
669 logfac1 : -1,
670 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100671 loglev1 : 7, /* max syslog level : debug */
672 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100673 /* others NULL OK */
674};
675
willy tarreau0f7af912005-12-17 12:21:26 +0100676/*********************************************************************/
677
willy tarreau1c2ad212005-12-18 01:11:29 +0100678fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100679 *StaticWriteEvent;
680
willy tarreau64a3cc32005-12-18 01:13:11 +0100681int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100682
willy tarreau0f7af912005-12-17 12:21:26 +0100683void **pool_session = NULL,
684 **pool_buffer = NULL,
685 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100686 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100687 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100688 **pool_capture = NULL,
689 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100690
691struct proxy *proxy = NULL; /* list of all existing proxies */
692struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100693struct task *rq = NULL; /* global run queue */
694struct task wait_queue = { /* global wait queue */
695 prev:LIST_HEAD(wait_queue),
696 next:LIST_HEAD(wait_queue)
697};
willy tarreau0f7af912005-12-17 12:21:26 +0100698
willy tarreau0f7af912005-12-17 12:21:26 +0100699static int totalconn = 0; /* total # of terminated sessions */
700static int actconn = 0; /* # of active sessions */
701static int maxfd = 0; /* # of the highest fd + 1 */
702static int listeners = 0; /* # of listeners */
703static int stopping = 0; /* non zero means stopping in progress */
704static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100705static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100706
willy tarreau53e99702006-03-25 18:53:50 +0100707/* Here we store informations about the pids of the processes we may pause
708 * or kill. We will send them a signal every 10 ms until we can bind to all
709 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100710 */
willy tarreau53e99702006-03-25 18:53:50 +0100711#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100712static int nb_oldpids = 0;
713static int *oldpids = NULL;
714static int oldpids_sig; /* use USR1 or TERM */
715
willy tarreau08dedbe2005-12-18 01:13:48 +0100716#if defined(ENABLE_EPOLL)
717/* FIXME: this is dirty, but at the moment, there's no other solution to remove
718 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
719 * structure with pointers to functions such as init_fd() and close_fd(), plus
720 * a private structure with several pointers to places such as below.
721 */
722
723static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
724#endif
725
willy tarreau0f7af912005-12-17 12:21:26 +0100726static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100727/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100728static char trash[BUFSIZE];
729
willy tarreaudd07e972005-12-18 00:48:48 +0100730const int zero = 0;
731const int one = 1;
732
willy tarreau0f7af912005-12-17 12:21:26 +0100733/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100734 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100735 */
736
737#define MAX_SYSLOG_LEN 1024
738#define NB_LOG_FACILITIES 24
739const char *log_facilities[NB_LOG_FACILITIES] = {
740 "kern", "user", "mail", "daemon",
741 "auth", "syslog", "lpr", "news",
742 "uucp", "cron", "auth2", "ftp",
743 "ntp", "audit", "alert", "cron2",
744 "local0", "local1", "local2", "local3",
745 "local4", "local5", "local6", "local7"
746};
747
748
749#define NB_LOG_LEVELS 8
750const char *log_levels[NB_LOG_LEVELS] = {
751 "emerg", "alert", "crit", "err",
752 "warning", "notice", "info", "debug"
753};
754
755#define SYSLOG_PORT 514
756
757const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
758 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100759
willy tarreaub1285d52005-12-18 01:20:14 +0100760const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100761const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
762const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
763const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
764 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
765 unknown, Set-cookie Rewritten */
766
willy tarreau0f7af912005-12-17 12:21:26 +0100767#define MAX_HOSTNAME_LEN 32
768static char hostname[MAX_HOSTNAME_LEN] = "";
769
willy tarreau8337c6b2005-12-17 13:41:01 +0100770const char *HTTP_302 =
771 "HTTP/1.0 302 Found\r\n"
772 "Cache-Control: no-cache\r\n"
773 "Connection: close\r\n"
774 "Location: "; /* not terminated since it will be concatenated with the URL */
775
willy tarreauc1f47532005-12-18 01:08:26 +0100776/* same as 302 except that the browser MUST retry with the GET method */
777const char *HTTP_303 =
778 "HTTP/1.0 303 See Other\r\n"
779 "Cache-Control: no-cache\r\n"
780 "Connection: close\r\n"
781 "Location: "; /* not terminated since it will be concatenated with the URL */
782
willy tarreaua1598082005-12-17 13:08:06 +0100783const char *HTTP_400 =
784 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100785 "Cache-Control: no-cache\r\n"
786 "Connection: close\r\n"
787 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100788 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100789
willy tarreaua1598082005-12-17 13:08:06 +0100790const char *HTTP_403 =
791 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100792 "Cache-Control: no-cache\r\n"
793 "Connection: close\r\n"
794 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100795 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
796
willy tarreau8337c6b2005-12-17 13:41:01 +0100797const char *HTTP_408 =
798 "HTTP/1.0 408 Request Time-out\r\n"
799 "Cache-Control: no-cache\r\n"
800 "Connection: close\r\n"
801 "\r\n"
802 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
803
willy tarreau750a4722005-12-17 13:21:24 +0100804const char *HTTP_500 =
805 "HTTP/1.0 500 Server Error\r\n"
806 "Cache-Control: no-cache\r\n"
807 "Connection: close\r\n"
808 "\r\n"
809 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100810
811const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100812 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100813 "Cache-Control: no-cache\r\n"
814 "Connection: close\r\n"
815 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100816 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
817
818const char *HTTP_503 =
819 "HTTP/1.0 503 Service Unavailable\r\n"
820 "Cache-Control: no-cache\r\n"
821 "Connection: close\r\n"
822 "\r\n"
823 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
824
825const char *HTTP_504 =
826 "HTTP/1.0 504 Gateway Time-out\r\n"
827 "Cache-Control: no-cache\r\n"
828 "Connection: close\r\n"
829 "\r\n"
830 "<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 +0100831
willy tarreau0f7af912005-12-17 12:21:26 +0100832/*********************************************************************/
833/* statistics ******************************************************/
834/*********************************************************************/
835
willy tarreau750a4722005-12-17 13:21:24 +0100836#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100837static int stats_tsk_lsrch, stats_tsk_rsrch,
838 stats_tsk_good, stats_tsk_right, stats_tsk_left,
839 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100840#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100841
842
843/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100844/* debugging *******************************************************/
845/*********************************************************************/
846#ifdef DEBUG_FULL
847static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
848static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
849#endif
850
851/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100852/* function prototypes *********************************************/
853/*********************************************************************/
854
855int event_accept(int fd);
856int event_cli_read(int fd);
857int event_cli_write(int fd);
858int event_srv_read(int fd);
859int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100860int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100861
willy tarreau12350152005-12-18 01:03:27 +0100862static int appsession_task_init(void);
863static int appsession_init(void);
864static int appsession_refresh(struct task *t);
865
willy tarreau0f7af912005-12-17 12:21:26 +0100866/*********************************************************************/
867/* general purpose functions ***************************************/
868/*********************************************************************/
869
870void display_version() {
871 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100872 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100873}
874
875/*
876 * This function prints the command line usage and exits
877 */
878void usage(char *name) {
879 display_version();
880 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100881 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100882#if STATTIME > 0
883 "sl"
884#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100885 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
886 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100887 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100888 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100889 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100890#if STATTIME > 0
891 " -s enables statistics output\n"
892 " -l enables long statistics format\n"
893#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100894 " -D goes daemon ; implies -q\n"
895 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100896 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100897 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100898 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100899 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100900 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100901#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100902 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100903#endif
904#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100905 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100906#endif
willy tarreau53e99702006-03-25 18:53:50 +0100907 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100908 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100909 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100910 exit(1);
911}
912
913
914/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100915 * Displays the message on stderr with the date and pid. Overrides the quiet
916 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100917 */
918void Alert(char *fmt, ...) {
919 va_list argp;
920 struct timeval tv;
921 struct tm *tm;
922
willy tarreaud0fb4652005-12-18 01:32:04 +0100923 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100924 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100925
willy tarreau5cbea6f2005-12-17 12:48:26 +0100926 gettimeofday(&tv, NULL);
927 tm=localtime(&tv.tv_sec);
928 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100929 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100930 vfprintf(stderr, fmt, argp);
931 fflush(stderr);
932 va_end(argp);
933 }
willy tarreau0f7af912005-12-17 12:21:26 +0100934}
935
936
937/*
938 * Displays the message on stderr with the date and pid.
939 */
940void Warning(char *fmt, ...) {
941 va_list argp;
942 struct timeval tv;
943 struct tm *tm;
944
willy tarreau982249e2005-12-18 00:57:06 +0100945 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100946 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100947
willy tarreau5cbea6f2005-12-17 12:48:26 +0100948 gettimeofday(&tv, NULL);
949 tm=localtime(&tv.tv_sec);
950 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100951 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100952 vfprintf(stderr, fmt, argp);
953 fflush(stderr);
954 va_end(argp);
955 }
956}
957
958/*
959 * Displays the message on <out> only if quiet mode is not set.
960 */
961void qfprintf(FILE *out, char *fmt, ...) {
962 va_list argp;
963
willy tarreau982249e2005-12-18 00:57:06 +0100964 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100965 va_start(argp, fmt);
966 vfprintf(out, fmt, argp);
967 fflush(out);
968 va_end(argp);
969 }
willy tarreau0f7af912005-12-17 12:21:26 +0100970}
971
972
973/*
974 * converts <str> to a struct sockaddr_in* which is locally allocated.
975 * The format is "addr:port", where "addr" can be empty or "*" to indicate
976 * INADDR_ANY.
977 */
978struct sockaddr_in *str2sa(char *str) {
979 static struct sockaddr_in sa;
980 char *c;
981 int port;
982
willy tarreaua1598082005-12-17 13:08:06 +0100983 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100984 str=strdup(str);
985
986 if ((c=strrchr(str,':')) != NULL) {
987 *c++=0;
988 port=atol(c);
989 }
990 else
991 port=0;
992
993 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
994 sa.sin_addr.s_addr = INADDR_ANY;
995 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100996 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100997 struct hostent *he;
998
999 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001000 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001001 }
1002 else
1003 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1004 }
1005 sa.sin_port=htons(port);
1006 sa.sin_family=AF_INET;
1007
1008 free(str);
1009 return &sa;
1010}
1011
willy tarreaub1285d52005-12-18 01:20:14 +01001012/*
1013 * converts <str> to a two struct in_addr* which are locally allocated.
1014 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1015 * is optionnal and either in the dotted or CIDR notation.
1016 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1017 */
1018int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1019 char *c;
1020 unsigned long len;
1021
1022 memset(mask, 0, sizeof(*mask));
1023 memset(addr, 0, sizeof(*addr));
1024 str=strdup(str);
1025
1026 if ((c = strrchr(str, '/')) != NULL) {
1027 *c++ = 0;
1028 /* c points to the mask */
1029 if (strchr(c, '.') != NULL) { /* dotted notation */
1030 if (!inet_pton(AF_INET, c, mask))
1031 return 0;
1032 }
1033 else { /* mask length */
1034 char *err;
1035 len = strtol(c, &err, 10);
1036 if (!*c || (err && *err) || (unsigned)len > 32)
1037 return 0;
1038 if (len)
1039 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1040 else
1041 mask->s_addr = 0;
1042 }
1043 }
1044 else {
1045 mask->s_addr = 0xFFFFFFFF;
1046 }
1047 if (!inet_pton(AF_INET, str, addr)) {
1048 struct hostent *he;
1049
1050 if ((he = gethostbyname(str)) == NULL) {
1051 return 0;
1052 }
1053 else
1054 *addr = *(struct in_addr *) *(he->h_addr_list);
1055 }
1056 free(str);
1057 return 1;
1058}
1059
willy tarreau9fe663a2005-12-17 13:02:59 +01001060
1061/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001062 * converts <str> to a list of listeners which are dynamically allocated.
1063 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1064 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1065 * - <port> is a numerical port from 1 to 65535 ;
1066 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1067 * This can be repeated as many times as necessary, separated by a coma.
1068 * The <tail> argument is a pointer to a current list which should be appended
1069 * to the tail of the new list. The pointer to the new list is returned.
1070 */
1071struct listener *str2listener(char *str, struct listener *tail) {
1072 struct listener *l;
1073 char *c, *next, *range, *dupstr;
1074 int port, end;
1075
1076 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001077
willy tarreaua41a8b42005-12-17 14:02:24 +01001078 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001079 struct sockaddr_storage ss;
1080
willy tarreaua41a8b42005-12-17 14:02:24 +01001081 str = next;
1082 /* 1) look for the end of the first address */
1083 if ((next = strrchr(str, ',')) != NULL) {
1084 *next++ = 0;
1085 }
1086
willy tarreau8a86dbf2005-12-18 00:45:59 +01001087 /* 2) look for the addr/port delimiter, it's the last colon. */
1088 if ((range = strrchr(str, ':')) == NULL) {
1089 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001090 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001091 }
1092
1093 *range++ = 0;
1094
1095 if (strrchr(str, ':') != NULL) {
1096 /* IPv6 address contains ':' */
1097 memset(&ss, 0, sizeof(ss));
1098 ss.ss_family = AF_INET6;
1099
1100 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1101 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001102 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001103 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001104 }
1105 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001106 memset(&ss, 0, sizeof(ss));
1107 ss.ss_family = AF_INET;
1108
1109 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1110 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1111 }
1112 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1113 struct hostent *he;
1114
1115 if ((he = gethostbyname(str)) == NULL) {
1116 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001117 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001118 }
1119 else
1120 ((struct sockaddr_in *)&ss)->sin_addr =
1121 *(struct in_addr *) *(he->h_addr_list);
1122 }
1123 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001124
1125 /* 3) look for the port-end delimiter */
1126 if ((c = strchr(range, '-')) != NULL) {
1127 *c++ = 0;
1128 end = atol(c);
1129 }
1130 else {
1131 end = atol(range);
1132 }
1133
willy tarreaud0fb4652005-12-18 01:32:04 +01001134 port = atol(range);
1135
1136 if (port < 1 || port > 65535) {
1137 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1138 goto fail;
1139 }
1140
1141 if (end < 1 || end > 65535) {
1142 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1143 goto fail;
1144 }
1145
1146 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001147 l = (struct listener *)calloc(1, sizeof(struct listener));
1148 l->next = tail;
1149 tail = l;
1150
willy tarreau41310e72006-03-25 18:17:56 +01001151 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001152 l->addr = ss;
1153 if (ss.ss_family == AF_INET6)
1154 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1155 else
1156 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1157
willy tarreaua41a8b42005-12-17 14:02:24 +01001158 } /* end for(port) */
1159 } /* end while(next) */
1160 free(dupstr);
1161 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001162 fail:
1163 free(dupstr);
1164 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001165}
1166
willy tarreau4302f492005-12-18 01:00:37 +01001167
1168#define FD_SETS_ARE_BITFIELDS
1169#ifdef FD_SETS_ARE_BITFIELDS
1170/*
1171 * This map is used with all the FD_* macros to check whether a particular bit
1172 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1173 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1174 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1175 * exclusively to the macros.
1176 */
1177fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1178fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1179
1180#else
1181#error "Check if your OS uses bitfields for fd_sets"
1182#endif
1183
1184/* will try to encode the string <string> replacing all characters tagged in
1185 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1186 * prefixed by <escape>, and will store the result between <start> (included
1187 *) and <stop> (excluded), and will always terminate the string with a '\0'
1188 * before <stop>. The position of the '\0' is returned if the conversion
1189 * completes. If bytes are missing between <start> and <stop>, then the
1190 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1191 * cannot even be stored so we return <start> without writing the 0.
1192 * The input string must also be zero-terminated.
1193 */
1194char hextab[16] = "0123456789ABCDEF";
1195char *encode_string(char *start, char *stop,
1196 const char escape, const fd_set *map,
1197 const char *string)
1198{
1199 if (start < stop) {
1200 stop--; /* reserve one byte for the final '\0' */
1201 while (start < stop && *string != 0) {
1202 if (!FD_ISSET((unsigned char)(*string), map))
1203 *start++ = *string;
1204 else {
1205 if (start + 3 >= stop)
1206 break;
1207 *start++ = escape;
1208 *start++ = hextab[(*string >> 4) & 15];
1209 *start++ = hextab[*string & 15];
1210 }
1211 string++;
1212 }
1213 *start = '\0';
1214 }
1215 return start;
1216}
willy tarreaua41a8b42005-12-17 14:02:24 +01001217
1218/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001219 * This function sends a syslog message to both log servers of a proxy,
1220 * or to global log servers if the proxy is NULL.
1221 * It also tries not to waste too much time computing the message header.
1222 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001223 */
1224void send_log(struct proxy *p, int level, char *message, ...) {
1225 static int logfd = -1; /* syslog UDP socket */
1226 static long tvsec = -1; /* to force the string to be initialized */
1227 struct timeval tv;
1228 va_list argp;
1229 static char logmsg[MAX_SYSLOG_LEN];
1230 static char *dataptr = NULL;
1231 int fac_level;
1232 int hdr_len, data_len;
1233 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001234 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001235 int nbloggers = 0;
1236 char *log_ptr;
1237
1238 if (logfd < 0) {
1239 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1240 return;
1241 }
1242
1243 if (level < 0 || progname == NULL || message == NULL)
1244 return;
1245
1246 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001247 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001248 /* this string is rebuild only once a second */
1249 struct tm *tm = localtime(&tv.tv_sec);
1250 tvsec = tv.tv_sec;
1251
willy tarreauc29948c2005-12-17 13:10:27 +01001252 hdr_len = snprintf(logmsg, sizeof(logmsg),
1253 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1254 monthname[tm->tm_mon],
1255 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1256 progname, pid);
1257 /* WARNING: depending upon implementations, snprintf may return
1258 * either -1 or the number of bytes that would be needed to store
1259 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001260 */
willy tarreauc29948c2005-12-17 13:10:27 +01001261 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1262 hdr_len = sizeof(logmsg);
1263
1264 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001265 }
1266
1267 va_start(argp, message);
1268 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001269 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1270 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001271 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001272 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001273
1274 if (p == NULL) {
1275 if (global.logfac1 >= 0) {
1276 sa[nbloggers] = &global.logsrv1;
1277 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001278 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001279 nbloggers++;
1280 }
1281 if (global.logfac2 >= 0) {
1282 sa[nbloggers] = &global.logsrv2;
1283 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001284 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001285 nbloggers++;
1286 }
1287 } else {
1288 if (p->logfac1 >= 0) {
1289 sa[nbloggers] = &p->logsrv1;
1290 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001291 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001292 nbloggers++;
1293 }
1294 if (p->logfac2 >= 0) {
1295 sa[nbloggers] = &p->logsrv2;
1296 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001297 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001298 nbloggers++;
1299 }
1300 }
1301
1302 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001303 /* we can filter the level of the messages that are sent to each logger */
1304 if (level > loglevel[nbloggers])
1305 continue;
1306
willy tarreauc29948c2005-12-17 13:10:27 +01001307 /* For each target, we may have a different facility.
1308 * We can also have a different log level for each message.
1309 * This induces variations in the message header length.
1310 * Since we don't want to recompute it each time, nor copy it every
1311 * time, we only change the facility in the pre-computed header,
1312 * and we change the pointer to the header accordingly.
1313 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001314 fac_level = (facilities[nbloggers] << 3) + level;
1315 log_ptr = logmsg + 3; /* last digit of the log level */
1316 do {
1317 *log_ptr = '0' + fac_level % 10;
1318 fac_level /= 10;
1319 log_ptr--;
1320 } while (fac_level && log_ptr > logmsg);
1321 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001322
willy tarreauc29948c2005-12-17 13:10:27 +01001323 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001324
1325#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001326 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001327 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1328#else
willy tarreauc29948c2005-12-17 13:10:27 +01001329 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001330 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1331#endif
1332 }
willy tarreau0f7af912005-12-17 12:21:26 +01001333}
1334
1335
1336/* sets <tv> to the current time */
1337static inline struct timeval *tv_now(struct timeval *tv) {
1338 if (tv)
1339 gettimeofday(tv, NULL);
1340 return tv;
1341}
1342
1343/*
1344 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1345 */
1346static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1347 if (!tv || !from)
1348 return NULL;
1349 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1350 tv->tv_sec = from->tv_sec + (ms/1000);
1351 while (tv->tv_usec >= 1000000) {
1352 tv->tv_usec -= 1000000;
1353 tv->tv_sec++;
1354 }
1355 return tv;
1356}
1357
1358/*
1359 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001360 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001361 */
1362static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001363 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001364 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001365 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001366 return 1;
1367 else if (tv1->tv_usec < tv2->tv_usec)
1368 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001369 else if (tv1->tv_usec > tv2->tv_usec)
1370 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001371 else
1372 return 0;
1373}
1374
1375/*
1376 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001377 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001378 */
1379unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1380 int cmp;
1381 unsigned long ret;
1382
1383
willy tarreauef900ab2005-12-17 12:52:52 +01001384 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001385 if (!cmp)
1386 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001387 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001388 struct timeval *tmp = tv1;
1389 tv1 = tv2;
1390 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001391 }
willy tarreauef900ab2005-12-17 12:52:52 +01001392 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001393 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001394 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001395 else
willy tarreauef900ab2005-12-17 12:52:52 +01001396 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001397 return (unsigned long) ret;
1398}
1399
1400/*
willy tarreau750a4722005-12-17 13:21:24 +01001401 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001402 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001403 */
1404static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1405 unsigned long ret;
1406
willy tarreau6e682ce2005-12-17 13:26:49 +01001407 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1408 if (tv2->tv_usec > tv1->tv_usec)
1409 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001410 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001411 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001412 return (unsigned long) ret;
1413}
1414
1415/*
willy tarreau0f7af912005-12-17 12:21:26 +01001416 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001417 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001418 */
1419static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001420 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001421 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001422 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001423 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001424 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001425 else
1426 return 0;
1427 }
willy tarreau0f7af912005-12-17 12:21:26 +01001428 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001429 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001430 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001431 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001432 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001433 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001434 else
1435 return 0;
1436}
1437
1438/*
1439 * returns the remaining time between tv1=now and event=tv2
1440 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001441 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001442 */
1443static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1444 unsigned long ret;
1445
willy tarreau0f7af912005-12-17 12:21:26 +01001446 if (tv_cmp_ms(tv1, tv2) >= 0)
1447 return 0; /* event elapsed */
1448
willy tarreauef900ab2005-12-17 12:52:52 +01001449 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001450 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001451 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001452 else
willy tarreauef900ab2005-12-17 12:52:52 +01001453 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001454 return (unsigned long) ret;
1455}
1456
1457
1458/*
1459 * zeroes a struct timeval
1460 */
1461
1462static inline struct timeval *tv_eternity(struct timeval *tv) {
1463 tv->tv_sec = tv->tv_usec = 0;
1464 return tv;
1465}
1466
1467/*
1468 * returns 1 if tv is null, else 0
1469 */
1470static inline int tv_iseternity(struct timeval *tv) {
1471 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1472 return 1;
1473 else
1474 return 0;
1475}
1476
1477/*
1478 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1479 * considering that 0 is the eternity.
1480 */
1481static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1482 if (tv_iseternity(tv1))
1483 if (tv_iseternity(tv2))
1484 return 0; /* same */
1485 else
1486 return 1; /* tv1 later than tv2 */
1487 else if (tv_iseternity(tv2))
1488 return -1; /* tv2 later than tv1 */
1489
1490 if (tv1->tv_sec > tv2->tv_sec)
1491 return 1;
1492 else if (tv1->tv_sec < tv2->tv_sec)
1493 return -1;
1494 else if (tv1->tv_usec > tv2->tv_usec)
1495 return 1;
1496 else if (tv1->tv_usec < tv2->tv_usec)
1497 return -1;
1498 else
1499 return 0;
1500}
1501
1502/*
1503 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1504 * considering that 0 is the eternity.
1505 */
1506static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1507 if (tv_iseternity(tv1))
1508 if (tv_iseternity(tv2))
1509 return 0; /* same */
1510 else
1511 return 1; /* tv1 later than tv2 */
1512 else if (tv_iseternity(tv2))
1513 return -1; /* tv2 later than tv1 */
1514
willy tarreauefae1842005-12-17 12:51:03 +01001515 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001516 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001517 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001518 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001519 return -1;
1520 else
1521 return 0;
1522 }
1523 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001524 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001525 return 1;
1526 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001527 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001528 return -1;
1529 else
1530 return 0;
1531}
1532
1533/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001534 * returns the remaining time between tv1=now and event=tv2
1535 * if tv2 is passed, 0 is returned.
1536 * Returns TIME_ETERNITY if tv2 is eternity.
1537 */
1538static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1539 unsigned long ret;
1540
1541 if (tv_iseternity(tv2))
1542 return TIME_ETERNITY;
1543
1544 if (tv_cmp_ms(tv1, tv2) >= 0)
1545 return 0; /* event elapsed */
1546
1547 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1548 if (tv2->tv_usec > tv1->tv_usec)
1549 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1550 else
1551 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1552 return (unsigned long) ret;
1553}
1554
1555/*
willy tarreau0f7af912005-12-17 12:21:26 +01001556 * returns the first event between tv1 and tv2 into tvmin.
1557 * a zero tv is ignored. tvmin is returned.
1558 */
1559static inline struct timeval *tv_min(struct timeval *tvmin,
1560 struct timeval *tv1, struct timeval *tv2) {
1561
1562 if (tv_cmp2(tv1, tv2) <= 0)
1563 *tvmin = *tv1;
1564 else
1565 *tvmin = *tv2;
1566
1567 return tvmin;
1568}
1569
1570
1571
1572/***********************************************************/
1573/* fd management ***************************************/
1574/***********************************************************/
1575
1576
1577
willy tarreau5cbea6f2005-12-17 12:48:26 +01001578/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1579 * The file descriptor is also closed.
1580 */
willy tarreau0f7af912005-12-17 12:21:26 +01001581static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001582 FD_CLR(fd, StaticReadEvent);
1583 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001584#if defined(ENABLE_EPOLL)
1585 if (PrevReadEvent) {
1586 FD_CLR(fd, PrevReadEvent);
1587 FD_CLR(fd, PrevWriteEvent);
1588 }
1589#endif
1590
willy tarreau5cbea6f2005-12-17 12:48:26 +01001591 close(fd);
1592 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001593
1594 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1595 maxfd--;
1596}
1597
1598/* recomputes the maxfd limit from the fd */
1599static inline void fd_insert(int fd) {
1600 if (fd+1 > maxfd)
1601 maxfd = fd+1;
1602}
1603
1604/*************************************************************/
1605/* task management ***************************************/
1606/*************************************************************/
1607
willy tarreau5cbea6f2005-12-17 12:48:26 +01001608/* puts the task <t> in run queue <q>, and returns <t> */
1609static inline struct task *task_wakeup(struct task **q, struct task *t) {
1610 if (t->state == TASK_RUNNING)
1611 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001612 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001613 t->rqnext = *q;
1614 t->state = TASK_RUNNING;
1615 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001616 }
1617}
1618
willy tarreau5cbea6f2005-12-17 12:48:26 +01001619/* removes the task <t> from the queue <q>
1620 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001621 * set the run queue to point to the next one, and return it
1622 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623static inline struct task *task_sleep(struct task **q, struct task *t) {
1624 if (t->state == TASK_RUNNING) {
1625 *q = t->rqnext;
1626 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001627 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001628 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001629}
1630
1631/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001632 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001633 * from the run queue. A pointer to the task itself is returned.
1634 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001635static inline struct task *task_delete(struct task *t) {
1636 t->prev->next = t->next;
1637 t->next->prev = t->prev;
1638 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001639}
1640
1641/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001642 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001643 */
1644static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001645 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001646}
1647
willy tarreau5cbea6f2005-12-17 12:48:26 +01001648/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001649 * may be only moved or left where it was, depending on its timing requirements.
1650 * <task> is returned.
1651 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001652struct task *task_queue(struct task *task) {
1653 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001654 struct task *start_from;
1655
1656 /* first, test if the task was already in a list */
1657 if (task->prev == NULL) {
1658 // start_from = list;
1659 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001660#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001661 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001662#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001663 /* insert the unlinked <task> into the list, searching back from the last entry */
1664 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1665 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001666#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001667 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001668#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001669 }
1670
1671 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1672 // start_from = start_from->next;
1673 // stats_tsk_nsrch++;
1674 // }
1675 }
1676 else if (task->prev == list ||
1677 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1678 start_from = task->next;
1679 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001680#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001681 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001682#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001683 return task; /* it's already in the right place */
1684 }
1685
willy tarreau750a4722005-12-17 13:21:24 +01001686#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001687 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001688#endif
1689
1690 /* if the task is not at the right place, there's little chance that
1691 * it has only shifted a bit, and it will nearly always be queued
1692 * at the end of the list because of constant timeouts
1693 * (observed in real case).
1694 */
1695#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1696 start_from = list->prev; /* assume we'll queue to the end of the list */
1697 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1698 start_from = start_from->prev;
1699#if STATTIME > 0
1700 stats_tsk_lsrch++;
1701#endif
1702 }
1703#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001704 /* insert the unlinked <task> into the list, searching after position <start_from> */
1705 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1706 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001707#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001708 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001709#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001710 }
willy tarreau750a4722005-12-17 13:21:24 +01001711#endif /* WE_REALLY_... */
1712
willy tarreau0f7af912005-12-17 12:21:26 +01001713 /* we need to unlink it now */
1714 task_delete(task);
1715 }
1716 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001717#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001718 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001719#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001720#ifdef LEFT_TO_TOP /* not very good */
1721 start_from = list;
1722 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1723 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001724#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001725 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001726#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001727 }
1728#else
1729 start_from = task->prev->prev; /* valid because of the previous test above */
1730 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1731 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001732#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001733 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001734#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001735 }
1736#endif
1737 /* we need to unlink it now */
1738 task_delete(task);
1739 }
1740 task->prev = start_from;
1741 task->next = start_from->next;
1742 task->next->prev = task;
1743 start_from->next = task;
1744 return task;
1745}
1746
1747
1748/*********************************************************************/
1749/* more specific functions ***************************************/
1750/*********************************************************************/
1751
1752/* some prototypes */
1753static int maintain_proxies(void);
1754
willy tarreaub952e1d2005-12-18 01:31:20 +01001755/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001756 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1757 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001758static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001759#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001760 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1761#else
willy tarreaua1598082005-12-17 13:08:06 +01001762#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001763 return getsockname(fd, (struct sockaddr *)sa, salen);
1764#else
1765 return -1;
1766#endif
1767#endif
1768}
1769
1770/*
1771 * frees the context associated to a session. It must have been removed first.
1772 */
1773static inline void session_free(struct session *s) {
1774 if (s->req)
1775 pool_free(buffer, s->req);
1776 if (s->rep)
1777 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001778
1779 if (s->rsp_cap != NULL) {
1780 struct cap_hdr *h;
1781 for (h = s->proxy->rsp_cap; h; h = h->next) {
1782 if (s->rsp_cap[h->index] != NULL)
1783 pool_free_to(h->pool, s->rsp_cap[h->index]);
1784 }
1785 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1786 }
1787 if (s->req_cap != NULL) {
1788 struct cap_hdr *h;
1789 for (h = s->proxy->req_cap; h; h = h->next) {
1790 if (s->req_cap[h->index] != NULL)
1791 pool_free_to(h->pool, s->req_cap[h->index]);
1792 }
1793 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1794 }
1795
willy tarreaua1598082005-12-17 13:08:06 +01001796 if (s->logs.uri)
1797 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001798 if (s->logs.cli_cookie)
1799 pool_free(capture, s->logs.cli_cookie);
1800 if (s->logs.srv_cookie)
1801 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001802
willy tarreau5cbea6f2005-12-17 12:48:26 +01001803 pool_free(session, s);
1804}
1805
willy tarreau0f7af912005-12-17 12:21:26 +01001806
1807/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001808 * This function recounts the number of usable active and backup servers for
1809 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
1810 */
1811static inline void recount_servers(struct proxy *px) {
1812 struct server *srv;
1813
1814 px->srv_act = 0; px->srv_bck = 0;
1815 for (srv = px->srv; srv != NULL; srv = srv->next) {
1816 if (srv->state & SRV_RUNNING) {
1817 if (srv->state & SRV_BACKUP)
1818 px->srv_bck++;
1819 else
1820 px->srv_act++;
1821 }
1822 }
1823}
1824
1825/*
1826 * This function tries to find a running server for the proxy <px> following
1827 * the round-robin method. Depending on the number of active/backup servers,
1828 * it will either look for active servers, or for backup servers.
1829 * If any server is found, it will be returned and px->cursrv will be updated
1830 * to point to the next server. If no valid server is found, NULL is returned.
willy tarreau8337c6b2005-12-17 13:41:01 +01001831 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001832static inline struct server *get_server_rr(struct proxy *px) {
1833 struct server *srv;
willy tarreau72e583d2006-03-23 11:27:02 +01001834 struct server *end;
willy tarreau8337c6b2005-12-17 13:41:01 +01001835
willy tarreau4c8c2b52006-03-24 19:36:41 +01001836 if (px->srv_act) {
1837 srv = px->cursrv;
willy tarreau72e583d2006-03-23 11:27:02 +01001838 if (srv == NULL)
1839 srv = px->srv;
1840 end = srv;
willy tarreau8337c6b2005-12-17 13:41:01 +01001841 do {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001842 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1843 px->cursrv = srv->next;
willy tarreau8337c6b2005-12-17 13:41:01 +01001844 return srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001845 }
1846
willy tarreau8337c6b2005-12-17 13:41:01 +01001847 srv = srv->next;
willy tarreau72e583d2006-03-23 11:27:02 +01001848 if (srv == NULL)
1849 srv = px->srv;
1850 } while (srv != end);
willy tarreau4c8c2b52006-03-24 19:36:41 +01001851 /* note that theorically we should not get there */
1852 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001853
willy tarreau4c8c2b52006-03-24 19:36:41 +01001854 if (px->srv_bck) {
Willy TARREAU3481c462006-03-01 22:37:57 +01001855 /* By default, we look for the first backup server if all others are
1856 * DOWN. But in some cases, it may be desirable to load-balance across
1857 * all backup servers.
1858 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001859 if (px->options & PR_O_USE_ALL_BK)
1860 srv = px->cursrv;
1861 else
1862 srv = px->srv;
1863
1864 if (srv == NULL)
Willy TARREAU3481c462006-03-01 22:37:57 +01001865 srv = px->srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001866 end = srv;
1867 do {
1868 if (srv->state & SRV_RUNNING) {
1869 px->cursrv = srv->next;
1870 return srv;
1871 }
1872 srv = srv->next;
1873 if (srv == NULL)
1874 srv = px->srv;
1875 } while (srv != end);
1876 /* note that theorically we should not get there */
1877 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001878
willy tarreau4c8c2b52006-03-24 19:36:41 +01001879 /* if we get there, it means there are no available servers at all */
willy tarreau8337c6b2005-12-17 13:41:01 +01001880 return NULL;
1881}
1882
willy tarreau62084d42006-03-24 18:57:41 +01001883
1884/*
willy tarreau1a3442d2006-03-24 21:03:20 +01001885 * This function tries to find a running server for the proxy <px> following
1886 * the source hash method. Depending on the number of active/backup servers,
1887 * it will either look for active servers, or for backup servers.
1888 * If any server is found, it will be returned. If no valid server is found,
1889 * NULL is returned.
1890 */
1891static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
1892 struct server *srv;
1893
1894 if (px->srv_act) {
1895 unsigned int h, l;
1896
1897 l = h = 0;
1898 if (px->srv_act > 1) {
1899 while ((l + sizeof (int)) <= len) {
1900 h ^= ntohl(*(unsigned int *)(&addr[l]));
1901 l += sizeof (int);
1902 }
1903 h %= px->srv_act;
1904 }
1905
1906 for (srv = px->srv; srv; srv = srv->next) {
1907 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1908 if (!h)
1909 return srv;
1910 h--;
1911 }
1912 }
1913 /* note that theorically we should not get there */
1914 }
1915
1916 if (px->srv_bck) {
1917 unsigned int h, l;
1918
1919 /* By default, we look for the first backup server if all others are
1920 * DOWN. But in some cases, it may be desirable to load-balance across
1921 * all backup servers.
1922 */
1923 l = h = 0;
1924 if (px->srv_bck > 1 && px->options & PR_O_USE_ALL_BK) {
1925 while ((l + sizeof (int)) <= len) {
1926 h ^= ntohl(*(unsigned int *)(&addr[l]));
1927 l += sizeof (int);
1928 }
1929 h %= px->srv_bck;
1930 }
1931
1932 for (srv = px->srv; srv; srv = srv->next) {
1933 if (srv->state & SRV_RUNNING) {
1934 if (!h)
1935 return srv;
1936 h--;
1937 }
1938 }
1939 /* note that theorically we should not get there */
1940 }
1941
1942 /* if we get there, it means there are no available servers at all */
1943 return NULL;
1944}
1945
1946
1947/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001948 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001949 * is set, or to the dispatch server if (s->direct) is 0.
1950 * It can return one of :
1951 * - SN_ERR_NONE if everything's OK
1952 * - SN_ERR_SRVTO if there are no more servers
1953 * - SN_ERR_SRVCL if the connection was refused by the server
1954 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1955 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1956 * - SN_ERR_INTERNAL for any other purely internal errors
1957 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001958 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001959int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001960 int fd;
1961
willy tarreau12350152005-12-18 01:03:27 +01001962#ifdef DEBUG_FULL
1963 fprintf(stderr,"connect_server : s=%p\n",s);
1964#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001965
willy tarreaue39cd132005-12-17 13:00:18 +01001966 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001967 s->srv_addr = s->srv->addr;
1968 }
1969 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01001970 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001971 if (!s->proxy->srv_act && !s->proxy->srv_bck)
1972 return SN_ERR_SRVTO;
1973
willy tarreau5cbea6f2005-12-17 12:48:26 +01001974 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001975 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001976
willy tarreau4c8c2b52006-03-24 19:36:41 +01001977 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01001978 s->srv_addr = srv->addr;
1979 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01001980 }
willy tarreau1a3442d2006-03-24 21:03:20 +01001981 else if (s->proxy->options & PR_O_BALANCE_SH) {
1982 struct server *srv;
1983 int len;
1984
1985 if (s->cli_addr.ss_family == AF_INET)
1986 len = 4;
1987 else if (s->cli_addr.ss_family == AF_INET6)
1988 len = 16;
1989 else /* unknown IP family */
1990 return SN_ERR_INTERNAL;
1991
1992 srv = get_server_sh(s->proxy,
1993 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1994 len);
1995 s->srv_addr = srv->addr;
1996 s->srv = srv;
1997 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001998 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001999 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002000 }
willy tarreaua1598082005-12-17 13:08:06 +01002001 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002002 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002003 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002004 }
2005 else if (s->proxy->options & PR_O_TRANSP) {
2006 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002007 socklen_t salen = sizeof(s->srv_addr);
2008
willy tarreau5cbea6f2005-12-17 12:48:26 +01002009 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2010 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002011 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012 }
2013 }
willy tarreau0f7af912005-12-17 12:21:26 +01002014
willy tarreaua41a8b42005-12-17 14:02:24 +01002015 /* if this server remaps proxied ports, we'll use
2016 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01002017 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01002018 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002019 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002020
willy tarreaub952e1d2005-12-18 01:31:20 +01002021 if (!(s->proxy->options & PR_O_TRANSP) ||
2022 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002023 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2024 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2025 }
2026
willy tarreau0f7af912005-12-17 12:21:26 +01002027 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002028 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002029
2030 if (errno == ENFILE)
2031 send_log(s->proxy, LOG_EMERG,
2032 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2033 s->proxy->id, maxfd);
2034 else if (errno == EMFILE)
2035 send_log(s->proxy, LOG_EMERG,
2036 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2037 s->proxy->id, maxfd);
2038 else if (errno == ENOBUFS || errno == ENOMEM)
2039 send_log(s->proxy, LOG_EMERG,
2040 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2041 s->proxy->id, maxfd);
2042 /* this is a resource error */
2043 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002044 }
2045
willy tarreau9fe663a2005-12-17 13:02:59 +01002046 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002047 /* do not log anything there, it's a normal condition when this option
2048 * is used to serialize connections to a server !
2049 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002050 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2051 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002052 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002053 }
2054
willy tarreau0f7af912005-12-17 12:21:26 +01002055 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2056 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002057 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002058 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002059 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002060 }
2061
willy tarreaub952e1d2005-12-18 01:31:20 +01002062 if (s->proxy->options & PR_O_TCP_SRV_KA)
2063 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2064
willy tarreau0174f312005-12-18 01:02:42 +01002065 /* allow specific binding :
2066 * - server-specific at first
2067 * - proxy-specific next
2068 */
2069 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2070 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2071 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2072 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2073 s->proxy->id, s->srv->id);
2074 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002075 send_log(s->proxy, LOG_EMERG,
2076 "Cannot bind to source address before connect() for server %s/%s.\n",
2077 s->proxy->id, s->srv->id);
2078 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002079 }
2080 }
2081 else if (s->proxy->options & PR_O_BIND_SRC) {
2082 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2083 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2084 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2085 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002086 send_log(s->proxy, LOG_EMERG,
2087 "Cannot bind to source address before connect() for server %s/%s.\n",
2088 s->proxy->id, s->srv->id);
2089 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002090 }
willy tarreaua1598082005-12-17 13:08:06 +01002091 }
2092
willy tarreaub1285d52005-12-18 01:20:14 +01002093 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2094 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2095
2096 if (errno == EAGAIN || errno == EADDRINUSE) {
2097 char *msg;
2098 if (errno == EAGAIN) /* no free ports left, try again later */
2099 msg = "no free ports";
2100 else
2101 msg = "local address already in use";
2102
2103 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002104 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002105 send_log(s->proxy, LOG_EMERG,
2106 "Connect() failed for server %s/%s: %s.\n",
2107 s->proxy->id, s->srv->id, msg);
2108 return SN_ERR_RESOURCE;
2109 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002110 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002111 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002112 return SN_ERR_SRVTO;
2113 } else {
2114 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002115 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002116 close(fd);
2117 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002118 }
2119 }
2120
willy tarreau5cbea6f2005-12-17 12:48:26 +01002121 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002122 fdtab[fd].read = &event_srv_read;
2123 fdtab[fd].write = &event_srv_write;
2124 fdtab[fd].state = FD_STCONN; /* connection in progress */
2125
2126 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002127#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2128 if (PrevReadEvent) {
2129 assert(!(FD_ISSET(fd, PrevReadEvent)));
2130 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2131 }
2132#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002133
2134 fd_insert(fd);
2135
2136 if (s->proxy->contimeout)
2137 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2138 else
2139 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002140 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002141}
2142
2143/*
2144 * this function is called on a read event from a client socket.
2145 * It returns 0.
2146 */
2147int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002148 struct task *t = fdtab[fd].owner;
2149 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002150 struct buffer *b = s->req;
2151 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002152
willy tarreau12350152005-12-18 01:03:27 +01002153#ifdef DEBUG_FULL
2154 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2155#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002156
willy tarreau0f7af912005-12-17 12:21:26 +01002157 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002158#ifdef FILL_BUFFERS
2159 while (1)
2160#else
2161 do
2162#endif
2163 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002164 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2165 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002166 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002167 }
2168 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002169 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002170 }
2171 else {
2172 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002173 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2174 * since it means that the rewrite protection has been removed. This
2175 * implies that the if statement can be removed.
2176 */
2177 if (max > b->rlim - b->data)
2178 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002179 }
2180
2181 if (max == 0) { /* not anymore room to store data */
2182 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002183 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002184 }
2185
willy tarreau3242e862005-12-17 12:27:53 +01002186#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002187 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002188 int skerr;
2189 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002190
willy tarreau5cbea6f2005-12-17 12:48:26 +01002191 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2192 if (skerr)
2193 ret = -1;
2194 else
2195 ret = recv(fd, b->r, max, 0);
2196 }
willy tarreau3242e862005-12-17 12:27:53 +01002197#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002198 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002199#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002200 if (ret > 0) {
2201 b->r += ret;
2202 b->l += ret;
2203 s->res_cr = RES_DATA;
2204
2205 if (b->r == b->data + BUFSIZE) {
2206 b->r = b->data; /* wrap around the buffer */
2207 }
willy tarreaua1598082005-12-17 13:08:06 +01002208
2209 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002210 /* we hope to read more data or to get a close on next round */
2211 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002212 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002213 else if (ret == 0) {
2214 s->res_cr = RES_NULL;
2215 break;
2216 }
2217 else if (errno == EAGAIN) {/* ignore EAGAIN */
2218 break;
2219 }
2220 else {
2221 s->res_cr = RES_ERROR;
2222 fdtab[fd].state = FD_STERROR;
2223 break;
2224 }
2225 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002226#ifndef FILL_BUFFERS
2227 while (0);
2228#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002229 }
2230 else {
2231 s->res_cr = RES_ERROR;
2232 fdtab[fd].state = FD_STERROR;
2233 }
2234
willy tarreau5cbea6f2005-12-17 12:48:26 +01002235 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002236 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002237 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2238 else
2239 tv_eternity(&s->crexpire);
2240
2241 task_wakeup(&rq, t);
2242 }
willy tarreau0f7af912005-12-17 12:21:26 +01002243
willy tarreau0f7af912005-12-17 12:21:26 +01002244 return 0;
2245}
2246
2247
2248/*
2249 * this function is called on a read event from a server socket.
2250 * It returns 0.
2251 */
2252int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002253 struct task *t = fdtab[fd].owner;
2254 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002255 struct buffer *b = s->rep;
2256 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002257
willy tarreau12350152005-12-18 01:03:27 +01002258#ifdef DEBUG_FULL
2259 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2260#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002261
willy tarreau0f7af912005-12-17 12:21:26 +01002262 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002263#ifdef FILL_BUFFERS
2264 while (1)
2265#else
2266 do
2267#endif
2268 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002269 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2270 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002271 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002272 }
2273 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002274 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002275 }
2276 else {
2277 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002278 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2279 * since it means that the rewrite protection has been removed. This
2280 * implies that the if statement can be removed.
2281 */
2282 if (max > b->rlim - b->data)
2283 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002284 }
2285
2286 if (max == 0) { /* not anymore room to store data */
2287 FD_CLR(fd, StaticReadEvent);
2288 break;
2289 }
2290
willy tarreau3242e862005-12-17 12:27:53 +01002291#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002292 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002293 int skerr;
2294 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002295
willy tarreau5cbea6f2005-12-17 12:48:26 +01002296 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2297 if (skerr)
2298 ret = -1;
2299 else
2300 ret = recv(fd, b->r, max, 0);
2301 }
willy tarreau3242e862005-12-17 12:27:53 +01002302#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002303 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002304#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002305 if (ret > 0) {
2306 b->r += ret;
2307 b->l += ret;
2308 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002309
willy tarreau5cbea6f2005-12-17 12:48:26 +01002310 if (b->r == b->data + BUFSIZE) {
2311 b->r = b->data; /* wrap around the buffer */
2312 }
willy tarreaua1598082005-12-17 13:08:06 +01002313
2314 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002315 /* we hope to read more data or to get a close on next round */
2316 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002317 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002318 else if (ret == 0) {
2319 s->res_sr = RES_NULL;
2320 break;
2321 }
2322 else if (errno == EAGAIN) {/* ignore EAGAIN */
2323 break;
2324 }
2325 else {
2326 s->res_sr = RES_ERROR;
2327 fdtab[fd].state = FD_STERROR;
2328 break;
2329 }
2330 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002331#ifndef FILL_BUFFERS
2332 while (0);
2333#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002334 }
2335 else {
2336 s->res_sr = RES_ERROR;
2337 fdtab[fd].state = FD_STERROR;
2338 }
2339
willy tarreau5cbea6f2005-12-17 12:48:26 +01002340 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002341 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002342 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2343 else
2344 tv_eternity(&s->srexpire);
2345
2346 task_wakeup(&rq, t);
2347 }
willy tarreau0f7af912005-12-17 12:21:26 +01002348
willy tarreau0f7af912005-12-17 12:21:26 +01002349 return 0;
2350}
2351
2352/*
2353 * this function is called on a write event from a client socket.
2354 * It returns 0.
2355 */
2356int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002357 struct task *t = fdtab[fd].owner;
2358 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002359 struct buffer *b = s->rep;
2360 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002361
willy tarreau12350152005-12-18 01:03:27 +01002362#ifdef DEBUG_FULL
2363 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2364#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002365
2366 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002367 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002368 // max = BUFSIZE; BUG !!!!
2369 max = 0;
2370 }
2371 else if (b->r > b->w) {
2372 max = b->r - b->w;
2373 }
2374 else
2375 max = b->data + BUFSIZE - b->w;
2376
willy tarreau0f7af912005-12-17 12:21:26 +01002377 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002378 if (max == 0) {
2379 s->res_cw = RES_NULL;
2380 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002381 tv_eternity(&s->cwexpire);
2382 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002383 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002384 }
2385
willy tarreau3242e862005-12-17 12:27:53 +01002386#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002387 {
2388 int skerr;
2389 socklen_t lskerr = sizeof(skerr);
2390
2391 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2392 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002393 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002394 else
willy tarreau3242e862005-12-17 12:27:53 +01002395 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002396 }
willy tarreau3242e862005-12-17 12:27:53 +01002397#else
willy tarreau0f7af912005-12-17 12:21:26 +01002398 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002399#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002400
2401 if (ret > 0) {
2402 b->l -= ret;
2403 b->w += ret;
2404
2405 s->res_cw = RES_DATA;
2406
2407 if (b->w == b->data + BUFSIZE) {
2408 b->w = b->data; /* wrap around the buffer */
2409 }
2410 }
2411 else if (ret == 0) {
2412 /* nothing written, just make as if we were never called */
2413// s->res_cw = RES_NULL;
2414 return 0;
2415 }
2416 else if (errno == EAGAIN) /* ignore EAGAIN */
2417 return 0;
2418 else {
2419 s->res_cw = RES_ERROR;
2420 fdtab[fd].state = FD_STERROR;
2421 }
2422 }
2423 else {
2424 s->res_cw = RES_ERROR;
2425 fdtab[fd].state = FD_STERROR;
2426 }
2427
willy tarreaub1ff9db2005-12-17 13:51:03 +01002428 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002429 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002430 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2431 s->crexpire = s->cwexpire;
2432 }
willy tarreau0f7af912005-12-17 12:21:26 +01002433 else
2434 tv_eternity(&s->cwexpire);
2435
willy tarreau5cbea6f2005-12-17 12:48:26 +01002436 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002437 return 0;
2438}
2439
2440
2441/*
2442 * this function is called on a write event from a server socket.
2443 * It returns 0.
2444 */
2445int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002446 struct task *t = fdtab[fd].owner;
2447 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002448 struct buffer *b = s->req;
2449 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002450
willy tarreau12350152005-12-18 01:03:27 +01002451#ifdef DEBUG_FULL
2452 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2453#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002454
2455 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002456 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002457 // max = BUFSIZE; BUG !!!!
2458 max = 0;
2459 }
2460 else if (b->r > b->w) {
2461 max = b->r - b->w;
2462 }
2463 else
2464 max = b->data + BUFSIZE - b->w;
2465
willy tarreau0f7af912005-12-17 12:21:26 +01002466 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002467 if (max == 0) {
2468 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002469 if (s->srv_state == SV_STCONN) {
2470 int skerr;
2471 socklen_t lskerr = sizeof(skerr);
2472 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2473 if (skerr) {
2474 s->res_sw = RES_ERROR;
2475 fdtab[fd].state = FD_STERROR;
2476 task_wakeup(&rq, t);
2477 tv_eternity(&s->swexpire);
2478 FD_CLR(fd, StaticWriteEvent);
2479 return 0;
2480 }
2481 }
2482
willy tarreau0f7af912005-12-17 12:21:26 +01002483 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002484 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002485 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002486 tv_eternity(&s->swexpire);
2487 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002488 return 0;
2489 }
2490
willy tarreau3242e862005-12-17 12:27:53 +01002491#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002492 {
2493 int skerr;
2494 socklen_t lskerr = sizeof(skerr);
2495 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2496 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002497 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002498 else
willy tarreau3242e862005-12-17 12:27:53 +01002499 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002500 }
willy tarreau3242e862005-12-17 12:27:53 +01002501#else
willy tarreau0f7af912005-12-17 12:21:26 +01002502 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002503#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002504 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002505 if (ret > 0) {
2506 b->l -= ret;
2507 b->w += ret;
2508
2509 s->res_sw = RES_DATA;
2510
2511 if (b->w == b->data + BUFSIZE) {
2512 b->w = b->data; /* wrap around the buffer */
2513 }
2514 }
2515 else if (ret == 0) {
2516 /* nothing written, just make as if we were never called */
2517 // s->res_sw = RES_NULL;
2518 return 0;
2519 }
2520 else if (errno == EAGAIN) /* ignore EAGAIN */
2521 return 0;
2522 else {
2523 s->res_sw = RES_ERROR;
2524 fdtab[fd].state = FD_STERROR;
2525 }
2526 }
2527 else {
2528 s->res_sw = RES_ERROR;
2529 fdtab[fd].state = FD_STERROR;
2530 }
2531
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002532 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2533 * otherwise it could loop indefinitely !
2534 */
2535 if (s->srv_state != SV_STCONN) {
2536 if (s->proxy->srvtimeout) {
2537 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2538 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2539 s->srexpire = s->swexpire;
2540 }
2541 else
2542 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002543 }
willy tarreau0f7af912005-12-17 12:21:26 +01002544
willy tarreau5cbea6f2005-12-17 12:48:26 +01002545 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002546 return 0;
2547}
2548
2549
2550/*
willy tarreaue39cd132005-12-17 13:00:18 +01002551 * returns a message to the client ; the connection is shut down for read,
2552 * and the request is cleared so that no server connection can be initiated.
2553 * The client must be in a valid state for this (HEADER, DATA ...).
2554 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002555 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002556 */
2557void client_retnclose(struct session *s, int len, const char *msg) {
2558 FD_CLR(s->cli_fd, StaticReadEvent);
2559 FD_SET(s->cli_fd, StaticWriteEvent);
2560 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002561 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002562 shutdown(s->cli_fd, SHUT_RD);
2563 s->cli_state = CL_STSHUTR;
2564 strcpy(s->rep->data, msg);
2565 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002566 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002567 s->rep->r += len;
2568 s->req->l = 0;
2569}
2570
2571
2572/*
2573 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002574 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002575 */
2576void client_return(struct session *s, int len, const char *msg) {
2577 strcpy(s->rep->data, msg);
2578 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002579 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002580 s->rep->r += len;
2581 s->req->l = 0;
2582}
2583
willy tarreau9fe663a2005-12-17 13:02:59 +01002584/*
2585 * send a log for the session when we have enough info about it
2586 */
2587void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002588 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002589 struct proxy *p = s->proxy;
2590 int log;
2591 char *uri;
2592 char *pxid;
2593 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002594 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002595
2596 /* This is a first attempt at a better logging system.
2597 * For now, we rely on send_log() to provide the date, although it obviously
2598 * is the date of the log and not of the request, and most fields are not
2599 * computed.
2600 */
2601
willy tarreaua1598082005-12-17 13:08:06 +01002602 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002603
willy tarreau8a86dbf2005-12-18 00:45:59 +01002604 if (s->cli_addr.ss_family == AF_INET)
2605 inet_ntop(AF_INET,
2606 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2607 pn, sizeof(pn));
2608 else
2609 inet_ntop(AF_INET6,
2610 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2611 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002612
willy tarreauc1cae632005-12-17 14:12:23 +01002613 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002614 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002615 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002616
willy tarreauc1cae632005-12-17 14:12:23 +01002617 tm = localtime(&s->logs.tv_accept.tv_sec);
2618 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002619 char tmpline[MAX_SYSLOG_LEN], *h;
2620 int hdr;
2621
2622 h = tmpline;
2623 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2624 *(h++) = ' ';
2625 *(h++) = '{';
2626 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2627 if (hdr)
2628 *(h++) = '|';
2629 if (s->req_cap[hdr] != NULL)
2630 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2631 }
2632 *(h++) = '}';
2633 }
2634
2635 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2636 *(h++) = ' ';
2637 *(h++) = '{';
2638 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2639 if (hdr)
2640 *(h++) = '|';
2641 if (s->rsp_cap[hdr] != NULL)
2642 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2643 }
2644 *(h++) = '}';
2645 }
2646
2647 if (h < tmpline + sizeof(tmpline) - 4) {
2648 *(h++) = ' ';
2649 *(h++) = '"';
2650 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2651 *(h++) = '"';
2652 }
2653 *h = '\0';
2654
willy tarreau0fe39652005-12-18 01:25:24 +01002655 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 %d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002656 pn,
2657 (s->cli_addr.ss_family == AF_INET) ?
2658 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2659 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002660 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2661 tm->tm_hour, tm->tm_min, tm->tm_sec,
2662 pxid, srv,
2663 s->logs.t_request,
2664 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2665 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002666 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2667 s->logs.status,
2668 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002669 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2670 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002671 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2672 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2673 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2674 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002675 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002676 }
2677 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002678 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002679 pn,
2680 (s->cli_addr.ss_family == AF_INET) ?
2681 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2682 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002683 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2684 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002685 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002686 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002687 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2688 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002689 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002690 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2691 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002692 }
2693
2694 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002695}
2696
willy tarreaue39cd132005-12-17 13:00:18 +01002697
2698/*
willy tarreau0f7af912005-12-17 12:21:26 +01002699 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002700 * to an accept. It tries to accept as many connections as possible.
2701 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002702 */
2703int event_accept(int fd) {
2704 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002705 struct session *s;
2706 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002707 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002708 int max_accept;
2709
2710 if (global.nbproc > 1)
2711 max_accept = 8; /* let other processes catch some connections too */
2712 else
2713 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002714
willy tarreauc2becdc2006-03-19 19:36:48 +01002715 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002716 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002717 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002718
willy tarreaub1285d52005-12-18 01:20:14 +01002719 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2720 switch (errno) {
2721 case EAGAIN:
2722 case EINTR:
2723 case ECONNABORTED:
2724 return 0; /* nothing more to accept */
2725 case ENFILE:
2726 send_log(p, LOG_EMERG,
2727 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2728 p->id, maxfd);
2729 return 0;
2730 case EMFILE:
2731 send_log(p, LOG_EMERG,
2732 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2733 p->id, maxfd);
2734 return 0;
2735 case ENOBUFS:
2736 case ENOMEM:
2737 send_log(p, LOG_EMERG,
2738 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2739 p->id, maxfd);
2740 return 0;
2741 default:
2742 return 0;
2743 }
2744 }
willy tarreau0f7af912005-12-17 12:21:26 +01002745
willy tarreau5cbea6f2005-12-17 12:48:26 +01002746 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2747 Alert("out of memory in event_accept().\n");
2748 FD_CLR(fd, StaticReadEvent);
2749 p->state = PR_STIDLE;
2750 close(cfd);
2751 return 0;
2752 }
willy tarreau0f7af912005-12-17 12:21:26 +01002753
willy tarreaub1285d52005-12-18 01:20:14 +01002754 /* if this session comes from a known monitoring system, we want to ignore
2755 * it as soon as possible, which means closing it immediately for TCP.
2756 */
2757 s->flags = 0;
2758 if (addr.ss_family == AF_INET &&
2759 p->mon_mask.s_addr &&
2760 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2761 if (p->mode == PR_MODE_TCP) {
2762 close(cfd);
2763 pool_free(session, s);
2764 continue;
2765 }
2766 s->flags |= SN_MONITOR;
2767 }
2768
willy tarreau5cbea6f2005-12-17 12:48:26 +01002769 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2770 Alert("out of memory in event_accept().\n");
2771 FD_CLR(fd, StaticReadEvent);
2772 p->state = PR_STIDLE;
2773 close(cfd);
2774 pool_free(session, s);
2775 return 0;
2776 }
willy tarreau0f7af912005-12-17 12:21:26 +01002777
willy tarreau5cbea6f2005-12-17 12:48:26 +01002778 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002779 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002780 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2781 close(cfd);
2782 pool_free(task, t);
2783 pool_free(session, s);
2784 return 0;
2785 }
willy tarreau0f7af912005-12-17 12:21:26 +01002786
willy tarreau5cbea6f2005-12-17 12:48:26 +01002787 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2788 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2789 (char *) &one, sizeof(one)) == -1)) {
2790 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2791 close(cfd);
2792 pool_free(task, t);
2793 pool_free(session, s);
2794 return 0;
2795 }
willy tarreau0f7af912005-12-17 12:21:26 +01002796
willy tarreaub952e1d2005-12-18 01:31:20 +01002797 if (p->options & PR_O_TCP_CLI_KA)
2798 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2799
willy tarreau9fe663a2005-12-17 13:02:59 +01002800 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2801 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2802 t->state = TASK_IDLE;
2803 t->process = process_session;
2804 t->context = s;
2805
2806 s->task = t;
2807 s->proxy = p;
2808 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2809 s->srv_state = SV_STIDLE;
2810 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002811
willy tarreau9fe663a2005-12-17 13:02:59 +01002812 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2813 s->cli_fd = cfd;
2814 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002815 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002816 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002817
willy tarreaub1285d52005-12-18 01:20:14 +01002818 if (s->flags & SN_MONITOR)
2819 s->logs.logwait = 0;
2820 else
2821 s->logs.logwait = p->to_log;
2822
willy tarreaua1598082005-12-17 13:08:06 +01002823 s->logs.tv_accept = now;
2824 s->logs.t_request = -1;
2825 s->logs.t_connect = -1;
2826 s->logs.t_data = -1;
2827 s->logs.t_close = 0;
2828 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002829 s->logs.cli_cookie = NULL;
2830 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002831 s->logs.status = -1;
2832 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002833
willy tarreau2f6ba652005-12-17 13:57:42 +01002834 s->uniq_id = totalconn;
2835
willy tarreau4302f492005-12-18 01:00:37 +01002836 if (p->nb_req_cap > 0) {
2837 if ((s->req_cap =
2838 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2839 == NULL) { /* no memory */
2840 close(cfd); /* nothing can be done for this fd without memory */
2841 pool_free(task, t);
2842 pool_free(session, s);
2843 return 0;
2844 }
2845 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2846 }
2847 else
2848 s->req_cap = NULL;
2849
2850 if (p->nb_rsp_cap > 0) {
2851 if ((s->rsp_cap =
2852 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2853 == NULL) { /* no memory */
2854 if (s->req_cap != NULL)
2855 pool_free_to(p->req_cap_pool, s->req_cap);
2856 close(cfd); /* nothing can be done for this fd without memory */
2857 pool_free(task, t);
2858 pool_free(session, s);
2859 return 0;
2860 }
2861 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2862 }
2863 else
2864 s->rsp_cap = NULL;
2865
willy tarreau5cbea6f2005-12-17 12:48:26 +01002866 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2867 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002868 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002869 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002870
willy tarreau8a86dbf2005-12-18 00:45:59 +01002871 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002872 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002873 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002874 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002875
willy tarreau9fe663a2005-12-17 13:02:59 +01002876 if (p->to_log) {
2877 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002878 if (s->logs.logwait & LW_CLIP)
2879 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002880 sess_log(s);
2881 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002882 else if (s->cli_addr.ss_family == AF_INET) {
2883 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2884 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2885 sn, sizeof(sn)) &&
2886 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2887 pn, sizeof(pn))) {
2888 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2889 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2890 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2891 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2892 }
2893 }
2894 else {
2895 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2896 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2897 sn, sizeof(sn)) &&
2898 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2899 pn, sizeof(pn))) {
2900 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2901 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2902 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2903 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2904 }
2905 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002906 }
willy tarreau0f7af912005-12-17 12:21:26 +01002907
willy tarreau982249e2005-12-18 00:57:06 +01002908 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002909 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002910 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002911 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002912 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002913 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002914 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002915 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002916
willy tarreau8a86dbf2005-12-18 00:45:59 +01002917 if (s->cli_addr.ss_family == AF_INET) {
2918 char pn[INET_ADDRSTRLEN];
2919 inet_ntop(AF_INET,
2920 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2921 pn, sizeof(pn));
2922
2923 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2924 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2925 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2926 }
2927 else {
2928 char pn[INET6_ADDRSTRLEN];
2929 inet_ntop(AF_INET6,
2930 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2931 pn, sizeof(pn));
2932
2933 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2934 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2935 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2936 }
2937
willy tarreauef900ab2005-12-17 12:52:52 +01002938 write(1, trash, len);
2939 }
willy tarreau0f7af912005-12-17 12:21:26 +01002940
willy tarreau5cbea6f2005-12-17 12:48:26 +01002941 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002942 if (s->rsp_cap != NULL)
2943 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2944 if (s->req_cap != NULL)
2945 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002946 close(cfd); /* nothing can be done for this fd without memory */
2947 pool_free(task, t);
2948 pool_free(session, s);
2949 return 0;
2950 }
willy tarreau4302f492005-12-18 01:00:37 +01002951
willy tarreau5cbea6f2005-12-17 12:48:26 +01002952 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002953 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002954 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2955 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002956 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002957 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002958
willy tarreau5cbea6f2005-12-17 12:48:26 +01002959 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2960 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002961 if (s->rsp_cap != NULL)
2962 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2963 if (s->req_cap != NULL)
2964 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002965 close(cfd); /* nothing can be done for this fd without memory */
2966 pool_free(task, t);
2967 pool_free(session, s);
2968 return 0;
2969 }
2970 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002971 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002972 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 +01002973
willy tarreau5cbea6f2005-12-17 12:48:26 +01002974 fdtab[cfd].read = &event_cli_read;
2975 fdtab[cfd].write = &event_cli_write;
2976 fdtab[cfd].owner = t;
2977 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002978
willy tarreaub1285d52005-12-18 01:20:14 +01002979 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2980 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2981 /* Either we got a request from a monitoring system on an HTTP instance,
2982 * or we're in health check mode with the 'httpchk' option enabled. In
2983 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2984 */
2985 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2986 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2987 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002988 }
2989 else {
2990 FD_SET(cfd, StaticReadEvent);
2991 }
2992
willy tarreaub952e1d2005-12-18 01:31:20 +01002993#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2994 if (PrevReadEvent) {
2995 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2996 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2997 }
2998#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002999 fd_insert(cfd);
3000
3001 tv_eternity(&s->cnexpire);
3002 tv_eternity(&s->srexpire);
3003 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003004 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003005 tv_eternity(&s->cwexpire);
3006
willy tarreaub1285d52005-12-18 01:20:14 +01003007 if (s->proxy->clitimeout) {
3008 if (FD_ISSET(cfd, StaticReadEvent))
3009 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3010 if (FD_ISSET(cfd, StaticWriteEvent))
3011 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3012 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003013
willy tarreaub1285d52005-12-18 01:20:14 +01003014 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003015
3016 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003017
3018 if (p->mode != PR_MODE_HEALTH)
3019 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003020
3021 p->nbconn++;
3022 actconn++;
3023 totalconn++;
3024
willy tarreaub952e1d2005-12-18 01:31:20 +01003025 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003026 } /* end of while (p->nbconn < p->maxconn) */
3027 return 0;
3028}
willy tarreau0f7af912005-12-17 12:21:26 +01003029
willy tarreau0f7af912005-12-17 12:21:26 +01003030
willy tarreau5cbea6f2005-12-17 12:48:26 +01003031/*
3032 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003033 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3034 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003035 * or -1 if an error occured.
3036 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003037int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003038 struct task *t = fdtab[fd].owner;
3039 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003040 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003041 socklen_t lskerr = sizeof(skerr);
3042
willy tarreau05be12b2006-03-19 19:35:00 +01003043 skerr = 1;
3044 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3045 || (skerr != 0)) {
3046 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003047 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003048 fdtab[fd].state = FD_STERROR;
3049 FD_CLR(fd, StaticWriteEvent);
3050 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003051 else if (s->result != -1) {
3052 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003053 if (s->proxy->options & PR_O_HTTP_CHK) {
3054 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003055 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003056 * so we'll send the request, and won't wake the checker up now.
3057 */
3058#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003059 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003060#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003061 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003062#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003063 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003064 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3065 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3066 return 0;
3067 }
willy tarreau05be12b2006-03-19 19:35:00 +01003068 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003069 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003070 FD_CLR(fd, StaticWriteEvent);
3071 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003072 }
3073 else {
3074 /* good TCP connection is enough */
3075 s->result = 1;
3076 }
3077 }
3078
3079 task_wakeup(&rq, t);
3080 return 0;
3081}
3082
willy tarreau0f7af912005-12-17 12:21:26 +01003083
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003084/*
3085 * This function is used only for server health-checks. It handles
3086 * the server's reply to an HTTP request. It returns 1 if the server replies
3087 * 2xx or 3xx (valid responses), or -1 in other cases.
3088 */
3089int event_srv_chk_r(int fd) {
3090 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003091 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003092 struct task *t = fdtab[fd].owner;
3093 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003094 int skerr;
3095 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003096
willy tarreaua4a583a2005-12-18 01:39:19 +01003097 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003098
willy tarreau05be12b2006-03-19 19:35:00 +01003099 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3100 if (!skerr) {
3101#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003102 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003103#else
willy tarreau05be12b2006-03-19 19:35:00 +01003104 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3105 * but the connection was closed on the remote end. Fortunately, recv still
3106 * works correctly and we don't need to do the getsockopt() on linux.
3107 */
3108 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003109#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003110
3111 if ((len >= sizeof("HTTP/1.0 000")) &&
3112 !memcmp(reply, "HTTP/1.", 7) &&
3113 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3114 result = 1;
3115 }
3116
3117 if (result == -1)
3118 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003119
3120 if (s->result != -1)
3121 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003122
3123 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003124 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003125 return 0;
3126}
3127
3128
3129/*
3130 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3131 * and moves <end> just after the end of <str>.
3132 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3133 * the shift value (positive or negative) is returned.
3134 * If there's no space left, the move is not done.
3135 *
3136 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003137int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003138 int delta;
3139 int len;
3140
3141 len = strlen(str);
3142 delta = len - (end - pos);
3143
3144 if (delta + b->r >= b->data + BUFSIZE)
3145 return 0; /* no space left */
3146
3147 /* first, protect the end of the buffer */
3148 memmove(end + delta, end, b->data + b->l - end);
3149
3150 /* now, copy str over pos */
3151 memcpy(pos, str,len);
3152
willy tarreau5cbea6f2005-12-17 12:48:26 +01003153 /* we only move data after the displaced zone */
3154 if (b->r > pos) b->r += delta;
3155 if (b->w > pos) b->w += delta;
3156 if (b->h > pos) b->h += delta;
3157 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003158 b->l += delta;
3159
3160 return delta;
3161}
3162
willy tarreau8337c6b2005-12-17 13:41:01 +01003163/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003164 * len is 0.
3165 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003166int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003167 int delta;
3168
3169 delta = len - (end - pos);
3170
3171 if (delta + b->r >= b->data + BUFSIZE)
3172 return 0; /* no space left */
3173
Willy TARREAUe78ae262006-01-08 01:24:12 +01003174 if (b->data + b->l < end)
3175 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3176 return 0;
3177
willy tarreau0f7af912005-12-17 12:21:26 +01003178 /* first, protect the end of the buffer */
3179 memmove(end + delta, end, b->data + b->l - end);
3180
3181 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003182 if (len)
3183 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003184
willy tarreau5cbea6f2005-12-17 12:48:26 +01003185 /* we only move data after the displaced zone */
3186 if (b->r > pos) b->r += delta;
3187 if (b->w > pos) b->w += delta;
3188 if (b->h > pos) b->h += delta;
3189 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003190 b->l += delta;
3191
3192 return delta;
3193}
3194
3195
3196int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3197 char *old_dst = dst;
3198
3199 while (*str) {
3200 if (*str == '\\') {
3201 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003202 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003203 int len, num;
3204
3205 num = *str - '0';
3206 str++;
3207
willy tarreau8a86dbf2005-12-18 00:45:59 +01003208 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003209 len = matches[num].rm_eo - matches[num].rm_so;
3210 memcpy(dst, src + matches[num].rm_so, len);
3211 dst += len;
3212 }
3213
3214 }
3215 else if (*str == 'x') {
3216 unsigned char hex1, hex2;
3217 str++;
3218
willy tarreauc1f47532005-12-18 01:08:26 +01003219 hex1 = toupper(*str++) - '0';
3220 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003221
3222 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3223 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3224 *dst++ = (hex1<<4) + hex2;
3225 }
3226 else
3227 *dst++ = *str++;
3228 }
3229 else
3230 *dst++ = *str++;
3231 }
3232 *dst = 0;
3233 return dst - old_dst;
3234}
3235
willy tarreauc1f47532005-12-18 01:08:26 +01003236static int ishex(char s)
3237{
3238 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3239}
3240
3241/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3242char *check_replace_string(char *str)
3243{
3244 char *err = NULL;
3245 while (*str) {
3246 if (*str == '\\') {
3247 err = str; /* in case of a backslash, we return the pointer to it */
3248 str++;
3249 if (!*str)
3250 return err;
3251 else if (isdigit((int)*str))
3252 err = NULL;
3253 else if (*str == 'x') {
3254 str++;
3255 if (!ishex(*str))
3256 return err;
3257 str++;
3258 if (!ishex(*str))
3259 return err;
3260 err = NULL;
3261 }
3262 else {
3263 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3264 err = NULL;
3265 }
3266 }
3267 str++;
3268 }
3269 return err;
3270}
3271
3272
willy tarreau9fe663a2005-12-17 13:02:59 +01003273
willy tarreau0f7af912005-12-17 12:21:26 +01003274/*
3275 * manages the client FSM and its socket. BTW, it also tries to handle the
3276 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3277 * 0 else.
3278 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003279int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003280 int s = t->srv_state;
3281 int c = t->cli_state;
3282 struct buffer *req = t->req;
3283 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003284 int method_checked = 0;
3285 appsess *asession_temp = NULL;
3286 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003287
willy tarreau750a4722005-12-17 13:21:24 +01003288#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003289 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3290 cli_stnames[c], srv_stnames[s],
3291 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3292 t->crexpire.tv_sec, t->crexpire.tv_usec,
3293 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003294#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003295 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3296 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3297 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3298 //);
3299 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003300 /* now parse the partial (or complete) headers */
3301 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3302 char *ptr;
3303 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003304 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003305
willy tarreau5cbea6f2005-12-17 12:48:26 +01003306 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003307
willy tarreau0f7af912005-12-17 12:21:26 +01003308 /* look for the end of the current header */
3309 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3310 ptr++;
3311
willy tarreau5cbea6f2005-12-17 12:48:26 +01003312 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003313 int line, len;
3314 /* we can only get here after an end of headers */
3315 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003316
willy tarreaue39cd132005-12-17 13:00:18 +01003317 if (t->flags & SN_CLDENY) {
3318 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003319 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003320 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003321 if (!(t->flags & SN_ERR_MASK))
3322 t->flags |= SN_ERR_PRXCOND;
3323 if (!(t->flags & SN_FINST_MASK))
3324 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003325 return 1;
3326 }
3327
willy tarreau5cbea6f2005-12-17 12:48:26 +01003328 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003329 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3330 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003331 }
willy tarreau0f7af912005-12-17 12:21:26 +01003332
willy tarreau9fe663a2005-12-17 13:02:59 +01003333 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003334 if (t->cli_addr.ss_family == AF_INET) {
3335 unsigned char *pn;
3336 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3337 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3338 pn[0], pn[1], pn[2], pn[3]);
3339 buffer_replace2(req, req->h, req->h, trash, len);
3340 }
3341 else if (t->cli_addr.ss_family == AF_INET6) {
3342 char pn[INET6_ADDRSTRLEN];
3343 inet_ntop(AF_INET6,
3344 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3345 pn, sizeof(pn));
3346 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3347 buffer_replace2(req, req->h, req->h, trash, len);
3348 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003349 }
3350
willy tarreau25c4ea52005-12-18 00:49:49 +01003351 /* add a "connection: close" line if needed */
3352 if (t->proxy->options & PR_O_HTTP_CLOSE)
3353 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3354
willy tarreau982249e2005-12-18 00:57:06 +01003355 if (!memcmp(req->data, "POST ", 5)) {
3356 /* this is a POST request, which is not cacheable by default */
3357 t->flags |= SN_POST;
3358 }
willy tarreaucd878942005-12-17 13:27:43 +01003359
willy tarreau5cbea6f2005-12-17 12:48:26 +01003360 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003361 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003362
willy tarreau750a4722005-12-17 13:21:24 +01003363 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003364 /* FIXME: we'll set the client in a wait state while we try to
3365 * connect to the server. Is this really needed ? wouldn't it be
3366 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003367 //FD_CLR(t->cli_fd, StaticReadEvent);
3368 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003369
3370 /* FIXME: if we break here (as up to 1.1.23), having the client
3371 * shutdown its connection can lead to an abort further.
3372 * it's better to either return 1 or even jump directly to the
3373 * data state which will save one schedule.
3374 */
3375 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003376
3377 if (!t->proxy->clitimeout ||
3378 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3379 /* If the client has no timeout, or if the server is not ready yet,
3380 * and we know for sure that it can expire, then it's cleaner to
3381 * disable the timeout on the client side so that too low values
3382 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003383 *
3384 * FIXME-20050705: the server needs a way to re-enable this time-out
3385 * when it switches its state, otherwise a client can stay connected
3386 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003387 */
3388 tv_eternity(&t->crexpire);
3389
willy tarreau197e8ec2005-12-17 14:10:59 +01003390 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003391 }
willy tarreau0f7af912005-12-17 12:21:26 +01003392
Willy TARREAU13032e72006-03-12 17:31:45 +01003393 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3394 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003395 /* this is a partial header, let's wait for more to come */
3396 req->lr = ptr;
3397 break;
3398 }
willy tarreau0f7af912005-12-17 12:21:26 +01003399
willy tarreau5cbea6f2005-12-17 12:48:26 +01003400 /* now we know that *ptr is either \r or \n,
3401 * and that there are at least 1 char after it.
3402 */
3403 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3404 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3405 else
3406 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003407
willy tarreau5cbea6f2005-12-17 12:48:26 +01003408 /*
3409 * now we know that we have a full header ; we can do whatever
3410 * we want with these pointers :
3411 * req->h = beginning of header
3412 * ptr = end of header (first \r or \n)
3413 * req->lr = beginning of next line (next rep->h)
3414 * req->r = end of data (not used at this stage)
3415 */
willy tarreau0f7af912005-12-17 12:21:26 +01003416
willy tarreau12350152005-12-18 01:03:27 +01003417 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3418 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3419 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3420
3421 /* skip ; */
3422 request_line++;
3423
3424 /* look if we have a jsessionid */
3425
3426 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3427
3428 /* skip jsessionid= */
3429 request_line += t->proxy->appsession_name_len + 1;
3430
3431 /* First try if we allready have an appsession */
3432 asession_temp = &local_asession;
3433
3434 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3435 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3436 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3437 return 0;
3438 }
3439
3440 /* Copy the sessionid */
3441 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3442 asession_temp->sessid[t->proxy->appsession_len] = 0;
3443 asession_temp->serverid = NULL;
3444
3445 /* only do insert, if lookup fails */
3446 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3447 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3448 Alert("Not enough memory process_cli():asession:calloc().\n");
3449 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3450 return 0;
3451 }
3452 asession_temp->sessid = local_asession.sessid;
3453 asession_temp->serverid = local_asession.serverid;
3454 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003455 } /* end if (chtbl_lookup()) */
3456 else {
willy tarreau12350152005-12-18 01:03:27 +01003457 /*free wasted memory;*/
3458 pool_free_to(apools.sessid, local_asession.sessid);
3459 }
3460
3461 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3462 asession_temp->request_count++;
3463
3464#if defined(DEBUG_HASH)
3465 print_table(&(t->proxy->htbl_proxy));
3466#endif
3467
3468 if (asession_temp->serverid == NULL) {
3469 Alert("Found Application Session without matching server.\n");
3470 } else {
3471 struct server *srv = t->proxy->srv;
3472 while (srv) {
3473 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3474 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3475 /* we found the server and it's usable */
3476 t->flags &= ~SN_CK_MASK;
3477 t->flags |= SN_CK_VALID | SN_DIRECT;
3478 t->srv = srv;
3479 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003480 } else {
willy tarreau12350152005-12-18 01:03:27 +01003481 t->flags &= ~SN_CK_MASK;
3482 t->flags |= SN_CK_DOWN;
3483 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003484 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003485 srv = srv->next;
3486 }/* end while(srv) */
3487 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003488 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003489 else {
3490 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3491 }
willy tarreau598da412005-12-18 01:07:29 +01003492 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003493 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003494 else{
3495 //printf("No Methode-Header with Session-String\n");
3496 }
3497
willy tarreau8337c6b2005-12-17 13:41:01 +01003498 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003499 /* we have a complete HTTP request that we must log */
3500 int urilen;
3501
willy tarreaua1598082005-12-17 13:08:06 +01003502 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003503 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003504 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003505 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003506 if (!(t->flags & SN_ERR_MASK))
3507 t->flags |= SN_ERR_PRXCOND;
3508 if (!(t->flags & SN_FINST_MASK))
3509 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003510 return 1;
3511 }
3512
3513 urilen = ptr - req->h;
3514 if (urilen >= REQURI_LEN)
3515 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003516 memcpy(t->logs.uri, req->h, urilen);
3517 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003518
willy tarreaua1598082005-12-17 13:08:06 +01003519 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003520 sess_log(t);
3521 }
willy tarreau4302f492005-12-18 01:00:37 +01003522 else if (t->logs.logwait & LW_REQHDR) {
3523 struct cap_hdr *h;
3524 int len;
3525 for (h = t->proxy->req_cap; h; h = h->next) {
3526 if ((h->namelen + 2 <= ptr - req->h) &&
3527 (req->h[h->namelen] == ':') &&
3528 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3529
3530 if (t->req_cap[h->index] == NULL)
3531 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3532
3533 len = ptr - (req->h + h->namelen + 2);
3534 if (len > h->len)
3535 len = h->len;
3536
3537 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3538 t->req_cap[h->index][len]=0;
3539 }
3540 }
3541
3542 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003543
willy tarreau5cbea6f2005-12-17 12:48:26 +01003544 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003545
willy tarreau982249e2005-12-18 00:57:06 +01003546 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003547 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003548 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 +01003549 max = ptr - req->h;
3550 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003551 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003552 trash[len++] = '\n';
3553 write(1, trash, len);
3554 }
willy tarreau0f7af912005-12-17 12:21:26 +01003555
willy tarreau25c4ea52005-12-18 00:49:49 +01003556
3557 /* remove "connection: " if needed */
3558 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3559 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3560 delete_header = 1;
3561 }
3562
willy tarreau5cbea6f2005-12-17 12:48:26 +01003563 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003564 if (!delete_header && t->proxy->req_exp != NULL
3565 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003566 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003567 char term;
3568
3569 term = *ptr;
3570 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003571 exp = t->proxy->req_exp;
3572 do {
3573 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3574 switch (exp->action) {
3575 case ACT_ALLOW:
3576 if (!(t->flags & SN_CLDENY))
3577 t->flags |= SN_CLALLOW;
3578 break;
3579 case ACT_REPLACE:
3580 if (!(t->flags & SN_CLDENY)) {
3581 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3582 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3583 }
3584 break;
3585 case ACT_REMOVE:
3586 if (!(t->flags & SN_CLDENY))
3587 delete_header = 1;
3588 break;
3589 case ACT_DENY:
3590 if (!(t->flags & SN_CLALLOW))
3591 t->flags |= SN_CLDENY;
3592 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003593 case ACT_PASS: /* we simply don't deny this one */
3594 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003595 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003596 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003597 }
willy tarreaue39cd132005-12-17 13:00:18 +01003598 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003599 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003600 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003601
willy tarreau240afa62005-12-17 13:14:35 +01003602 /* Now look for cookies. Conforming to RFC2109, we have to support
3603 * attributes whose name begin with a '$', and associate them with
3604 * the right cookie, if we want to delete this cookie.
3605 * So there are 3 cases for each cookie read :
3606 * 1) it's a special attribute, beginning with a '$' : ignore it.
3607 * 2) it's a server id cookie that we *MAY* want to delete : save
3608 * some pointers on it (last semi-colon, beginning of cookie...)
3609 * 3) it's an application cookie : we *MAY* have to delete a previous
3610 * "special" cookie.
3611 * At the end of loop, if a "special" cookie remains, we may have to
3612 * remove it. If no application cookie persists in the header, we
3613 * *MUST* delete it
3614 */
willy tarreau12350152005-12-18 01:03:27 +01003615 if (!delete_header &&
3616 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003617 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003618 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003619 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003620 char *del_colon, *del_cookie, *colon;
3621 int app_cookies;
3622
willy tarreau5cbea6f2005-12-17 12:48:26 +01003623 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003624 colon = p1;
3625 /* del_cookie == NULL => nothing to be deleted */
3626 del_colon = del_cookie = NULL;
3627 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003628
3629 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003630 /* skip spaces and colons, but keep an eye on these ones */
3631 while (p1 < ptr) {
3632 if (*p1 == ';' || *p1 == ',')
3633 colon = p1;
3634 else if (!isspace((int)*p1))
3635 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003636 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003637 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003638
3639 if (p1 == ptr)
3640 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641
3642 /* p1 is at the beginning of the cookie name */
3643 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003644 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003645 p2++;
3646
3647 if (p2 == ptr)
3648 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003649
3650 p3 = p2 + 1; /* skips the '=' sign */
3651 if (p3 == ptr)
3652 break;
3653
willy tarreau240afa62005-12-17 13:14:35 +01003654 p4 = p3;
3655 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003656 p4++;
3657
3658 /* here, we have the cookie name between p1 and p2,
3659 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003660 * we can process it :
3661 *
3662 * Cookie: NAME=VALUE;
3663 * | || || |
3664 * | || || +--> p4
3665 * | || |+-------> p3
3666 * | || +--------> p2
3667 * | |+------------> p1
3668 * | +-------------> colon
3669 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003670 */
3671
willy tarreau240afa62005-12-17 13:14:35 +01003672 if (*p1 == '$') {
3673 /* skip this one */
3674 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003675 else {
3676 /* first, let's see if we want to capture it */
3677 if (t->proxy->capture_name != NULL &&
3678 t->logs.cli_cookie == NULL &&
3679 (p4 - p1 >= t->proxy->capture_namelen) &&
3680 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3681 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003682
willy tarreau8337c6b2005-12-17 13:41:01 +01003683 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3684 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003685 } else {
3686 if (log_len > t->proxy->capture_len)
3687 log_len = t->proxy->capture_len;
3688 memcpy(t->logs.cli_cookie, p1, log_len);
3689 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003690 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003691 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003692
3693 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3694 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3695 /* Cool... it's the right one */
3696 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003697 char *delim;
3698
3699 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3700 * have the server ID betweek p3 and delim, and the original cookie between
3701 * delim+1 and p4. Otherwise, delim==p4 :
3702 *
3703 * Cookie: NAME=SRV~VALUE;
3704 * | || || | |
3705 * | || || | +--> p4
3706 * | || || +--------> delim
3707 * | || |+-----------> p3
3708 * | || +------------> p2
3709 * | |+----------------> p1
3710 * | +-----------------> colon
3711 * +------------------------> req->h
3712 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003713
willy tarreau0174f312005-12-18 01:02:42 +01003714 if (t->proxy->options & PR_O_COOK_PFX) {
3715 for (delim = p3; delim < p4; delim++)
3716 if (*delim == COOKIE_DELIM)
3717 break;
3718 }
3719 else
3720 delim = p4;
3721
3722
3723 /* Here, we'll look for the first running server which supports the cookie.
3724 * This allows to share a same cookie between several servers, for example
3725 * to dedicate backup servers to specific servers only.
3726 */
3727 while (srv) {
3728 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3729 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3730 /* we found the server and it's usable */
3731 t->flags &= ~SN_CK_MASK;
3732 t->flags |= SN_CK_VALID | SN_DIRECT;
3733 t->srv = srv;
3734 break;
willy tarreau12350152005-12-18 01:03:27 +01003735 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003736 /* we found a server, but it's down */
3737 t->flags &= ~SN_CK_MASK;
3738 t->flags |= SN_CK_DOWN;
3739 }
3740 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003741 srv = srv->next;
3742 }
3743
willy tarreau0174f312005-12-18 01:02:42 +01003744 if (!srv && !(t->flags & SN_CK_DOWN)) {
3745 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003746 t->flags &= ~SN_CK_MASK;
3747 t->flags |= SN_CK_INVALID;
3748 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003749
willy tarreau0174f312005-12-18 01:02:42 +01003750 /* depending on the cookie mode, we may have to either :
3751 * - delete the complete cookie if we're in insert+indirect mode, so that
3752 * the server never sees it ;
3753 * - remove the server id from the cookie value, and tag the cookie as an
3754 * application cookie so that it does not get accidentely removed later,
3755 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003756 */
willy tarreau0174f312005-12-18 01:02:42 +01003757 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3758 buffer_replace2(req, p3, delim + 1, NULL, 0);
3759 p4 -= (delim + 1 - p3);
3760 ptr -= (delim + 1 - p3);
3761 del_cookie = del_colon = NULL;
3762 app_cookies++; /* protect the header from deletion */
3763 }
3764 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003765 (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 +01003766 del_cookie = p1;
3767 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003768 }
willy tarreau12350152005-12-18 01:03:27 +01003769 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003770 /* now we know that we must keep this cookie since it's
3771 * not ours. But if we wanted to delete our cookie
3772 * earlier, we cannot remove the complete header, but we
3773 * can remove the previous block itself.
3774 */
3775 app_cookies++;
3776
3777 if (del_cookie != NULL) {
3778 buffer_replace2(req, del_cookie, p1, NULL, 0);
3779 p4 -= (p1 - del_cookie);
3780 ptr -= (p1 - del_cookie);
3781 del_cookie = del_colon = NULL;
3782 }
willy tarreau240afa62005-12-17 13:14:35 +01003783 }
willy tarreau12350152005-12-18 01:03:27 +01003784
3785 if ((t->proxy->appsession_name != NULL) &&
3786 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3787 /* first, let's see if the cookie is our appcookie*/
3788
3789 /* Cool... it's the right one */
3790
3791 asession_temp = &local_asession;
3792
3793 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3794 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3795 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3796 return 0;
3797 }
3798
3799 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3800 asession_temp->sessid[t->proxy->appsession_len] = 0;
3801 asession_temp->serverid = NULL;
3802
3803 /* only do insert, if lookup fails */
3804 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3805 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3806 Alert("Not enough memory process_cli():asession:calloc().\n");
3807 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3808 return 0;
3809 }
3810
3811 asession_temp->sessid = local_asession.sessid;
3812 asession_temp->serverid = local_asession.serverid;
3813 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3814 }
3815 else{
3816 /* free wasted memory */
3817 pool_free_to(apools.sessid, local_asession.sessid);
3818 }
3819
3820 if (asession_temp->serverid == NULL) {
3821 Alert("Found Application Session without matching server.\n");
3822 } else {
3823 struct server *srv = t->proxy->srv;
3824 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003825 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003826 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3827 /* we found the server and it's usable */
3828 t->flags &= ~SN_CK_MASK;
3829 t->flags |= SN_CK_VALID | SN_DIRECT;
3830 t->srv = srv;
3831 break;
3832 } else {
3833 t->flags &= ~SN_CK_MASK;
3834 t->flags |= SN_CK_DOWN;
3835 }
3836 }
3837 srv = srv->next;
3838 }/* end while(srv) */
3839 }/* end else if server == NULL */
3840
3841 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003842 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003843 }
willy tarreau240afa62005-12-17 13:14:35 +01003844
willy tarreau5cbea6f2005-12-17 12:48:26 +01003845 /* we'll have to look for another cookie ... */
3846 p1 = p4;
3847 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003848
3849 /* There's no more cookie on this line.
3850 * We may have marked the last one(s) for deletion.
3851 * We must do this now in two ways :
3852 * - if there is no app cookie, we simply delete the header ;
3853 * - if there are app cookies, we must delete the end of the
3854 * string properly, including the colon/semi-colon before
3855 * the cookie name.
3856 */
3857 if (del_cookie != NULL) {
3858 if (app_cookies) {
3859 buffer_replace2(req, del_colon, ptr, NULL, 0);
3860 /* WARNING! <ptr> becomes invalid for now. If some code
3861 * below needs to rely on it before the end of the global
3862 * header loop, we need to correct it with this code :
3863 * ptr = del_colon;
3864 */
3865 }
3866 else
3867 delete_header = 1;
3868 }
3869 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003870
3871 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003872 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003873 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003874 }
willy tarreau240afa62005-12-17 13:14:35 +01003875 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3876
willy tarreau5cbea6f2005-12-17 12:48:26 +01003877 req->h = req->lr;
3878 } /* while (req->lr < req->r) */
3879
3880 /* end of header processing (even if incomplete) */
3881
willy tarreauef900ab2005-12-17 12:52:52 +01003882 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3883 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3884 * full. We cannot loop here since event_cli_read will disable it only if
3885 * req->l == rlim-data
3886 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003887 FD_SET(t->cli_fd, StaticReadEvent);
3888 if (t->proxy->clitimeout)
3889 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3890 else
3891 tv_eternity(&t->crexpire);
3892 }
3893
willy tarreaue39cd132005-12-17 13:00:18 +01003894 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003895 * won't be able to free more later, so the session will never terminate.
3896 */
willy tarreaue39cd132005-12-17 13:00:18 +01003897 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003898 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003899 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003900 if (!(t->flags & SN_ERR_MASK))
3901 t->flags |= SN_ERR_PRXCOND;
3902 if (!(t->flags & SN_FINST_MASK))
3903 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003904 return 1;
3905 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003906 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003907 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003908 tv_eternity(&t->crexpire);
3909 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003910 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003911 if (!(t->flags & SN_ERR_MASK))
3912 t->flags |= SN_ERR_CLICL;
3913 if (!(t->flags & SN_FINST_MASK))
3914 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003915 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003916 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003917 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3918
3919 /* read timeout : give up with an error message.
3920 */
3921 t->logs.status = 408;
3922 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003923 if (!(t->flags & SN_ERR_MASK))
3924 t->flags |= SN_ERR_CLITO;
3925 if (!(t->flags & SN_FINST_MASK))
3926 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003927 return 1;
3928 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003929
3930 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003931 }
3932 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003933 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003934 /* FIXME: this error handling is partly buggy because we always report
3935 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3936 * or HEADER phase. BTW, it's not logical to expire the client while
3937 * we're waiting for the server to connect.
3938 */
willy tarreau0f7af912005-12-17 12:21:26 +01003939 /* read or write error */
3940 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003941 tv_eternity(&t->crexpire);
3942 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003943 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003944 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003945 if (!(t->flags & SN_ERR_MASK))
3946 t->flags |= SN_ERR_CLICL;
3947 if (!(t->flags & SN_FINST_MASK))
3948 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003949 return 1;
3950 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003951 /* last read, or end of server write */
3952 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003953 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003954 tv_eternity(&t->crexpire);
3955 shutdown(t->cli_fd, SHUT_RD);
3956 t->cli_state = CL_STSHUTR;
3957 return 1;
3958 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003959 /* last server read and buffer empty */
3960 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003961 FD_CLR(t->cli_fd, StaticWriteEvent);
3962 tv_eternity(&t->cwexpire);
3963 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003964 /* We must ensure that the read part is still alive when switching
3965 * to shutw */
3966 FD_SET(t->cli_fd, StaticReadEvent);
3967 if (t->proxy->clitimeout)
3968 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003969 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003970 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01003971 return 1;
3972 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003973 /* read timeout */
3974 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3975 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003976 tv_eternity(&t->crexpire);
3977 shutdown(t->cli_fd, SHUT_RD);
3978 t->cli_state = CL_STSHUTR;
3979 if (!(t->flags & SN_ERR_MASK))
3980 t->flags |= SN_ERR_CLITO;
3981 if (!(t->flags & SN_FINST_MASK))
3982 t->flags |= SN_FINST_D;
3983 return 1;
3984 }
3985 /* write timeout */
3986 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3987 FD_CLR(t->cli_fd, StaticWriteEvent);
3988 tv_eternity(&t->cwexpire);
3989 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003990 /* We must ensure that the read part is still alive when switching
3991 * to shutw */
3992 FD_SET(t->cli_fd, StaticReadEvent);
3993 if (t->proxy->clitimeout)
3994 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3995
willy tarreau036e1ce2005-12-17 13:46:33 +01003996 t->cli_state = CL_STSHUTW;
3997 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003998 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003999 if (!(t->flags & SN_FINST_MASK))
4000 t->flags |= SN_FINST_D;
4001 return 1;
4002 }
willy tarreau0f7af912005-12-17 12:21:26 +01004003
willy tarreauc58fc692005-12-17 14:13:08 +01004004 if (req->l >= req->rlim - req->data) {
4005 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004006 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004007 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004008 FD_CLR(t->cli_fd, StaticReadEvent);
4009 tv_eternity(&t->crexpire);
4010 }
4011 }
4012 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004013 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004014 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4015 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004016 if (!t->proxy->clitimeout ||
4017 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4018 /* If the client has no timeout, or if the server not ready yet, and we
4019 * know for sure that it can expire, then it's cleaner to disable the
4020 * timeout on the client side so that too low values cannot make the
4021 * sessions abort too early.
4022 */
willy tarreau0f7af912005-12-17 12:21:26 +01004023 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004024 else
4025 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004026 }
4027 }
4028
4029 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004030 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004031 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4032 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4033 tv_eternity(&t->cwexpire);
4034 }
4035 }
4036 else { /* buffer not empty */
4037 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4038 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004039 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004040 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004041 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4042 t->crexpire = t->cwexpire;
4043 }
willy tarreau0f7af912005-12-17 12:21:26 +01004044 else
4045 tv_eternity(&t->cwexpire);
4046 }
4047 }
4048 return 0; /* other cases change nothing */
4049 }
4050 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004051 if (t->res_cw == RES_ERROR) {
4052 tv_eternity(&t->cwexpire);
4053 fd_delete(t->cli_fd);
4054 t->cli_state = CL_STCLOSE;
4055 if (!(t->flags & SN_ERR_MASK))
4056 t->flags |= SN_ERR_CLICL;
4057 if (!(t->flags & SN_FINST_MASK))
4058 t->flags |= SN_FINST_D;
4059 return 1;
4060 }
4061 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004062 tv_eternity(&t->cwexpire);
4063 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004064 t->cli_state = CL_STCLOSE;
4065 return 1;
4066 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004067 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4068 tv_eternity(&t->cwexpire);
4069 fd_delete(t->cli_fd);
4070 t->cli_state = CL_STCLOSE;
4071 if (!(t->flags & SN_ERR_MASK))
4072 t->flags |= SN_ERR_CLITO;
4073 if (!(t->flags & SN_FINST_MASK))
4074 t->flags |= SN_FINST_D;
4075 return 1;
4076 }
willy tarreau0f7af912005-12-17 12:21:26 +01004077 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004078 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004079 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4080 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4081 tv_eternity(&t->cwexpire);
4082 }
4083 }
4084 else { /* buffer not empty */
4085 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4086 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004087 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004088 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004089 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4090 t->crexpire = t->cwexpire;
4091 }
willy tarreau0f7af912005-12-17 12:21:26 +01004092 else
4093 tv_eternity(&t->cwexpire);
4094 }
4095 }
4096 return 0;
4097 }
4098 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004099 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004100 tv_eternity(&t->crexpire);
4101 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004102 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004103 if (!(t->flags & SN_ERR_MASK))
4104 t->flags |= SN_ERR_CLICL;
4105 if (!(t->flags & SN_FINST_MASK))
4106 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004107 return 1;
4108 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004109 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4110 tv_eternity(&t->crexpire);
4111 fd_delete(t->cli_fd);
4112 t->cli_state = CL_STCLOSE;
4113 return 1;
4114 }
4115 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4116 tv_eternity(&t->crexpire);
4117 fd_delete(t->cli_fd);
4118 t->cli_state = CL_STCLOSE;
4119 if (!(t->flags & SN_ERR_MASK))
4120 t->flags |= SN_ERR_CLITO;
4121 if (!(t->flags & SN_FINST_MASK))
4122 t->flags |= SN_FINST_D;
4123 return 1;
4124 }
willy tarreauef900ab2005-12-17 12:52:52 +01004125 else if (req->l >= req->rlim - req->data) {
4126 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004127
4128 /* FIXME-20050705: is it possible for a client to maintain a session
4129 * after the timeout by sending more data after it receives a close ?
4130 */
4131
willy tarreau0f7af912005-12-17 12:21:26 +01004132 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004133 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004134 FD_CLR(t->cli_fd, StaticReadEvent);
4135 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004136 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01004137 }
4138 }
4139 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004140 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004141 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4142 FD_SET(t->cli_fd, StaticReadEvent);
4143 if (t->proxy->clitimeout)
4144 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4145 else
4146 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004147 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01004148 }
4149 }
4150 return 0;
4151 }
4152 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004153 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004154 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004155 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 +01004156 write(1, trash, len);
4157 }
4158 return 0;
4159 }
4160 return 0;
4161}
4162
4163
4164/*
4165 * manages the server FSM and its socket. It returns 1 if a state has changed
4166 * (and a resync may be needed), 0 else.
4167 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004168int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004169 int s = t->srv_state;
4170 int c = t->cli_state;
4171 struct buffer *req = t->req;
4172 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004173 appsess *asession_temp = NULL;
4174 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004175 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004176
willy tarreau750a4722005-12-17 13:21:24 +01004177#ifdef DEBUG_FULL
4178 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4179#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004180 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4181 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4182 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4183 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004184 if (s == SV_STIDLE) {
4185 if (c == CL_STHEADERS)
4186 return 0; /* stay in idle, waiting for data to reach the client side */
4187 else if (c == CL_STCLOSE ||
4188 c == CL_STSHUTW ||
4189 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4190 tv_eternity(&t->cnexpire);
4191 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004192 if (!(t->flags & SN_ERR_MASK))
4193 t->flags |= SN_ERR_CLICL;
4194 if (!(t->flags & SN_FINST_MASK))
4195 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004196 return 1;
4197 }
4198 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004199 /* initiate a connection to the server */
4200 conn_err = connect_server(t);
4201 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004202 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4203 t->srv_state = SV_STCONN;
4204 }
4205 else { /* try again */
4206 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004207 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004208 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004209 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004210 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4211 t->flags &= ~SN_CK_MASK;
4212 t->flags |= SN_CK_DOWN;
4213 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004214 }
4215
willy tarreaub1285d52005-12-18 01:20:14 +01004216 conn_err = connect_server(t);
4217 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004218 t->srv_state = SV_STCONN;
4219 break;
4220 }
4221 }
4222 if (t->conn_retries < 0) {
4223 /* if conn_retries < 0 or other error, let's abort */
4224 tv_eternity(&t->cnexpire);
4225 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004226 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004227 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004228 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004229 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004230 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004231 if (!(t->flags & SN_FINST_MASK))
4232 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004233 }
4234 }
4235 return 1;
4236 }
4237 }
4238 else if (s == SV_STCONN) { /* connection in progress */
4239 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004240 //fprintf(stderr,"1: c=%d, s=%d, now=%d.%06d, exp=%d.%06d\n", c, s, now.tv_sec, now.tv_usec, t->cnexpire.tv_sec, t->cnexpire.tv_usec);
willy tarreau0f7af912005-12-17 12:21:26 +01004241 return 0; /* nothing changed */
4242 }
4243 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4244 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4245 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004246 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004247 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004248 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004249 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004250 if (t->conn_retries >= 0) {
4251 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004252 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004253 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004254 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4255 t->flags &= ~SN_CK_MASK;
4256 t->flags |= SN_CK_DOWN;
4257 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004258 }
willy tarreaub1285d52005-12-18 01:20:14 +01004259 conn_err = connect_server(t);
4260 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004261 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004262 }
willy tarreaub1285d52005-12-18 01:20:14 +01004263 else if (t->res_sw == RES_SILENT)
4264 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4265 else
4266 conn_err = SN_ERR_SRVCL; // it was a connect error.
4267
willy tarreau0f7af912005-12-17 12:21:26 +01004268 /* if conn_retries < 0 or other error, let's abort */
4269 tv_eternity(&t->cnexpire);
4270 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004271 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004272 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004273 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004274 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004275 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004276 if (!(t->flags & SN_FINST_MASK))
4277 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004278 return 1;
4279 }
4280 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004281 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004282
willy tarreau0f7af912005-12-17 12:21:26 +01004283 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004284 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004285 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004286 tv_eternity(&t->swexpire);
4287 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004288 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004289 if (t->proxy->srvtimeout) {
4290 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4291 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4292 t->srexpire = t->swexpire;
4293 }
4294 else
4295 tv_eternity(&t->swexpire);
4296 }
willy tarreau0f7af912005-12-17 12:21:26 +01004297
4298 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4299 FD_SET(t->srv_fd, StaticReadEvent);
4300 if (t->proxy->srvtimeout)
4301 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4302 else
4303 tv_eternity(&t->srexpire);
4304
4305 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004306 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004307
4308 /* if the user wants to log as soon as possible, without counting
4309 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004310 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004311 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4312 sess_log(t);
4313 }
willy tarreau0f7af912005-12-17 12:21:26 +01004314 }
willy tarreauef900ab2005-12-17 12:52:52 +01004315 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004316 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004317 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4318 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004319 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004320 return 1;
4321 }
4322 }
4323 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004324 /* now parse the partial (or complete) headers */
4325 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4326 char *ptr;
4327 int delete_header;
4328
4329 ptr = rep->lr;
4330
4331 /* look for the end of the current header */
4332 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4333 ptr++;
4334
4335 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004336 int line, len;
4337
4338 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004339
4340 /* first, we'll block if security checks have caught nasty things */
4341 if (t->flags & SN_CACHEABLE) {
4342 if ((t->flags & SN_CACHE_COOK) &&
4343 (t->flags & SN_SCK_ANY) &&
4344 (t->proxy->options & PR_O_CHK_CACHE)) {
4345
4346 /* we're in presence of a cacheable response containing
4347 * a set-cookie header. We'll block it as requested by
4348 * the 'checkcache' option, and send an alert.
4349 */
4350 tv_eternity(&t->srexpire);
4351 tv_eternity(&t->swexpire);
4352 fd_delete(t->srv_fd);
4353 t->srv_state = SV_STCLOSE;
4354 t->logs.status = 502;
4355 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4356 if (!(t->flags & SN_ERR_MASK))
4357 t->flags |= SN_ERR_PRXCOND;
4358 if (!(t->flags & SN_FINST_MASK))
4359 t->flags |= SN_FINST_H;
4360
4361 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4362 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4363
4364 return 1;
4365 }
4366 }
4367
willy tarreau982249e2005-12-18 00:57:06 +01004368 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4369 if (t->flags & SN_SVDENY) {
4370 tv_eternity(&t->srexpire);
4371 tv_eternity(&t->swexpire);
4372 fd_delete(t->srv_fd);
4373 t->srv_state = SV_STCLOSE;
4374 t->logs.status = 502;
4375 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4376 if (!(t->flags & SN_ERR_MASK))
4377 t->flags |= SN_ERR_PRXCOND;
4378 if (!(t->flags & SN_FINST_MASK))
4379 t->flags |= SN_FINST_H;
4380 return 1;
4381 }
4382
willy tarreau5cbea6f2005-12-17 12:48:26 +01004383 /* we'll have something else to do here : add new headers ... */
4384
willy tarreaucd878942005-12-17 13:27:43 +01004385 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4386 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004387 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004388 * insert a set-cookie here, except if we want to insert only on POST
4389 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004390 */
willy tarreau750a4722005-12-17 13:21:24 +01004391 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004392 t->proxy->cookie_name,
4393 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004394
willy tarreau036e1ce2005-12-17 13:46:33 +01004395 t->flags |= SN_SCK_INSERTED;
4396
willy tarreau750a4722005-12-17 13:21:24 +01004397 /* Here, we will tell an eventual cache on the client side that we don't
4398 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4399 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4400 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4401 */
willy tarreau240afa62005-12-17 13:14:35 +01004402 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004403 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4404 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004405
4406 if (rep->data + rep->l < rep->h)
4407 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4408 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004409 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004410 }
4411
4412 /* headers to be added */
4413 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004414 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4415 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004416 }
4417
willy tarreau25c4ea52005-12-18 00:49:49 +01004418 /* add a "connection: close" line if needed */
4419 if (t->proxy->options & PR_O_HTTP_CLOSE)
4420 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4421
willy tarreau5cbea6f2005-12-17 12:48:26 +01004422 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004423 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004424 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004425
Willy TARREAU767ba712006-03-01 22:40:50 +01004426 /* client connection already closed or option 'httpclose' required :
4427 * we close the server's outgoing connection right now.
4428 */
4429 if ((req->l == 0) &&
4430 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4431 FD_CLR(t->srv_fd, StaticWriteEvent);
4432 tv_eternity(&t->swexpire);
4433
4434 /* We must ensure that the read part is still alive when switching
4435 * to shutw */
4436 FD_SET(t->srv_fd, StaticReadEvent);
4437 if (t->proxy->srvtimeout)
4438 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4439
4440 shutdown(t->srv_fd, SHUT_WR);
4441 t->srv_state = SV_STSHUTW;
4442 }
4443
willy tarreau25c4ea52005-12-18 00:49:49 +01004444 /* if the user wants to log as soon as possible, without counting
4445 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004446 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004447 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4448 t->logs.bytes = rep->h - rep->data;
4449 sess_log(t);
4450 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004451 break;
4452 }
4453
4454 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4455 if (ptr > rep->r - 2) {
4456 /* this is a partial header, let's wait for more to come */
4457 rep->lr = ptr;
4458 break;
4459 }
4460
4461 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4462 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4463
4464 /* now we know that *ptr is either \r or \n,
4465 * and that there are at least 1 char after it.
4466 */
4467 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4468 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4469 else
4470 rep->lr = ptr + 2; /* \r\n or \n\r */
4471
4472 /*
4473 * now we know that we have a full header ; we can do whatever
4474 * we want with these pointers :
4475 * rep->h = beginning of header
4476 * ptr = end of header (first \r or \n)
4477 * rep->lr = beginning of next line (next rep->h)
4478 * rep->r = end of data (not used at this stage)
4479 */
4480
willy tarreaua1598082005-12-17 13:08:06 +01004481
willy tarreau982249e2005-12-18 00:57:06 +01004482 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004483 t->logs.logwait &= ~LW_RESP;
4484 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004485 switch (t->logs.status) {
4486 case 200:
4487 case 203:
4488 case 206:
4489 case 300:
4490 case 301:
4491 case 410:
4492 /* RFC2616 @13.4:
4493 * "A response received with a status code of
4494 * 200, 203, 206, 300, 301 or 410 MAY be stored
4495 * by a cache (...) unless a cache-control
4496 * directive prohibits caching."
4497 *
4498 * RFC2616 @9.5: POST method :
4499 * "Responses to this method are not cacheable,
4500 * unless the response includes appropriate
4501 * Cache-Control or Expires header fields."
4502 */
4503 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4504 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4505 break;
4506 default:
4507 break;
4508 }
willy tarreau4302f492005-12-18 01:00:37 +01004509 }
4510 else if (t->logs.logwait & LW_RSPHDR) {
4511 struct cap_hdr *h;
4512 int len;
4513 for (h = t->proxy->rsp_cap; h; h = h->next) {
4514 if ((h->namelen + 2 <= ptr - rep->h) &&
4515 (rep->h[h->namelen] == ':') &&
4516 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4517
4518 if (t->rsp_cap[h->index] == NULL)
4519 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4520
4521 len = ptr - (rep->h + h->namelen + 2);
4522 if (len > h->len)
4523 len = h->len;
4524
4525 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4526 t->rsp_cap[h->index][len]=0;
4527 }
4528 }
4529
willy tarreaua1598082005-12-17 13:08:06 +01004530 }
4531
willy tarreau5cbea6f2005-12-17 12:48:26 +01004532 delete_header = 0;
4533
willy tarreau982249e2005-12-18 00:57:06 +01004534 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004535 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004536 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 +01004537 max = ptr - rep->h;
4538 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004539 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004540 trash[len++] = '\n';
4541 write(1, trash, len);
4542 }
4543
willy tarreau25c4ea52005-12-18 00:49:49 +01004544 /* remove "connection: " if needed */
4545 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4546 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4547 delete_header = 1;
4548 }
4549
willy tarreau5cbea6f2005-12-17 12:48:26 +01004550 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004551 if (!delete_header && t->proxy->rsp_exp != NULL
4552 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004553 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004554 char term;
4555
4556 term = *ptr;
4557 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004558 exp = t->proxy->rsp_exp;
4559 do {
4560 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4561 switch (exp->action) {
4562 case ACT_ALLOW:
4563 if (!(t->flags & SN_SVDENY))
4564 t->flags |= SN_SVALLOW;
4565 break;
4566 case ACT_REPLACE:
4567 if (!(t->flags & SN_SVDENY)) {
4568 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4569 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4570 }
4571 break;
4572 case ACT_REMOVE:
4573 if (!(t->flags & SN_SVDENY))
4574 delete_header = 1;
4575 break;
4576 case ACT_DENY:
4577 if (!(t->flags & SN_SVALLOW))
4578 t->flags |= SN_SVDENY;
4579 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004580 case ACT_PASS: /* we simply don't deny this one */
4581 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004582 }
4583 break;
4584 }
willy tarreaue39cd132005-12-17 13:00:18 +01004585 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004586 *ptr = term; /* restore the string terminator */
4587 }
4588
willy tarreau97f58572005-12-18 00:53:44 +01004589 /* check for cache-control: or pragma: headers */
4590 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4591 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4592 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4593 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4594 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004595 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004596 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4597 else {
4598 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004599 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004600 t->flags &= ~SN_CACHE_COOK;
4601 }
4602 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004603 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004604 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004605 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004606 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4607 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004608 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004609 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004610 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4611 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4612 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4613 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4614 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4615 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004616 }
4617 }
4618 }
4619
willy tarreau5cbea6f2005-12-17 12:48:26 +01004620 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004621 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004622 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004623 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004624 char *p1, *p2, *p3, *p4;
4625
willy tarreau97f58572005-12-18 00:53:44 +01004626 t->flags |= SN_SCK_ANY;
4627
willy tarreau5cbea6f2005-12-17 12:48:26 +01004628 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4629
4630 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004631 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004632 p1++;
4633
4634 if (p1 == ptr || *p1 == ';') /* end of cookie */
4635 break;
4636
4637 /* p1 is at the beginning of the cookie name */
4638 p2 = p1;
4639
4640 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4641 p2++;
4642
4643 if (p2 == ptr || *p2 == ';') /* next cookie */
4644 break;
4645
4646 p3 = p2 + 1; /* skips the '=' sign */
4647 if (p3 == ptr)
4648 break;
4649
4650 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004651 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004652 p4++;
4653
4654 /* here, we have the cookie name between p1 and p2,
4655 * and its value between p3 and p4.
4656 * we can process it.
4657 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004658
4659 /* first, let's see if we want to capture it */
4660 if (t->proxy->capture_name != NULL &&
4661 t->logs.srv_cookie == NULL &&
4662 (p4 - p1 >= t->proxy->capture_namelen) &&
4663 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4664 int log_len = p4 - p1;
4665
4666 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4667 Alert("HTTP logging : out of memory.\n");
4668 }
4669
4670 if (log_len > t->proxy->capture_len)
4671 log_len = t->proxy->capture_len;
4672 memcpy(t->logs.srv_cookie, p1, log_len);
4673 t->logs.srv_cookie[log_len] = 0;
4674 }
4675
4676 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4677 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004678 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004679 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004680
4681 /* If the cookie is in insert mode on a known server, we'll delete
4682 * this occurrence because we'll insert another one later.
4683 * We'll delete it too if the "indirect" option is set and we're in
4684 * a direct access. */
4685 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004686 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004687 /* this header must be deleted */
4688 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004689 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004690 }
4691 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4692 /* replace bytes p3->p4 with the cookie name associated
4693 * with this server since we know it.
4694 */
4695 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004696 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004697 }
willy tarreau0174f312005-12-18 01:02:42 +01004698 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4699 /* insert the cookie name associated with this server
4700 * before existing cookie, and insert a delimitor between them..
4701 */
4702 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4703 p3[t->srv->cklen] = COOKIE_DELIM;
4704 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4705 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004706 break;
4707 }
willy tarreau12350152005-12-18 01:03:27 +01004708
4709 /* first, let's see if the cookie is our appcookie*/
4710 if ((t->proxy->appsession_name != NULL) &&
4711 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4712
4713 /* Cool... it's the right one */
4714
willy tarreaub952e1d2005-12-18 01:31:20 +01004715 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004716 asession_temp = &local_asession;
4717
willy tarreaub952e1d2005-12-18 01:31:20 +01004718 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004719 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4720 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4721 }
4722 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4723 asession_temp->sessid[t->proxy->appsession_len] = 0;
4724 asession_temp->serverid = NULL;
4725
4726 /* only do insert, if lookup fails */
4727 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4728 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4729 Alert("Not enought Memory process_srv():asession:calloc().\n");
4730 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4731 return 0;
4732 }
4733 asession_temp->sessid = local_asession.sessid;
4734 asession_temp->serverid = local_asession.serverid;
4735 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004736 }/* end if (chtbl_lookup()) */
4737 else {
willy tarreau12350152005-12-18 01:03:27 +01004738 /* free wasted memory */
4739 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004740 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004741
willy tarreaub952e1d2005-12-18 01:31:20 +01004742 if (asession_temp->serverid == NULL) {
4743 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004744 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4745 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4746 }
4747 asession_temp->serverid[0] = '\0';
4748 }
4749
willy tarreaub952e1d2005-12-18 01:31:20 +01004750 if (asession_temp->serverid[0] == '\0')
4751 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004752
4753 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4754
4755#if defined(DEBUG_HASH)
4756 print_table(&(t->proxy->htbl_proxy));
4757#endif
4758 break;
4759 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004760 else {
4761 // fprintf(stderr,"Ignoring unknown cookie : ");
4762 // write(2, p1, p2-p1);
4763 // fprintf(stderr," = ");
4764 // write(2, p3, p4-p3);
4765 // fprintf(stderr,"\n");
4766 }
4767 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4768 } /* we're now at the end of the cookie value */
4769 } /* end of cookie processing */
4770
willy tarreau97f58572005-12-18 00:53:44 +01004771 /* check for any set-cookie in case we check for cacheability */
4772 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4773 (t->proxy->options & PR_O_CHK_CACHE) &&
4774 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4775 t->flags |= SN_SCK_ANY;
4776 }
4777
willy tarreau5cbea6f2005-12-17 12:48:26 +01004778 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004779 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004780 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004781
willy tarreau5cbea6f2005-12-17 12:48:26 +01004782 rep->h = rep->lr;
4783 } /* while (rep->lr < rep->r) */
4784
4785 /* end of header processing (even if incomplete) */
4786
willy tarreauef900ab2005-12-17 12:52:52 +01004787 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4788 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4789 * full. We cannot loop here since event_srv_read will disable it only if
4790 * rep->l == rlim-data
4791 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004792 FD_SET(t->srv_fd, StaticReadEvent);
4793 if (t->proxy->srvtimeout)
4794 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4795 else
4796 tv_eternity(&t->srexpire);
4797 }
willy tarreau0f7af912005-12-17 12:21:26 +01004798
willy tarreau8337c6b2005-12-17 13:41:01 +01004799 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004800 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004801 tv_eternity(&t->srexpire);
4802 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004803 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004804 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004805 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004806 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004807 if (!(t->flags & SN_ERR_MASK))
4808 t->flags |= SN_ERR_SRVCL;
4809 if (!(t->flags & SN_FINST_MASK))
4810 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004811 return 1;
4812 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004813 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004814 * since we are in header mode, if there's no space left for headers, we
4815 * won't be able to free more later, so the session will never terminate.
4816 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004817 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 +01004818 FD_CLR(t->srv_fd, StaticReadEvent);
4819 tv_eternity(&t->srexpire);
4820 shutdown(t->srv_fd, SHUT_RD);
4821 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004822 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01004823 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004824 }
4825 /* read timeout : return a 504 to the client.
4826 */
4827 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4828 tv_eternity(&t->srexpire);
4829 tv_eternity(&t->swexpire);
4830 fd_delete(t->srv_fd);
4831 t->srv_state = SV_STCLOSE;
4832 t->logs.status = 504;
4833 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004834 if (!(t->flags & SN_ERR_MASK))
4835 t->flags |= SN_ERR_SRVTO;
4836 if (!(t->flags & SN_FINST_MASK))
4837 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004838 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004839
4840 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004841 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004842 /* FIXME!!! here, we don't want to switch to SHUTW if the
4843 * client shuts read too early, because we may still have
4844 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004845 * The side-effect is that if the client completely closes its
4846 * connection during SV_STHEADER, the connection to the server
4847 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004848 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004849 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004850 FD_CLR(t->srv_fd, StaticWriteEvent);
4851 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004852
4853 /* We must ensure that the read part is still alive when switching
4854 * to shutw */
4855 FD_SET(t->srv_fd, StaticReadEvent);
4856 if (t->proxy->srvtimeout)
4857 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4858
willy tarreau0f7af912005-12-17 12:21:26 +01004859 shutdown(t->srv_fd, SHUT_WR);
4860 t->srv_state = SV_STSHUTW;
4861 return 1;
4862 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004863 /* write timeout */
4864 /* FIXME!!! here, we don't want to switch to SHUTW if the
4865 * client shuts read too early, because we may still have
4866 * some work to do on the headers.
4867 */
4868 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4869 FD_CLR(t->srv_fd, StaticWriteEvent);
4870 tv_eternity(&t->swexpire);
4871 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004872 /* We must ensure that the read part is still alive when switching
4873 * to shutw */
4874 FD_SET(t->srv_fd, StaticReadEvent);
4875 if (t->proxy->srvtimeout)
4876 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4877
4878 /* We must ensure that the read part is still alive when switching
4879 * to shutw */
4880 FD_SET(t->srv_fd, StaticReadEvent);
4881 if (t->proxy->srvtimeout)
4882 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4883
willy tarreau036e1ce2005-12-17 13:46:33 +01004884 t->srv_state = SV_STSHUTW;
4885 if (!(t->flags & SN_ERR_MASK))
4886 t->flags |= SN_ERR_SRVTO;
4887 if (!(t->flags & SN_FINST_MASK))
4888 t->flags |= SN_FINST_H;
4889 return 1;
4890 }
willy tarreau0f7af912005-12-17 12:21:26 +01004891
4892 if (req->l == 0) {
4893 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4894 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4895 tv_eternity(&t->swexpire);
4896 }
4897 }
4898 else { /* client buffer not empty */
4899 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4900 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004901 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004902 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004903 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4904 t->srexpire = t->swexpire;
4905 }
willy tarreau0f7af912005-12-17 12:21:26 +01004906 else
4907 tv_eternity(&t->swexpire);
4908 }
4909 }
4910
willy tarreau5cbea6f2005-12-17 12:48:26 +01004911 /* be nice with the client side which would like to send a complete header
4912 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4913 * would read all remaining data at once ! The client should not write past rep->lr
4914 * when the server is in header state.
4915 */
4916 //return header_processed;
4917 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004918 }
4919 else if (s == SV_STDATA) {
4920 /* read or write error */
4921 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004922 tv_eternity(&t->srexpire);
4923 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004924 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004925 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004926 if (!(t->flags & SN_ERR_MASK))
4927 t->flags |= SN_ERR_SRVCL;
4928 if (!(t->flags & SN_FINST_MASK))
4929 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004930 return 1;
4931 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004932 /* last read, or end of client write */
4933 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004934 FD_CLR(t->srv_fd, StaticReadEvent);
4935 tv_eternity(&t->srexpire);
4936 shutdown(t->srv_fd, SHUT_RD);
4937 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004938 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01004939 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004940 }
4941 /* end of client read and no more data to send */
4942 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4943 FD_CLR(t->srv_fd, StaticWriteEvent);
4944 tv_eternity(&t->swexpire);
4945 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004946 /* We must ensure that the read part is still alive when switching
4947 * to shutw */
4948 FD_SET(t->srv_fd, StaticReadEvent);
4949 if (t->proxy->srvtimeout)
4950 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4951
willy tarreaua41a8b42005-12-17 14:02:24 +01004952 t->srv_state = SV_STSHUTW;
4953 return 1;
4954 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004955 /* read timeout */
4956 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4957 FD_CLR(t->srv_fd, StaticReadEvent);
4958 tv_eternity(&t->srexpire);
4959 shutdown(t->srv_fd, SHUT_RD);
4960 t->srv_state = SV_STSHUTR;
4961 if (!(t->flags & SN_ERR_MASK))
4962 t->flags |= SN_ERR_SRVTO;
4963 if (!(t->flags & SN_FINST_MASK))
4964 t->flags |= SN_FINST_D;
4965 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004966 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004967 /* write timeout */
4968 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004969 FD_CLR(t->srv_fd, StaticWriteEvent);
4970 tv_eternity(&t->swexpire);
4971 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004972 /* We must ensure that the read part is still alive when switching
4973 * to shutw */
4974 FD_SET(t->srv_fd, StaticReadEvent);
4975 if (t->proxy->srvtimeout)
4976 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004977 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004978 if (!(t->flags & SN_ERR_MASK))
4979 t->flags |= SN_ERR_SRVTO;
4980 if (!(t->flags & SN_FINST_MASK))
4981 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004982 return 1;
4983 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004984
4985 /* recompute request time-outs */
4986 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004987 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4988 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4989 tv_eternity(&t->swexpire);
4990 }
4991 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004992 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004993 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4994 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004995 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004996 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004997 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4998 t->srexpire = t->swexpire;
4999 }
willy tarreau0f7af912005-12-17 12:21:26 +01005000 else
5001 tv_eternity(&t->swexpire);
5002 }
5003 }
5004
willy tarreaub1ff9db2005-12-17 13:51:03 +01005005 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005006 if (rep->l == BUFSIZE) { /* no room to read more data */
5007 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5008 FD_CLR(t->srv_fd, StaticReadEvent);
5009 tv_eternity(&t->srexpire);
5010 }
5011 }
5012 else {
5013 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5014 FD_SET(t->srv_fd, StaticReadEvent);
5015 if (t->proxy->srvtimeout)
5016 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5017 else
5018 tv_eternity(&t->srexpire);
5019 }
5020 }
5021
5022 return 0; /* other cases change nothing */
5023 }
5024 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005025 if (t->res_sw == RES_ERROR) {
5026 //FD_CLR(t->srv_fd, StaticWriteEvent);
5027 tv_eternity(&t->swexpire);
5028 fd_delete(t->srv_fd);
5029 //close(t->srv_fd);
5030 t->srv_state = SV_STCLOSE;
5031 if (!(t->flags & SN_ERR_MASK))
5032 t->flags |= SN_ERR_SRVCL;
5033 if (!(t->flags & SN_FINST_MASK))
5034 t->flags |= SN_FINST_D;
5035 return 1;
5036 }
5037 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005038 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005039 tv_eternity(&t->swexpire);
5040 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005041 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005042 t->srv_state = SV_STCLOSE;
5043 return 1;
5044 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005045 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5046 //FD_CLR(t->srv_fd, StaticWriteEvent);
5047 tv_eternity(&t->swexpire);
5048 fd_delete(t->srv_fd);
5049 //close(t->srv_fd);
5050 t->srv_state = SV_STCLOSE;
5051 if (!(t->flags & SN_ERR_MASK))
5052 t->flags |= SN_ERR_SRVTO;
5053 if (!(t->flags & SN_FINST_MASK))
5054 t->flags |= SN_FINST_D;
5055 return 1;
5056 }
willy tarreau0f7af912005-12-17 12:21:26 +01005057 else if (req->l == 0) {
5058 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5059 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5060 tv_eternity(&t->swexpire);
5061 }
5062 }
5063 else { /* buffer not empty */
5064 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5065 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005066 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005067 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005068 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5069 t->srexpire = t->swexpire;
5070 }
willy tarreau0f7af912005-12-17 12:21:26 +01005071 else
5072 tv_eternity(&t->swexpire);
5073 }
5074 }
5075 return 0;
5076 }
5077 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005078 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005079 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005080 tv_eternity(&t->srexpire);
5081 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005082 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005083 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005084 if (!(t->flags & SN_ERR_MASK))
5085 t->flags |= SN_ERR_SRVCL;
5086 if (!(t->flags & SN_FINST_MASK))
5087 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005088 return 1;
5089 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005090 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5091 //FD_CLR(t->srv_fd, StaticReadEvent);
5092 tv_eternity(&t->srexpire);
5093 fd_delete(t->srv_fd);
5094 //close(t->srv_fd);
5095 t->srv_state = SV_STCLOSE;
5096 return 1;
5097 }
5098 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5099 //FD_CLR(t->srv_fd, StaticReadEvent);
5100 tv_eternity(&t->srexpire);
5101 fd_delete(t->srv_fd);
5102 //close(t->srv_fd);
5103 t->srv_state = SV_STCLOSE;
5104 if (!(t->flags & SN_ERR_MASK))
5105 t->flags |= SN_ERR_SRVTO;
5106 if (!(t->flags & SN_FINST_MASK))
5107 t->flags |= SN_FINST_D;
5108 return 1;
5109 }
willy tarreau0f7af912005-12-17 12:21:26 +01005110 else if (rep->l == BUFSIZE) { /* no room to read more data */
5111 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5112 FD_CLR(t->srv_fd, StaticReadEvent);
5113 tv_eternity(&t->srexpire);
5114 }
5115 }
5116 else {
5117 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5118 FD_SET(t->srv_fd, StaticReadEvent);
5119 if (t->proxy->srvtimeout)
5120 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5121 else
5122 tv_eternity(&t->srexpire);
5123 }
5124 }
5125 return 0;
5126 }
5127 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005128 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005129 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005130 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 +01005131 write(1, trash, len);
5132 }
5133 return 0;
5134 }
5135 return 0;
5136}
5137
5138
willy tarreau5cbea6f2005-12-17 12:48:26 +01005139/* Processes the client and server jobs of a session task, then
5140 * puts it back to the wait queue in a clean state, or
5141 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005142 * the time the task accepts to wait, or TIME_ETERNITY for
5143 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005144 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005145int process_session(struct task *t) {
5146 struct session *s = t->context;
5147 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005148
willy tarreau5cbea6f2005-12-17 12:48:26 +01005149 do {
5150 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005151 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005152 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005153 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005154 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005155 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005156 } while (fsm_resync);
5157
5158 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005159 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005160 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005161
willy tarreau5cbea6f2005-12-17 12:48:26 +01005162 tv_min(&min1, &s->crexpire, &s->cwexpire);
5163 tv_min(&min2, &s->srexpire, &s->swexpire);
5164 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005165 tv_min(&t->expire, &min1, &min2);
5166
5167 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005168 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005169
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005170#ifdef DEBUG_FULL
5171 /* DEBUG code : this should never ever happen, otherwise it indicates
5172 * that a task still has something to do and will provoke a quick loop.
5173 */
5174 if (tv_remain2(&now, &t->expire) <= 0)
5175 exit(100);
5176#endif
5177
willy tarreaub952e1d2005-12-18 01:31:20 +01005178 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005179 }
5180
willy tarreau5cbea6f2005-12-17 12:48:26 +01005181 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005182 actconn--;
5183
willy tarreau982249e2005-12-18 00:57:06 +01005184 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005185 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005186 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 +01005187 write(1, trash, len);
5188 }
5189
willy tarreau750a4722005-12-17 13:21:24 +01005190 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005191 if (s->rep != NULL)
5192 s->logs.bytes = s->rep->total;
5193
willy tarreau9fe663a2005-12-17 13:02:59 +01005194 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005195 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005196 sess_log(s);
5197
willy tarreau0f7af912005-12-17 12:21:26 +01005198 /* the task MUST not be in the run queue anymore */
5199 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005201 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005202 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005203}
5204
5205
5206
5207/*
5208 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005209 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005210 */
5211int process_chk(struct task *t) {
5212 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005213 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005214 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005215
willy tarreauef900ab2005-12-17 12:52:52 +01005216 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005217
willy tarreau25424f82006-03-19 19:37:48 +01005218 new_chk:
5219 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005220 if (fd < 0) { /* no check currently running */
5221 //fprintf(stderr, "process_chk: 2\n");
5222 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5223 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005224 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005225 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005226
5227 /* we don't send any health-checks when the proxy is stopped or when
5228 * the server should not be checked.
5229 */
5230 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005231 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5232 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005233 task_queue(t); /* restore t to its place in the task list */
5234 return tv_remain2(&now, &t->expire);
5235 }
5236
willy tarreau5cbea6f2005-12-17 12:48:26 +01005237 /* we'll initiate a new check */
5238 s->result = 0; /* no result yet */
5239 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005240 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005241 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5242 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5243 //fprintf(stderr, "process_chk: 3\n");
5244
willy tarreaua41a8b42005-12-17 14:02:24 +01005245 /* we'll connect to the check port on the server */
5246 sa = s->addr;
5247 sa.sin_port = htons(s->check_port);
5248
willy tarreau0174f312005-12-18 01:02:42 +01005249 /* allow specific binding :
5250 * - server-specific at first
5251 * - proxy-specific next
5252 */
5253 if (s->state & SRV_BIND_SRC) {
5254 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5255 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5256 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5257 s->proxy->id, s->id);
5258 s->result = -1;
5259 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005260 }
willy tarreau0174f312005-12-18 01:02:42 +01005261 else if (s->proxy->options & PR_O_BIND_SRC) {
5262 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5263 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5264 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5265 s->proxy->id);
5266 s->result = -1;
5267 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005268 }
willy tarreau0174f312005-12-18 01:02:42 +01005269
5270 if (!s->result) {
5271 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5272 /* OK, connection in progress or established */
5273
5274 //fprintf(stderr, "process_chk: 4\n");
5275
5276 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5277 fdtab[fd].owner = t;
5278 fdtab[fd].read = &event_srv_chk_r;
5279 fdtab[fd].write = &event_srv_chk_w;
5280 fdtab[fd].state = FD_STCONN; /* connection in progress */
5281 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005282#ifdef DEBUG_FULL
5283 assert (!FD_ISSET(fd, StaticReadEvent));
5284#endif
willy tarreau0174f312005-12-18 01:02:42 +01005285 fd_insert(fd);
5286 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5287 tv_delayfrom(&t->expire, &now, s->inter);
5288 task_queue(t); /* restore t to its place in the task list */
5289 return tv_remain(&now, &t->expire);
5290 }
5291 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5292 s->result = -1; /* a real error */
5293 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005294 }
5295 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005296 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005297 }
5298
5299 if (!s->result) { /* nothing done */
5300 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005301 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5302 tv_delayfrom(&t->expire, &t->expire, s->inter);
5303 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005304 }
5305
5306 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005307 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005308 s->health--; /* still good */
5309 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005310 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005311 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005312 recount_servers(s->proxy);
5313 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5314 s->state & SRV_BACKUP ? "Backup " : "",
5315 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5316 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5317 send_log(s->proxy, LOG_ALERT,
5318 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5319 s->state & SRV_BACKUP ? "Backup " : "",
5320 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5321 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005322
willy tarreau62084d42006-03-24 18:57:41 +01005323 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005324 Alert("Proxy %s has no server available !\n", s->proxy->id);
5325 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5326 }
5327 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005328 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005329 }
5330
5331 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005332 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005333 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5334 tv_delayfrom(&t->expire, &t->expire, s->inter);
5335 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005336 }
5337 else {
5338 //fprintf(stderr, "process_chk: 8\n");
5339 /* there was a test running */
5340 if (s->result > 0) { /* good server detected */
5341 //fprintf(stderr, "process_chk: 9\n");
5342 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005343 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005344 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005345 recount_servers(s->proxy);
5346 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5347 s->state & SRV_BACKUP ? "Backup " : "",
5348 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5349 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5350 send_log(s->proxy, LOG_NOTICE,
5351 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5352 s->state & SRV_BACKUP ? "Backup " : "",
5353 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5354 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005355 }
willy tarreauef900ab2005-12-17 12:52:52 +01005356
willy tarreaue47c8d72005-12-17 12:55:52 +01005357 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005358 s->state |= SRV_RUNNING;
5359 }
willy tarreauef900ab2005-12-17 12:52:52 +01005360 s->curfd = -1; /* no check running anymore */
5361 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005362 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005363 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5364 tv_delayfrom(&t->expire, &t->expire, s->inter);
5365 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005366 }
5367 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5368 //fprintf(stderr, "process_chk: 10\n");
5369 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005370 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005371 s->health--; /* still good */
5372 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005373 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005374
willy tarreau62084d42006-03-24 18:57:41 +01005375 if (s->health == s->rise) {
5376 recount_servers(s->proxy);
5377 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5378 s->state & SRV_BACKUP ? "Backup " : "",
5379 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5380 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5381 send_log(s->proxy, LOG_ALERT,
5382 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5383 s->state & SRV_BACKUP ? "Backup " : "",
5384 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5385 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5386
5387 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5388 Alert("Proxy %s has no server available !\n", s->proxy->id);
5389 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5390 }
5391 }
willy tarreauef900ab2005-12-17 12:52:52 +01005392
willy tarreau5cbea6f2005-12-17 12:48:26 +01005393 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005394 }
5395 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005396 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005397 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005398 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5399 tv_delayfrom(&t->expire, &t->expire, s->inter);
5400 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005401 }
5402 /* if result is 0 and there's no timeout, we have to wait again */
5403 }
5404 //fprintf(stderr, "process_chk: 11\n");
5405 s->result = 0;
5406 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005407 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005408}
5409
5410
willy tarreau5cbea6f2005-12-17 12:48:26 +01005411
willy tarreau0f7af912005-12-17 12:21:26 +01005412#if STATTIME > 0
5413int stats(void);
5414#endif
5415
5416/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005417 * This does 4 things :
5418 * - wake up all expired tasks
5419 * - call all runnable tasks
5420 * - call maintain_proxies() to enable/disable the listeners
5421 * - return the delay till next event in ms, -1 = wait indefinitely
5422 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5423 *
willy tarreau0f7af912005-12-17 12:21:26 +01005424 */
5425
willy tarreau1c2ad212005-12-18 01:11:29 +01005426int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005427 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005428 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005429 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005430
willy tarreaub952e1d2005-12-18 01:31:20 +01005431 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005432
willy tarreau1c2ad212005-12-18 01:11:29 +01005433 /* look for expired tasks and add them to the run queue.
5434 */
5435 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5436 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5437 tnext = t->next;
5438 if (t->state & TASK_RUNNING)
5439 continue;
5440
willy tarreaub952e1d2005-12-18 01:31:20 +01005441 if (tv_iseternity(&t->expire))
5442 continue;
5443
willy tarreau1c2ad212005-12-18 01:11:29 +01005444 /* wakeup expired entries. It doesn't matter if they are
5445 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005446 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005447 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005448 task_wakeup(&rq, t);
5449 }
5450 else {
5451 /* first non-runnable task. Use its expiration date as an upper bound */
5452 int temp_time = tv_remain(&now, &t->expire);
5453 if (temp_time)
5454 next_time = temp_time;
5455 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005456 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005457 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005458
willy tarreau1c2ad212005-12-18 01:11:29 +01005459 /* process each task in the run queue now. Each task may be deleted
5460 * since we only use tnext.
5461 */
5462 tnext = rq;
5463 while ((t = tnext) != NULL) {
5464 int temp_time;
5465
5466 tnext = t->rqnext;
5467 task_sleep(&rq, t);
5468 temp_time = t->process(t);
5469 next_time = MINTIME(temp_time, next_time);
5470 }
5471
5472 /* maintain all proxies in a consistent state. This should quickly become a task */
5473 time2 = maintain_proxies();
5474 return MINTIME(time2, next_time);
5475}
5476
5477
5478#if defined(ENABLE_EPOLL)
5479
5480/*
5481 * Main epoll() loop.
5482 */
5483
5484/* does 3 actions :
5485 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5486 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5487 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5488 *
5489 * returns 0 if initialization failed, !0 otherwise.
5490 */
5491
5492int epoll_loop(int action) {
5493 int next_time;
5494 int status;
5495 int fd;
5496
5497 int fds, count;
5498 int pr, pw, sr, sw;
5499 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5500 struct epoll_event ev;
5501
5502 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005503 static struct epoll_event *epoll_events = NULL;
5504 static int epoll_fd;
5505
5506 if (action == POLL_LOOP_ACTION_INIT) {
5507 epoll_fd = epoll_create(global.maxsock + 1);
5508 if (epoll_fd < 0)
5509 return 0;
5510 else {
5511 epoll_events = (struct epoll_event*)
5512 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5513 PrevReadEvent = (fd_set *)
5514 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5515 PrevWriteEvent = (fd_set *)
5516 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005517 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005518 return 1;
5519 }
5520 else if (action == POLL_LOOP_ACTION_CLEAN) {
5521 if (PrevWriteEvent) free(PrevWriteEvent);
5522 if (PrevReadEvent) free(PrevReadEvent);
5523 if (epoll_events) free(epoll_events);
5524 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005525 epoll_fd = 0;
5526 return 1;
5527 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005528
willy tarreau1c2ad212005-12-18 01:11:29 +01005529 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005530
willy tarreau1c2ad212005-12-18 01:11:29 +01005531 tv_now(&now);
5532
5533 while (1) {
5534 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005535
5536 /* stop when there's no connection left and we don't allow them anymore */
5537 if (!actconn && listeners == 0)
5538 break;
5539
willy tarreau0f7af912005-12-17 12:21:26 +01005540#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005541 {
5542 int time2;
5543 time2 = stats();
5544 next_time = MINTIME(time2, next_time);
5545 }
willy tarreau0f7af912005-12-17 12:21:26 +01005546#endif
5547
willy tarreau1c2ad212005-12-18 01:11:29 +01005548 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5549
5550 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5551 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5552
5553 if ((ro^rn) | (wo^wn)) {
5554 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5555#define FDSETS_ARE_INT_ALIGNED
5556#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005557
willy tarreauad90a0c2005-12-18 01:09:15 +01005558#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5559#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005560 pr = (ro >> count) & 1;
5561 pw = (wo >> count) & 1;
5562 sr = (rn >> count) & 1;
5563 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005564#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005565 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5566 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5567 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5568 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005569#endif
5570#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005571 pr = FD_ISSET(fd, PrevReadEvent);
5572 pw = FD_ISSET(fd, PrevWriteEvent);
5573 sr = FD_ISSET(fd, StaticReadEvent);
5574 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005575#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005576 if (!((sr^pr) | (sw^pw)))
5577 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005578
willy tarreau1c2ad212005-12-18 01:11:29 +01005579 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5580 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005581
willy tarreaub952e1d2005-12-18 01:31:20 +01005582#ifdef EPOLL_CTL_MOD_WORKAROUND
5583 /* I encountered a rarely reproducible problem with
5584 * EPOLL_CTL_MOD where a modified FD (systematically
5585 * the one in epoll_events[0], fd#7) would sometimes
5586 * be set EPOLL_OUT while asked for a read ! This is
5587 * with the 2.4 epoll patch. The workaround is to
5588 * delete then recreate in case of modification.
5589 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5590 * nor RHEL kernels.
5591 */
5592
5593 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5594 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5595
5596 if ((sr | sw))
5597 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5598#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005599 if ((pr | pw)) {
5600 /* the file-descriptor already exists... */
5601 if ((sr | sw)) {
5602 /* ...and it will still exist */
5603 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5604 // perror("epoll_ctl(MOD)");
5605 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005606 }
5607 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005608 /* ...and it will be removed */
5609 if (fdtab[fd].state != FD_STCLOSE &&
5610 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5611 // perror("epoll_ctl(DEL)");
5612 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005613 }
5614 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005615 } else {
5616 /* the file-descriptor did not exist, let's add it */
5617 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5618 // perror("epoll_ctl(ADD)");
5619 // exit(1);
5620 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005621 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005622#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005623 }
5624 ((int*)PrevReadEvent)[fds] = rn;
5625 ((int*)PrevWriteEvent)[fds] = wn;
5626 }
5627 }
5628
5629 /* now let's wait for events */
5630 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5631 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005632
willy tarreau1c2ad212005-12-18 01:11:29 +01005633 for (count = 0; count < status; count++) {
5634 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005635
5636 if (FD_ISSET(fd, StaticReadEvent)) {
5637 if (fdtab[fd].state == FD_STCLOSE)
5638 continue;
5639 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5640 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005641 }
willy tarreau05be12b2006-03-19 19:35:00 +01005642
5643 if (FD_ISSET(fd, StaticWriteEvent)) {
5644 if (fdtab[fd].state == FD_STCLOSE)
5645 continue;
5646 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5647 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005648 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005649 }
5650 }
5651 return 1;
5652}
5653#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005654
willy tarreauad90a0c2005-12-18 01:09:15 +01005655
willy tarreau5cbea6f2005-12-17 12:48:26 +01005656
willy tarreau1c2ad212005-12-18 01:11:29 +01005657#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005658
willy tarreau1c2ad212005-12-18 01:11:29 +01005659/*
5660 * Main poll() loop.
5661 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005662
willy tarreau1c2ad212005-12-18 01:11:29 +01005663/* does 3 actions :
5664 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5665 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5666 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5667 *
5668 * returns 0 if initialization failed, !0 otherwise.
5669 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005670
willy tarreau1c2ad212005-12-18 01:11:29 +01005671int poll_loop(int action) {
5672 int next_time;
5673 int status;
5674 int fd, nbfd;
5675
5676 int fds, count;
5677 int sr, sw;
5678 unsigned rn, wn; /* read new, write new */
5679
5680 /* private data */
5681 static struct pollfd *poll_events = NULL;
5682
5683 if (action == POLL_LOOP_ACTION_INIT) {
5684 poll_events = (struct pollfd*)
5685 calloc(1, sizeof(struct pollfd) * global.maxsock);
5686 return 1;
5687 }
5688 else if (action == POLL_LOOP_ACTION_CLEAN) {
5689 if (poll_events)
5690 free(poll_events);
5691 return 1;
5692 }
5693
5694 /* OK, it's POLL_LOOP_ACTION_RUN */
5695
5696 tv_now(&now);
5697
5698 while (1) {
5699 next_time = process_runnable_tasks();
5700
5701 /* stop when there's no connection left and we don't allow them anymore */
5702 if (!actconn && listeners == 0)
5703 break;
5704
5705#if STATTIME > 0
5706 {
5707 int time2;
5708 time2 = stats();
5709 next_time = MINTIME(time2, next_time);
5710 }
5711#endif
5712
5713
5714 nbfd = 0;
5715 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5716
5717 rn = ((int*)StaticReadEvent)[fds];
5718 wn = ((int*)StaticWriteEvent)[fds];
5719
5720 if ((rn|wn)) {
5721 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5722#define FDSETS_ARE_INT_ALIGNED
5723#ifdef FDSETS_ARE_INT_ALIGNED
5724
5725#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5726#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5727 sr = (rn >> count) & 1;
5728 sw = (wn >> count) & 1;
5729#else
5730 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5731 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5732#endif
5733#else
5734 sr = FD_ISSET(fd, StaticReadEvent);
5735 sw = FD_ISSET(fd, StaticWriteEvent);
5736#endif
5737 if ((sr|sw)) {
5738 poll_events[nbfd].fd = fd;
5739 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5740 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005741 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005742 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005743 }
5744 }
5745
5746 /* now let's wait for events */
5747 status = poll(poll_events, nbfd, next_time);
5748 tv_now(&now);
5749
5750 for (count = 0; status > 0 && count < nbfd; count++) {
5751 fd = poll_events[count].fd;
5752
5753 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5754 continue;
5755
5756 /* ok, we found one active fd */
5757 status--;
5758
willy tarreau05be12b2006-03-19 19:35:00 +01005759 if (FD_ISSET(fd, StaticReadEvent)) {
5760 if (fdtab[fd].state == FD_STCLOSE)
5761 continue;
5762 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5763 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005764 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005765
willy tarreau05be12b2006-03-19 19:35:00 +01005766 if (FD_ISSET(fd, StaticWriteEvent)) {
5767 if (fdtab[fd].state == FD_STCLOSE)
5768 continue;
5769 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5770 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005771 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005772 }
5773 }
5774 return 1;
5775}
willy tarreauad90a0c2005-12-18 01:09:15 +01005776#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005777
willy tarreauad90a0c2005-12-18 01:09:15 +01005778
willy tarreauad90a0c2005-12-18 01:09:15 +01005779
willy tarreau1c2ad212005-12-18 01:11:29 +01005780/*
5781 * Main select() loop.
5782 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005783
willy tarreau1c2ad212005-12-18 01:11:29 +01005784/* does 3 actions :
5785 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5786 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5787 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5788 *
5789 * returns 0 if initialization failed, !0 otherwise.
5790 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005791
willy tarreauad90a0c2005-12-18 01:09:15 +01005792
willy tarreau1c2ad212005-12-18 01:11:29 +01005793int select_loop(int action) {
5794 int next_time;
5795 int status;
5796 int fd,i;
5797 struct timeval delta;
5798 int readnotnull, writenotnull;
5799 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005800
willy tarreau1c2ad212005-12-18 01:11:29 +01005801 if (action == POLL_LOOP_ACTION_INIT) {
5802 ReadEvent = (fd_set *)
5803 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5804 WriteEvent = (fd_set *)
5805 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5806 return 1;
5807 }
5808 else if (action == POLL_LOOP_ACTION_CLEAN) {
5809 if (WriteEvent) free(WriteEvent);
5810 if (ReadEvent) free(ReadEvent);
5811 return 1;
5812 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005813
willy tarreau1c2ad212005-12-18 01:11:29 +01005814 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005815
willy tarreau1c2ad212005-12-18 01:11:29 +01005816 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005817
willy tarreau1c2ad212005-12-18 01:11:29 +01005818 while (1) {
5819 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005820
willy tarreau1c2ad212005-12-18 01:11:29 +01005821 /* stop when there's no connection left and we don't allow them anymore */
5822 if (!actconn && listeners == 0)
5823 break;
5824
5825#if STATTIME > 0
5826 {
5827 int time2;
5828 time2 = stats();
5829 next_time = MINTIME(time2, next_time);
5830 }
5831#endif
5832
willy tarreau1c2ad212005-12-18 01:11:29 +01005833 if (next_time > 0) { /* FIXME */
5834 /* Convert to timeval */
5835 /* to avoid eventual select loops due to timer precision */
5836 next_time += SCHEDULER_RESOLUTION;
5837 delta.tv_sec = next_time / 1000;
5838 delta.tv_usec = (next_time % 1000) * 1000;
5839 }
5840 else if (next_time == 0) { /* allow select to return immediately when needed */
5841 delta.tv_sec = delta.tv_usec = 0;
5842 }
5843
5844
5845 /* let's restore fdset state */
5846
5847 readnotnull = 0; writenotnull = 0;
5848 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5849 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5850 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5851 }
5852
5853 // /* just a verification code, needs to be removed for performance */
5854 // for (i=0; i<maxfd; i++) {
5855 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5856 // abort();
5857 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5858 // abort();
5859 //
5860 // }
5861
5862 status = select(maxfd,
5863 readnotnull ? ReadEvent : NULL,
5864 writenotnull ? WriteEvent : NULL,
5865 NULL,
5866 (next_time >= 0) ? &delta : NULL);
5867
5868 /* this is an experiment on the separation of the select work */
5869 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5870 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5871
5872 tv_now(&now);
5873
5874 if (status > 0) { /* must proceed with events */
5875
5876 int fds;
5877 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005878
willy tarreau1c2ad212005-12-18 01:11:29 +01005879 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5880 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5881 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5882
5883 /* if we specify read first, the accepts and zero reads will be
5884 * seen first. Moreover, system buffers will be flushed faster.
5885 */
willy tarreau05be12b2006-03-19 19:35:00 +01005886 if (FD_ISSET(fd, ReadEvent)) {
5887 if (fdtab[fd].state == FD_STCLOSE)
5888 continue;
5889 fdtab[fd].read(fd);
5890 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005891
willy tarreau05be12b2006-03-19 19:35:00 +01005892 if (FD_ISSET(fd, WriteEvent)) {
5893 if (fdtab[fd].state == FD_STCLOSE)
5894 continue;
5895 fdtab[fd].write(fd);
5896 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005897 }
5898 }
5899 else {
5900 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005901 }
willy tarreau0f7af912005-12-17 12:21:26 +01005902 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005903 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005904}
5905
5906
5907#if STATTIME > 0
5908/*
5909 * Display proxy statistics regularly. It is designed to be called from the
5910 * select_loop().
5911 */
5912int stats(void) {
5913 static int lines;
5914 static struct timeval nextevt;
5915 static struct timeval lastevt;
5916 static struct timeval starttime = {0,0};
5917 unsigned long totaltime, deltatime;
5918 int ret;
5919
willy tarreau750a4722005-12-17 13:21:24 +01005920 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005921 deltatime = (tv_diff(&lastevt, &now)?:1);
5922 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005923
willy tarreau9fe663a2005-12-17 13:02:59 +01005924 if (global.mode & MODE_STATS) {
5925 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005926 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005927 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5928 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005929 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005930 actconn, totalconn,
5931 stats_tsk_new, stats_tsk_good,
5932 stats_tsk_left, stats_tsk_right,
5933 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5934 }
5935 }
5936
5937 tv_delayfrom(&nextevt, &now, STATTIME);
5938
5939 lastevt=now;
5940 }
5941 ret = tv_remain(&now, &nextevt);
5942 return ret;
5943}
5944#endif
5945
5946
5947/*
5948 * this function enables proxies when there are enough free sessions,
5949 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005950 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005951 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005952 */
5953static int maintain_proxies(void) {
5954 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005955 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005956 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005957
5958 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005959 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005960
5961 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005962 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005963 while (p) {
5964 if (p->nbconn < p->maxconn) {
5965 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005966 for (l = p->listen; l != NULL; l = l->next) {
5967 FD_SET(l->fd, StaticReadEvent);
5968 }
willy tarreau0f7af912005-12-17 12:21:26 +01005969 p->state = PR_STRUN;
5970 }
5971 }
5972 else {
5973 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005974 for (l = p->listen; l != NULL; l = l->next) {
5975 FD_CLR(l->fd, StaticReadEvent);
5976 }
willy tarreau0f7af912005-12-17 12:21:26 +01005977 p->state = PR_STIDLE;
5978 }
5979 }
5980 p = p->next;
5981 }
5982 }
5983 else { /* block all proxies */
5984 while (p) {
5985 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005986 for (l = p->listen; l != NULL; l = l->next) {
5987 FD_CLR(l->fd, StaticReadEvent);
5988 }
willy tarreau0f7af912005-12-17 12:21:26 +01005989 p->state = PR_STIDLE;
5990 }
5991 p = p->next;
5992 }
5993 }
5994
willy tarreau5cbea6f2005-12-17 12:48:26 +01005995 if (stopping) {
5996 p = proxy;
5997 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005998 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005999 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006000 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006001 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006002 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006003 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006004
willy tarreaua41a8b42005-12-17 14:02:24 +01006005 for (l = p->listen; l != NULL; l = l->next) {
6006 fd_delete(l->fd);
6007 listeners--;
6008 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006009 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006010 }
6011 else {
6012 tleft = MINTIME(t, tleft);
6013 }
6014 }
6015 p = p->next;
6016 }
6017 }
6018 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006019}
6020
6021/*
6022 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006023 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6024 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006025 */
6026static void soft_stop(void) {
6027 struct proxy *p;
6028
6029 stopping = 1;
6030 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006031 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006032 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006033 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006034 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006035 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006036 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006037 }
willy tarreau0f7af912005-12-17 12:21:26 +01006038 p = p->next;
6039 }
6040}
6041
willy tarreaudbd3bef2006-01-20 19:35:18 +01006042static void pause_proxy(struct proxy *p) {
6043 struct listener *l;
6044 for (l = p->listen; l != NULL; l = l->next) {
6045 shutdown(l->fd, SHUT_RD);
6046 FD_CLR(l->fd, StaticReadEvent);
6047 p->state = PR_STPAUSED;
6048 }
6049}
6050
6051/*
6052 * This function temporarily disables listening so that another new instance
6053 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006054 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006055 * the proxy, or a SIGTTIN can be sent to listen again.
6056 */
6057static void pause_proxies(void) {
6058 struct proxy *p;
6059
6060 p = proxy;
6061 tv_now(&now); /* else, the old time before select will be used */
6062 while (p) {
6063 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6064 Warning("Pausing proxy %s.\n", p->id);
6065 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6066 pause_proxy(p);
6067 }
6068 p = p->next;
6069 }
6070}
6071
6072
6073/*
6074 * This function reactivates listening. This can be used after a call to
6075 * sig_pause(), for example when a new instance has failed starting up.
6076 * It is designed to be called upon reception of a SIGTTIN.
6077 */
6078static void listen_proxies(void) {
6079 struct proxy *p;
6080 struct listener *l;
6081
6082 p = proxy;
6083 tv_now(&now); /* else, the old time before select will be used */
6084 while (p) {
6085 if (p->state == PR_STPAUSED) {
6086 Warning("Enabling proxy %s.\n", p->id);
6087 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6088
6089 for (l = p->listen; l != NULL; l = l->next) {
6090 if (listen(l->fd, p->maxconn) == 0) {
6091 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6092 FD_SET(l->fd, StaticReadEvent);
6093 p->state = PR_STRUN;
6094 }
6095 else
6096 p->state = PR_STIDLE;
6097 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006098 int port;
6099
6100 if (l->addr.ss_family == AF_INET6)
6101 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6102 else
6103 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6104
willy tarreaudbd3bef2006-01-20 19:35:18 +01006105 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006106 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006107 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006108 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006109 /* Another port might have been enabled. Let's stop everything. */
6110 pause_proxy(p);
6111 break;
6112 }
6113 }
6114 }
6115 p = p->next;
6116 }
6117}
6118
6119
willy tarreau0f7af912005-12-17 12:21:26 +01006120/*
6121 * upon SIGUSR1, let's have a soft stop.
6122 */
6123void sig_soft_stop(int sig) {
6124 soft_stop();
6125 signal(sig, SIG_IGN);
6126}
6127
willy tarreaudbd3bef2006-01-20 19:35:18 +01006128/*
6129 * upon SIGTTOU, we pause everything
6130 */
6131void sig_pause(int sig) {
6132 pause_proxies();
6133 signal(sig, sig_pause);
6134}
willy tarreau0f7af912005-12-17 12:21:26 +01006135
willy tarreau8337c6b2005-12-17 13:41:01 +01006136/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006137 * upon SIGTTIN, let's have a soft stop.
6138 */
6139void sig_listen(int sig) {
6140 listen_proxies();
6141 signal(sig, sig_listen);
6142}
6143
6144/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006145 * this function dumps every server's state when the process receives SIGHUP.
6146 */
6147void sig_dump_state(int sig) {
6148 struct proxy *p = proxy;
6149
6150 Warning("SIGHUP received, dumping servers states.\n");
6151 while (p) {
6152 struct server *s = p->srv;
6153
6154 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6155 while (s) {
6156 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006157 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
6158 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006159 }
6160 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006161 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
6162 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006163 }
6164 s = s->next;
6165 }
willy tarreaudd07e972005-12-18 00:48:48 +01006166
willy tarreau62084d42006-03-24 18:57:41 +01006167 if (p->srv_act == 0) {
6168 if (p->srv_bck) {
6169 Warning("SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6170 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6171 } else {
6172 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6173 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
6174 }
6175 }
willy tarreaudd07e972005-12-18 00:48:48 +01006176
willy tarreau8337c6b2005-12-17 13:41:01 +01006177 p = p->next;
6178 }
6179 signal(sig, sig_dump_state);
6180}
6181
willy tarreau0f7af912005-12-17 12:21:26 +01006182void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006183 struct task *t, *tnext;
6184 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006185
willy tarreau5cbea6f2005-12-17 12:48:26 +01006186 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6187 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6188 tnext = t->next;
6189 s = t->context;
6190 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6191 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6192 "req=%d, rep=%d, clifd=%d\n",
6193 s, tv_remain(&now, &t->expire),
6194 s->cli_state,
6195 s->srv_state,
6196 FD_ISSET(s->cli_fd, StaticReadEvent),
6197 FD_ISSET(s->cli_fd, StaticWriteEvent),
6198 FD_ISSET(s->srv_fd, StaticReadEvent),
6199 FD_ISSET(s->srv_fd, StaticWriteEvent),
6200 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6201 );
willy tarreau0f7af912005-12-17 12:21:26 +01006202 }
willy tarreau12350152005-12-18 01:03:27 +01006203}
6204
willy tarreau64a3cc32005-12-18 01:13:11 +01006205#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006206static void fast_stop(void)
6207{
6208 struct proxy *p;
6209 p = proxy;
6210 while (p) {
6211 p->grace = 0;
6212 p = p->next;
6213 }
6214 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006215}
6216
willy tarreau12350152005-12-18 01:03:27 +01006217void sig_int(int sig) {
6218 /* This would normally be a hard stop,
6219 but we want to be sure about deallocation,
6220 and so on, so we do a soft stop with
6221 0 GRACE time
6222 */
6223 fast_stop();
6224 /* If we are killed twice, we decide to die*/
6225 signal(sig, SIG_DFL);
6226}
6227
6228void sig_term(int sig) {
6229 /* This would normally be a hard stop,
6230 but we want to be sure about deallocation,
6231 and so on, so we do a soft stop with
6232 0 GRACE time
6233 */
6234 fast_stop();
6235 /* If we are killed twice, we decide to die*/
6236 signal(sig, SIG_DFL);
6237}
willy tarreau64a3cc32005-12-18 01:13:11 +01006238#endif
willy tarreau12350152005-12-18 01:03:27 +01006239
willy tarreauc1f47532005-12-18 01:08:26 +01006240/* returns the pointer to an error in the replacement string, or NULL if OK */
6241char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006242 struct hdr_exp *exp;
6243
willy tarreauc1f47532005-12-18 01:08:26 +01006244 if (replace != NULL) {
6245 char *err;
6246 err = check_replace_string(replace);
6247 if (err)
6248 return err;
6249 }
6250
willy tarreaue39cd132005-12-17 13:00:18 +01006251 while (*head != NULL)
6252 head = &(*head)->next;
6253
6254 exp = calloc(1, sizeof(struct hdr_exp));
6255
6256 exp->preg = preg;
6257 exp->replace = replace;
6258 exp->action = action;
6259 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006260
6261 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006262}
6263
willy tarreau9fe663a2005-12-17 13:02:59 +01006264
willy tarreau0f7af912005-12-17 12:21:26 +01006265/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006266 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006267 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006268int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006269
willy tarreau9fe663a2005-12-17 13:02:59 +01006270 if (!strcmp(args[0], "global")) { /* new section */
6271 /* no option, nothing special to do */
6272 return 0;
6273 }
6274 else if (!strcmp(args[0], "daemon")) {
6275 global.mode |= MODE_DAEMON;
6276 }
6277 else if (!strcmp(args[0], "debug")) {
6278 global.mode |= MODE_DEBUG;
6279 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006280 else if (!strcmp(args[0], "noepoll")) {
6281 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6282 }
6283 else if (!strcmp(args[0], "nopoll")) {
6284 cfg_polling_mechanism &= ~POLL_USE_POLL;
6285 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006286 else if (!strcmp(args[0], "quiet")) {
6287 global.mode |= MODE_QUIET;
6288 }
6289 else if (!strcmp(args[0], "stats")) {
6290 global.mode |= MODE_STATS;
6291 }
6292 else if (!strcmp(args[0], "uid")) {
6293 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006294 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006295 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006296 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006297 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006298 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006299 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006300 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006301 global.uid = atol(args[1]);
6302 }
6303 else if (!strcmp(args[0], "gid")) {
6304 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006305 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006306 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006307 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006308 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006309 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006310 return -1;
6311 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006312 global.gid = atol(args[1]);
6313 }
6314 else if (!strcmp(args[0], "nbproc")) {
6315 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006316 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006317 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006318 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006319 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006320 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006321 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006322 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006323 global.nbproc = atol(args[1]);
6324 }
6325 else if (!strcmp(args[0], "maxconn")) {
6326 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006327 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006328 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006329 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006330 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006331 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006332 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006333 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006334 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006335#ifdef SYSTEM_MAXCONN
6336 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6337 Alert("parsing [%s:%d] : maxconn value %d too high for this system.\nLimiting to %d. Please use '-n' to force the value.\n", file, linenum, global.maxconn, DEFAULT_MAXCONN);
6338 global.maxconn = DEFAULT_MAXCONN;
6339 }
6340#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006341 }
willy tarreaub1285d52005-12-18 01:20:14 +01006342 else if (!strcmp(args[0], "ulimit-n")) {
6343 if (global.rlimit_nofile != 0) {
6344 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6345 return 0;
6346 }
6347 if (*(args[1]) == 0) {
6348 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6349 return -1;
6350 }
6351 global.rlimit_nofile = atol(args[1]);
6352 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006353 else if (!strcmp(args[0], "chroot")) {
6354 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006355 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006356 return 0;
6357 }
6358 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006359 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006360 return -1;
6361 }
6362 global.chroot = strdup(args[1]);
6363 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006364 else if (!strcmp(args[0], "pidfile")) {
6365 if (global.pidfile != NULL) {
6366 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6367 return 0;
6368 }
6369 if (*(args[1]) == 0) {
6370 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6371 return -1;
6372 }
6373 global.pidfile = strdup(args[1]);
6374 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006375 else if (!strcmp(args[0], "log")) { /* syslog server address */
6376 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006377 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006378
6379 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006380 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006381 return -1;
6382 }
6383
6384 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6385 if (!strcmp(log_facilities[facility], args[2]))
6386 break;
6387
6388 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006389 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006390 exit(1);
6391 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006392
6393 level = 7; /* max syslog level = debug */
6394 if (*(args[3])) {
6395 while (level >= 0 && strcmp(log_levels[level], args[3]))
6396 level--;
6397 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006398 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006399 exit(1);
6400 }
6401 }
6402
willy tarreau9fe663a2005-12-17 13:02:59 +01006403 sa = str2sa(args[1]);
6404 if (!sa->sin_port)
6405 sa->sin_port = htons(SYSLOG_PORT);
6406
6407 if (global.logfac1 == -1) {
6408 global.logsrv1 = *sa;
6409 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006410 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006411 }
6412 else if (global.logfac2 == -1) {
6413 global.logsrv2 = *sa;
6414 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006415 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006416 }
6417 else {
6418 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6419 return -1;
6420 }
6421
6422 }
6423 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006424 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006425 return -1;
6426 }
6427 return 0;
6428}
6429
6430
willy tarreaua41a8b42005-12-17 14:02:24 +01006431void init_default_instance() {
6432 memset(&defproxy, 0, sizeof(defproxy));
6433 defproxy.mode = PR_MODE_TCP;
6434 defproxy.state = PR_STNEW;
6435 defproxy.maxconn = cfg_maxpconn;
6436 defproxy.conn_retries = CONN_RETRIES;
6437 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6438}
6439
willy tarreau9fe663a2005-12-17 13:02:59 +01006440/*
6441 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6442 */
6443int cfg_parse_listen(char *file, int linenum, char **args) {
6444 static struct proxy *curproxy = NULL;
6445 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006446 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006447 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006448
6449 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006450 if (!*args[1]) {
6451 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6452 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006453 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006454 return -1;
6455 }
6456
6457 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006458 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006459 return -1;
6460 }
6461 curproxy->next = proxy;
6462 proxy = curproxy;
6463 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006464
6465 /* parse the listener address if any */
6466 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006467 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006468 if (!curproxy->listen)
6469 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006470 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006471 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006472
willy tarreau9fe663a2005-12-17 13:02:59 +01006473 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006474 curproxy->state = defproxy.state;
6475 curproxy->maxconn = defproxy.maxconn;
6476 curproxy->conn_retries = defproxy.conn_retries;
6477 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006478
6479 if (defproxy.check_req)
6480 curproxy->check_req = strdup(defproxy.check_req);
6481 curproxy->check_len = defproxy.check_len;
6482
6483 if (defproxy.cookie_name)
6484 curproxy->cookie_name = strdup(defproxy.cookie_name);
6485 curproxy->cookie_len = defproxy.cookie_len;
6486
6487 if (defproxy.capture_name)
6488 curproxy->capture_name = strdup(defproxy.capture_name);
6489 curproxy->capture_namelen = defproxy.capture_namelen;
6490 curproxy->capture_len = defproxy.capture_len;
6491
6492 if (defproxy.errmsg.msg400)
6493 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6494 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6495
6496 if (defproxy.errmsg.msg403)
6497 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6498 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6499
6500 if (defproxy.errmsg.msg408)
6501 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6502 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6503
6504 if (defproxy.errmsg.msg500)
6505 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6506 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6507
6508 if (defproxy.errmsg.msg502)
6509 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6510 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6511
6512 if (defproxy.errmsg.msg503)
6513 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6514 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6515
6516 if (defproxy.errmsg.msg504)
6517 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6518 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6519
willy tarreaua41a8b42005-12-17 14:02:24 +01006520 curproxy->clitimeout = defproxy.clitimeout;
6521 curproxy->contimeout = defproxy.contimeout;
6522 curproxy->srvtimeout = defproxy.srvtimeout;
6523 curproxy->mode = defproxy.mode;
6524 curproxy->logfac1 = defproxy.logfac1;
6525 curproxy->logsrv1 = defproxy.logsrv1;
6526 curproxy->loglev1 = defproxy.loglev1;
6527 curproxy->logfac2 = defproxy.logfac2;
6528 curproxy->logsrv2 = defproxy.logsrv2;
6529 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006530 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006531 curproxy->grace = defproxy.grace;
6532 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006533 curproxy->mon_net = defproxy.mon_net;
6534 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006535 return 0;
6536 }
6537 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006538 /* some variables may have already been initialized earlier */
6539 if (defproxy.check_req) free(defproxy.check_req);
6540 if (defproxy.cookie_name) free(defproxy.cookie_name);
6541 if (defproxy.capture_name) free(defproxy.capture_name);
6542 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6543 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6544 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6545 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6546 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6547 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6548 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6549
6550 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006551 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006552 return 0;
6553 }
6554 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006555 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006556 return -1;
6557 }
6558
willy tarreaua41a8b42005-12-17 14:02:24 +01006559 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6560 if (curproxy == &defproxy) {
6561 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6562 return -1;
6563 }
6564
6565 if (strchr(args[1], ':') == NULL) {
6566 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6567 file, linenum, args[0]);
6568 return -1;
6569 }
6570 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006571 if (!curproxy->listen)
6572 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006573 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006574 return 0;
6575 }
willy tarreaub1285d52005-12-18 01:20:14 +01006576 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6577 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6578 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6579 file, linenum, args[0]);
6580 return -1;
6581 }
6582 /* flush useless bits */
6583 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6584 return 0;
6585 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006586 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006587 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6588 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6589 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6590 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006591 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006592 return -1;
6593 }
6594 }
6595 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006596 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006597 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006598 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6599 curproxy->state = PR_STNEW;
6600 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006601 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6602 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006603// if (curproxy == &defproxy) {
6604// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6605// return -1;
6606// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006607
willy tarreau9fe663a2005-12-17 13:02:59 +01006608 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006609// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6610// file, linenum);
6611// return 0;
6612 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006613 }
6614
6615 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006616 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6617 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006618 return -1;
6619 }
6620 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006621 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006622
6623 cur_arg = 2;
6624 while (*(args[cur_arg])) {
6625 if (!strcmp(args[cur_arg], "rewrite")) {
6626 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006627 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006628 else if (!strcmp(args[cur_arg], "indirect")) {
6629 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006630 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006631 else if (!strcmp(args[cur_arg], "insert")) {
6632 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006633 }
willy tarreau240afa62005-12-17 13:14:35 +01006634 else if (!strcmp(args[cur_arg], "nocache")) {
6635 curproxy->options |= PR_O_COOK_NOC;
6636 }
willy tarreaucd878942005-12-17 13:27:43 +01006637 else if (!strcmp(args[cur_arg], "postonly")) {
6638 curproxy->options |= PR_O_COOK_POST;
6639 }
willy tarreau0174f312005-12-18 01:02:42 +01006640 else if (!strcmp(args[cur_arg], "prefix")) {
6641 curproxy->options |= PR_O_COOK_PFX;
6642 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006643 else {
willy tarreau0174f312005-12-18 01:02:42 +01006644 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006645 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006646 return -1;
6647 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006648 cur_arg++;
6649 }
willy tarreau0174f312005-12-18 01:02:42 +01006650 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6651 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6652 file, linenum);
6653 return -1;
6654 }
6655
6656 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6657 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006658 file, linenum);
6659 return -1;
6660 }
willy tarreau12350152005-12-18 01:03:27 +01006661 }/* end else if (!strcmp(args[0], "cookie")) */
6662 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6663// if (curproxy == &defproxy) {
6664// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6665// return -1;
6666// }
6667
6668 if (curproxy->appsession_name != NULL) {
6669// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6670// file, linenum);
6671// return 0;
6672 free(curproxy->appsession_name);
6673 }
6674
6675 if (*(args[5]) == 0) {
6676 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6677 file, linenum, args[0]);
6678 return -1;
6679 }
6680 have_appsession = 1;
6681 curproxy->appsession_name = strdup(args[1]);
6682 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6683 curproxy->appsession_len = atoi(args[3]);
6684 curproxy->appsession_timeout = atoi(args[5]);
6685 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6686 if (rc) {
6687 Alert("Error Init Appsession Hashtable.\n");
6688 return -1;
6689 }
6690 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006691 else if (!strcmp(args[0], "capture")) {
6692 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6693 // if (curproxy == &defproxy) {
6694 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6695 // return -1;
6696 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006697
willy tarreau4302f492005-12-18 01:00:37 +01006698 if (curproxy->capture_name != NULL) {
6699 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6700 // file, linenum, args[0]);
6701 // return 0;
6702 free(curproxy->capture_name);
6703 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006704
willy tarreau4302f492005-12-18 01:00:37 +01006705 if (*(args[4]) == 0) {
6706 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6707 file, linenum, args[0]);
6708 return -1;
6709 }
6710 curproxy->capture_name = strdup(args[2]);
6711 curproxy->capture_namelen = strlen(curproxy->capture_name);
6712 curproxy->capture_len = atol(args[4]);
6713 if (curproxy->capture_len >= CAPTURE_LEN) {
6714 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6715 file, linenum, CAPTURE_LEN - 1);
6716 curproxy->capture_len = CAPTURE_LEN - 1;
6717 }
6718 curproxy->to_log |= LW_COOKIE;
6719 }
6720 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6721 struct cap_hdr *hdr;
6722
6723 if (curproxy == &defproxy) {
6724 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6725 return -1;
6726 }
6727
6728 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6729 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6730 file, linenum, args[0], args[1]);
6731 return -1;
6732 }
6733
6734 hdr = calloc(sizeof(struct cap_hdr), 1);
6735 hdr->next = curproxy->req_cap;
6736 hdr->name = strdup(args[3]);
6737 hdr->namelen = strlen(args[3]);
6738 hdr->len = atol(args[5]);
6739 hdr->index = curproxy->nb_req_cap++;
6740 curproxy->req_cap = hdr;
6741 curproxy->to_log |= LW_REQHDR;
6742 }
6743 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6744 struct cap_hdr *hdr;
6745
6746 if (curproxy == &defproxy) {
6747 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6748 return -1;
6749 }
6750
6751 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6752 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6753 file, linenum, args[0], args[1]);
6754 return -1;
6755 }
6756 hdr = calloc(sizeof(struct cap_hdr), 1);
6757 hdr->next = curproxy->rsp_cap;
6758 hdr->name = strdup(args[3]);
6759 hdr->namelen = strlen(args[3]);
6760 hdr->len = atol(args[5]);
6761 hdr->index = curproxy->nb_rsp_cap++;
6762 curproxy->rsp_cap = hdr;
6763 curproxy->to_log |= LW_RSPHDR;
6764 }
6765 else {
6766 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006767 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006768 return -1;
6769 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006770 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006771 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006772 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006773 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006774 return 0;
6775 }
6776 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006777 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6778 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006779 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006781 curproxy->contimeout = atol(args[1]);
6782 }
6783 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006784 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006785 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6786 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006787 return 0;
6788 }
6789 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006790 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6791 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006792 return -1;
6793 }
6794 curproxy->clitimeout = atol(args[1]);
6795 }
6796 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006797 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006798 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006799 return 0;
6800 }
6801 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006802 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6803 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006804 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006805 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006806 curproxy->srvtimeout = atol(args[1]);
6807 }
6808 else if (!strcmp(args[0], "retries")) { /* connection retries */
6809 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006810 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6811 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006812 return -1;
6813 }
6814 curproxy->conn_retries = atol(args[1]);
6815 }
6816 else if (!strcmp(args[0], "option")) {
6817 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006818 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006819 return -1;
6820 }
6821 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006822 /* enable reconnections to dispatch */
6823 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006824#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006825 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006826 /* enable transparent proxy connections */
6827 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006828#endif
6829 else if (!strcmp(args[1], "keepalive"))
6830 /* enable keep-alive */
6831 curproxy->options |= PR_O_KEEPALIVE;
6832 else if (!strcmp(args[1], "forwardfor"))
6833 /* insert x-forwarded-for field */
6834 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006835 else if (!strcmp(args[1], "logasap"))
6836 /* log as soon as possible, without waiting for the session to complete */
6837 curproxy->options |= PR_O_LOGASAP;
6838 else if (!strcmp(args[1], "httpclose"))
6839 /* force connection: close in both directions in HTTP mode */
6840 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006841 else if (!strcmp(args[1], "forceclose"))
6842 /* force connection: close in both directions in HTTP mode and enforce end of session */
6843 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006844 else if (!strcmp(args[1], "checkcache"))
6845 /* require examination of cacheability of the 'set-cookie' field */
6846 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006847 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006848 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006849 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006850 else if (!strcmp(args[1], "tcplog"))
6851 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006852 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006853 else if (!strcmp(args[1], "dontlognull")) {
6854 /* don't log empty requests */
6855 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006856 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006857 else if (!strcmp(args[1], "tcpka")) {
6858 /* enable TCP keep-alives on client and server sessions */
6859 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6860 }
6861 else if (!strcmp(args[1], "clitcpka")) {
6862 /* enable TCP keep-alives on client sessions */
6863 curproxy->options |= PR_O_TCP_CLI_KA;
6864 }
6865 else if (!strcmp(args[1], "srvtcpka")) {
6866 /* enable TCP keep-alives on server sessions */
6867 curproxy->options |= PR_O_TCP_SRV_KA;
6868 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006869 else if (!strcmp(args[1], "allbackups")) {
6870 /* Use all backup servers simultaneously */
6871 curproxy->options |= PR_O_USE_ALL_BK;
6872 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006873 else if (!strcmp(args[1], "httpchk")) {
6874 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006875 if (curproxy->check_req != NULL) {
6876 free(curproxy->check_req);
6877 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006878 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006879 if (!*args[2]) { /* no argument */
6880 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6881 curproxy->check_len = strlen(DEF_CHECK_REQ);
6882 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006883 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6884 curproxy->check_req = (char *)malloc(reqlen);
6885 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6886 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006887 } else { /* more arguments : METHOD URI [HTTP_VER] */
6888 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6889 if (*args[4])
6890 reqlen += strlen(args[4]);
6891 else
6892 reqlen += strlen("HTTP/1.0");
6893
6894 curproxy->check_req = (char *)malloc(reqlen);
6895 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6896 "%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 +01006897 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006898 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006899 else if (!strcmp(args[1], "persist")) {
6900 /* persist on using the server specified by the cookie, even when it's down */
6901 curproxy->options |= PR_O_PERSIST;
6902 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006903 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006904 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006905 return -1;
6906 }
6907 return 0;
6908 }
6909 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6910 /* enable reconnections to dispatch */
6911 curproxy->options |= PR_O_REDISP;
6912 }
willy tarreaua1598082005-12-17 13:08:06 +01006913#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006914 else if (!strcmp(args[0], "transparent")) {
6915 /* enable transparent proxy connections */
6916 curproxy->options |= PR_O_TRANSP;
6917 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006918#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006919 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6920 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006921 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006922 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006923 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006924 curproxy->maxconn = atol(args[1]);
6925 }
6926 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6927 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006928 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006929 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006930 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006931 curproxy->grace = atol(args[1]);
6932 }
6933 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006934 if (curproxy == &defproxy) {
6935 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6936 return -1;
6937 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006938 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006939 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006940 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006941 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006942 curproxy->dispatch_addr = *str2sa(args[1]);
6943 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006944 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006945 if (*(args[1])) {
6946 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006947 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006948 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006949 else if (!strcmp(args[1], "source")) {
6950 curproxy->options |= PR_O_BALANCE_SH;
6951 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006952 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01006953 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006954 return -1;
6955 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006956 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006957 else /* if no option is set, use round-robin by default */
6958 curproxy->options |= PR_O_BALANCE_RR;
6959 }
6960 else if (!strcmp(args[0], "server")) { /* server address */
6961 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006962 char *rport;
6963 char *raddr;
6964 short realport;
6965 int do_check;
6966
6967 if (curproxy == &defproxy) {
6968 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6969 return -1;
6970 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006971
willy tarreaua41a8b42005-12-17 14:02:24 +01006972 if (!*args[2]) {
6973 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006974 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006975 return -1;
6976 }
6977 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6978 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6979 return -1;
6980 }
willy tarreau0174f312005-12-18 01:02:42 +01006981
6982 if (curproxy->srv == NULL)
6983 curproxy->srv = newsrv;
6984 else
6985 curproxy->cursrv->next = newsrv;
6986 curproxy->cursrv = newsrv;
6987
6988 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006989 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006990
6991 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006992 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006993 newsrv->id = strdup(args[1]);
6994
6995 /* several ways to check the port component :
6996 * - IP => port=+0, relative
6997 * - IP: => port=+0, relative
6998 * - IP:N => port=N, absolute
6999 * - IP:+N => port=+N, relative
7000 * - IP:-N => port=-N, relative
7001 */
7002 raddr = strdup(args[2]);
7003 rport = strchr(raddr, ':');
7004 if (rport) {
7005 *rport++ = 0;
7006 realport = atol(rport);
7007 if (!isdigit((int)*rport))
7008 newsrv->state |= SRV_MAPPORTS;
7009 } else {
7010 realport = 0;
7011 newsrv->state |= SRV_MAPPORTS;
7012 }
7013
7014 newsrv->addr = *str2sa(raddr);
7015 newsrv->addr.sin_port = htons(realport);
7016 free(raddr);
7017
willy tarreau9fe663a2005-12-17 13:02:59 +01007018 newsrv->curfd = -1; /* no health-check in progress */
7019 newsrv->inter = DEF_CHKINTR;
7020 newsrv->rise = DEF_RISETIME;
7021 newsrv->fall = DEF_FALLTIME;
7022 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7023 cur_arg = 3;
7024 while (*args[cur_arg]) {
7025 if (!strcmp(args[cur_arg], "cookie")) {
7026 newsrv->cookie = strdup(args[cur_arg + 1]);
7027 newsrv->cklen = strlen(args[cur_arg + 1]);
7028 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007029 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007030 else if (!strcmp(args[cur_arg], "rise")) {
7031 newsrv->rise = atol(args[cur_arg + 1]);
7032 newsrv->health = newsrv->rise;
7033 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007034 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007035 else if (!strcmp(args[cur_arg], "fall")) {
7036 newsrv->fall = atol(args[cur_arg + 1]);
7037 cur_arg += 2;
7038 }
7039 else if (!strcmp(args[cur_arg], "inter")) {
7040 newsrv->inter = atol(args[cur_arg + 1]);
7041 cur_arg += 2;
7042 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007043 else if (!strcmp(args[cur_arg], "port")) {
7044 newsrv->check_port = atol(args[cur_arg + 1]);
7045 cur_arg += 2;
7046 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007047 else if (!strcmp(args[cur_arg], "backup")) {
7048 newsrv->state |= SRV_BACKUP;
7049 cur_arg ++;
7050 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007051 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007052 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007053 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007054 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007055 }
willy tarreau0174f312005-12-18 01:02:42 +01007056 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7057 if (!*args[cur_arg + 1]) {
7058 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7059 file, linenum, "source");
7060 return -1;
7061 }
7062 newsrv->state |= SRV_BIND_SRC;
7063 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7064 cur_arg += 2;
7065 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007066 else {
willy tarreau0174f312005-12-18 01:02:42 +01007067 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 +01007068 file, linenum, newsrv->id);
7069 return -1;
7070 }
7071 }
7072
7073 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007074 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7075 newsrv->check_port = realport; /* by default */
7076 if (!newsrv->check_port) {
7077 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 +01007078 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007079 return -1;
7080 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007081 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007082 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007083
willy tarreau62084d42006-03-24 18:57:41 +01007084 if (newsrv->state & SRV_BACKUP)
7085 curproxy->srv_bck++;
7086 else
7087 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007088 }
7089 else if (!strcmp(args[0], "log")) { /* syslog server address */
7090 struct sockaddr_in *sa;
7091 int facility;
7092
7093 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7094 curproxy->logfac1 = global.logfac1;
7095 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007096 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007097 curproxy->logfac2 = global.logfac2;
7098 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007099 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007100 }
7101 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007102 int level;
7103
willy tarreau0f7af912005-12-17 12:21:26 +01007104 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7105 if (!strcmp(log_facilities[facility], args[2]))
7106 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007107
willy tarreau0f7af912005-12-17 12:21:26 +01007108 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007109 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007110 exit(1);
7111 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007112
willy tarreau8337c6b2005-12-17 13:41:01 +01007113 level = 7; /* max syslog level = debug */
7114 if (*(args[3])) {
7115 while (level >= 0 && strcmp(log_levels[level], args[3]))
7116 level--;
7117 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007118 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007119 exit(1);
7120 }
7121 }
7122
willy tarreau0f7af912005-12-17 12:21:26 +01007123 sa = str2sa(args[1]);
7124 if (!sa->sin_port)
7125 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007126
willy tarreau0f7af912005-12-17 12:21:26 +01007127 if (curproxy->logfac1 == -1) {
7128 curproxy->logsrv1 = *sa;
7129 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007130 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007131 }
7132 else if (curproxy->logfac2 == -1) {
7133 curproxy->logsrv2 = *sa;
7134 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007135 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007136 }
7137 else {
7138 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007139 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007140 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007141 }
7142 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007143 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007144 file, linenum);
7145 return -1;
7146 }
7147 }
willy tarreaua1598082005-12-17 13:08:06 +01007148 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007149 if (!*args[1]) {
7150 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007151 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007152 return -1;
7153 }
7154
7155 curproxy->source_addr = *str2sa(args[1]);
7156 curproxy->options |= PR_O_BIND_SRC;
7157 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007158 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7159 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007160 if (curproxy == &defproxy) {
7161 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7162 return -1;
7163 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007164
7165 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007166 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7167 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007168 return -1;
7169 }
7170
7171 preg = calloc(1, sizeof(regex_t));
7172 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007173 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007174 return -1;
7175 }
7176
willy tarreauc1f47532005-12-18 01:08:26 +01007177 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7178 if (err) {
7179 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7180 file, linenum, *err);
7181 return -1;
7182 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007183 }
7184 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7185 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007186 if (curproxy == &defproxy) {
7187 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7188 return -1;
7189 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007190
7191 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007192 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007193 return -1;
7194 }
7195
7196 preg = calloc(1, sizeof(regex_t));
7197 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007198 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007199 return -1;
7200 }
7201
7202 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7203 }
7204 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7205 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007206 if (curproxy == &defproxy) {
7207 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7208 return -1;
7209 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007210
7211 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007212 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007213 return -1;
7214 }
7215
7216 preg = calloc(1, sizeof(regex_t));
7217 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007218 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007219 return -1;
7220 }
7221
7222 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7223 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007224 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7225 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007226 if (curproxy == &defproxy) {
7227 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7228 return -1;
7229 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007230
7231 if (*(args[1]) == 0) {
7232 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7233 return -1;
7234 }
7235
7236 preg = calloc(1, sizeof(regex_t));
7237 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7238 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7239 return -1;
7240 }
7241
7242 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7243 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007244 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7245 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007246 if (curproxy == &defproxy) {
7247 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7248 return -1;
7249 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007250
7251 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007252 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007253 return -1;
7254 }
7255
7256 preg = calloc(1, sizeof(regex_t));
7257 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007258 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007259 return -1;
7260 }
7261
7262 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7263 }
7264 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7265 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007266 if (curproxy == &defproxy) {
7267 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7268 return -1;
7269 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007270
7271 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007272 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7273 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007274 return -1;
7275 }
7276
7277 preg = calloc(1, sizeof(regex_t));
7278 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007279 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007280 return -1;
7281 }
7282
willy tarreauc1f47532005-12-18 01:08:26 +01007283 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7284 if (err) {
7285 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7286 file, linenum, *err);
7287 return -1;
7288 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007289 }
7290 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7291 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007292 if (curproxy == &defproxy) {
7293 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7294 return -1;
7295 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007296
7297 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007298 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007299 return -1;
7300 }
7301
7302 preg = calloc(1, sizeof(regex_t));
7303 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007304 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007305 return -1;
7306 }
7307
7308 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7309 }
7310 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7311 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007312 if (curproxy == &defproxy) {
7313 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7314 return -1;
7315 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007316
7317 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007318 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007319 return -1;
7320 }
7321
7322 preg = calloc(1, sizeof(regex_t));
7323 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007324 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007325 return -1;
7326 }
7327
7328 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7329 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007330 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7331 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007332 if (curproxy == &defproxy) {
7333 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7334 return -1;
7335 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007336
7337 if (*(args[1]) == 0) {
7338 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7339 return -1;
7340 }
7341
7342 preg = calloc(1, sizeof(regex_t));
7343 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7344 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7345 return -1;
7346 }
7347
7348 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7349 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007350 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7351 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007352 if (curproxy == &defproxy) {
7353 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7354 return -1;
7355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007356
7357 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007358 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007359 return -1;
7360 }
7361
7362 preg = calloc(1, sizeof(regex_t));
7363 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007364 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007365 return -1;
7366 }
7367
7368 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7369 }
7370 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007371 if (curproxy == &defproxy) {
7372 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7373 return -1;
7374 }
7375
willy tarreau9fe663a2005-12-17 13:02:59 +01007376 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007377 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007378 return 0;
7379 }
7380
7381 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007382 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007383 return -1;
7384 }
7385
willy tarreau4302f492005-12-18 01:00:37 +01007386 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7387 }
7388 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7389 regex_t *preg;
7390
7391 if (*(args[1]) == 0 || *(args[2]) == 0) {
7392 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7393 file, linenum, args[0]);
7394 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007395 }
willy tarreau4302f492005-12-18 01:00:37 +01007396
7397 preg = calloc(1, sizeof(regex_t));
7398 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7399 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7400 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007401 }
willy tarreau4302f492005-12-18 01:00:37 +01007402
willy tarreauc1f47532005-12-18 01:08:26 +01007403 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7404 if (err) {
7405 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7406 file, linenum, *err);
7407 return -1;
7408 }
willy tarreau4302f492005-12-18 01:00:37 +01007409 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007410 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7411 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007412 if (curproxy == &defproxy) {
7413 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7414 return -1;
7415 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007416
7417 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007418 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007419 return -1;
7420 }
willy tarreaue39cd132005-12-17 13:00:18 +01007421
willy tarreau9fe663a2005-12-17 13:02:59 +01007422 preg = calloc(1, sizeof(regex_t));
7423 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007424 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007425 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007426 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007427
willy tarreauc1f47532005-12-18 01:08:26 +01007428 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7429 if (err) {
7430 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7431 file, linenum, *err);
7432 return -1;
7433 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007434 }
willy tarreau982249e2005-12-18 00:57:06 +01007435 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7436 regex_t *preg;
7437 if (curproxy == &defproxy) {
7438 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7439 return -1;
7440 }
7441
7442 if (*(args[1]) == 0) {
7443 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7444 return -1;
7445 }
7446
7447 preg = calloc(1, sizeof(regex_t));
7448 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7449 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7450 return -1;
7451 }
7452
willy tarreauc1f47532005-12-18 01:08:26 +01007453 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7454 if (err) {
7455 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7456 file, linenum, *err);
7457 return -1;
7458 }
willy tarreau982249e2005-12-18 00:57:06 +01007459 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007460 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007461 regex_t *preg;
7462 if (curproxy == &defproxy) {
7463 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7464 return -1;
7465 }
willy tarreaue39cd132005-12-17 13:00:18 +01007466
willy tarreaua41a8b42005-12-17 14:02:24 +01007467 if (*(args[1]) == 0 || *(args[2]) == 0) {
7468 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7469 file, linenum, args[0]);
7470 return -1;
7471 }
willy tarreaue39cd132005-12-17 13:00:18 +01007472
willy tarreaua41a8b42005-12-17 14:02:24 +01007473 preg = calloc(1, sizeof(regex_t));
7474 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7475 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7476 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007477 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007478
willy tarreauc1f47532005-12-18 01:08:26 +01007479 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7480 if (err) {
7481 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7482 file, linenum, *err);
7483 return -1;
7484 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007485 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007486 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7487 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007488 if (curproxy == &defproxy) {
7489 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7490 return -1;
7491 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007492
7493 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007494 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007495 return -1;
7496 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007497
willy tarreau9fe663a2005-12-17 13:02:59 +01007498 preg = calloc(1, sizeof(regex_t));
7499 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007500 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007501 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007502 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007503
willy tarreauc1f47532005-12-18 01:08:26 +01007504 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7505 if (err) {
7506 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7507 file, linenum, *err);
7508 return -1;
7509 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007510 }
willy tarreau982249e2005-12-18 00:57:06 +01007511 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7512 regex_t *preg;
7513 if (curproxy == &defproxy) {
7514 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7515 return -1;
7516 }
7517
7518 if (*(args[1]) == 0) {
7519 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7520 return -1;
7521 }
7522
7523 preg = calloc(1, sizeof(regex_t));
7524 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7525 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7526 return -1;
7527 }
7528
willy tarreauc1f47532005-12-18 01:08:26 +01007529 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7530 if (err) {
7531 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7532 file, linenum, *err);
7533 return -1;
7534 }
willy tarreau982249e2005-12-18 00:57:06 +01007535 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007536 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007537 if (curproxy == &defproxy) {
7538 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7539 return -1;
7540 }
7541
willy tarreau9fe663a2005-12-17 13:02:59 +01007542 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007543 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007544 return 0;
7545 }
7546
7547 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007548 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007549 return -1;
7550 }
7551
7552 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7553 }
willy tarreauc1f47532005-12-18 01:08:26 +01007554 else if (!strcmp(args[0], "errorloc") ||
7555 !strcmp(args[0], "errorloc302") ||
7556 !strcmp(args[0], "errorloc303")) { /* error location */
7557 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007558 char *err;
7559
willy tarreaueedaa9f2005-12-17 14:08:03 +01007560 // if (curproxy == &defproxy) {
7561 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7562 // return -1;
7563 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007564
willy tarreau8337c6b2005-12-17 13:41:01 +01007565 if (*(args[2]) == 0) {
7566 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7567 return -1;
7568 }
7569
7570 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007571 if (!strcmp(args[0], "errorloc303")) {
7572 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7573 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7574 } else {
7575 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7576 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7577 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007578
7579 if (errnum == 400) {
7580 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007581 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007582 free(curproxy->errmsg.msg400);
7583 }
7584 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007585 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007586 }
7587 else if (errnum == 403) {
7588 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007589 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007590 free(curproxy->errmsg.msg403);
7591 }
7592 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007593 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007594 }
7595 else if (errnum == 408) {
7596 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007597 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007598 free(curproxy->errmsg.msg408);
7599 }
7600 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007601 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007602 }
7603 else if (errnum == 500) {
7604 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007605 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007606 free(curproxy->errmsg.msg500);
7607 }
7608 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007609 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007610 }
7611 else if (errnum == 502) {
7612 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007613 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007614 free(curproxy->errmsg.msg502);
7615 }
7616 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007617 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007618 }
7619 else if (errnum == 503) {
7620 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007621 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007622 free(curproxy->errmsg.msg503);
7623 }
7624 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007625 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007626 }
7627 else if (errnum == 504) {
7628 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007629 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007630 free(curproxy->errmsg.msg504);
7631 }
7632 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007633 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007634 }
7635 else {
7636 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7637 free(err);
7638 }
7639 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007640 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007641 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007642 return -1;
7643 }
7644 return 0;
7645}
willy tarreaue39cd132005-12-17 13:00:18 +01007646
willy tarreau5cbea6f2005-12-17 12:48:26 +01007647
willy tarreau9fe663a2005-12-17 13:02:59 +01007648/*
7649 * This function reads and parses the configuration file given in the argument.
7650 * returns 0 if OK, -1 if error.
7651 */
7652int readcfgfile(char *file) {
7653 char thisline[256];
7654 char *line;
7655 FILE *f;
7656 int linenum = 0;
7657 char *end;
7658 char *args[MAX_LINE_ARGS];
7659 int arg;
7660 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007661 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007662 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007663
willy tarreau9fe663a2005-12-17 13:02:59 +01007664 struct proxy *curproxy = NULL;
7665 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007666
willy tarreau9fe663a2005-12-17 13:02:59 +01007667 if ((f=fopen(file,"r")) == NULL)
7668 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007669
willy tarreaueedaa9f2005-12-17 14:08:03 +01007670 init_default_instance();
7671
willy tarreau9fe663a2005-12-17 13:02:59 +01007672 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7673 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007674
willy tarreau9fe663a2005-12-17 13:02:59 +01007675 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007676
willy tarreau9fe663a2005-12-17 13:02:59 +01007677 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007678 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007679 line++;
7680
7681 arg = 0;
7682 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007683
willy tarreau9fe663a2005-12-17 13:02:59 +01007684 while (*line && arg < MAX_LINE_ARGS) {
7685 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7686 * C equivalent value. Other combinations left unchanged (eg: \1).
7687 */
7688 if (*line == '\\') {
7689 int skip = 0;
7690 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7691 *line = line[1];
7692 skip = 1;
7693 }
7694 else if (line[1] == 'r') {
7695 *line = '\r';
7696 skip = 1;
7697 }
7698 else if (line[1] == 'n') {
7699 *line = '\n';
7700 skip = 1;
7701 }
7702 else if (line[1] == 't') {
7703 *line = '\t';
7704 skip = 1;
7705 }
willy tarreauc1f47532005-12-18 01:08:26 +01007706 else if (line[1] == 'x') {
7707 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7708 unsigned char hex1, hex2;
7709 hex1 = toupper(line[2]) - '0';
7710 hex2 = toupper(line[3]) - '0';
7711 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7712 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7713 *line = (hex1<<4) + hex2;
7714 skip = 3;
7715 }
7716 else {
7717 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7718 return -1;
7719 }
7720 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007721 if (skip) {
7722 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7723 end -= skip;
7724 }
7725 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007726 }
willy tarreaua1598082005-12-17 13:08:06 +01007727 else if (*line == '#' || *line == '\n' || *line == '\r') {
7728 /* end of string, end of loop */
7729 *line = 0;
7730 break;
7731 }
willy tarreauc29948c2005-12-17 13:10:27 +01007732 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007733 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007734 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007735 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007736 line++;
7737 args[++arg] = line;
7738 }
7739 else {
7740 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007741 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007742 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007743
willy tarreau9fe663a2005-12-17 13:02:59 +01007744 /* empty line */
7745 if (!**args)
7746 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007747
willy tarreau9fe663a2005-12-17 13:02:59 +01007748 /* zero out remaining args */
7749 while (++arg < MAX_LINE_ARGS) {
7750 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007751 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007752
willy tarreaua41a8b42005-12-17 14:02:24 +01007753 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007754 confsect = CFG_LISTEN;
7755 else if (!strcmp(args[0], "global")) /* global config */
7756 confsect = CFG_GLOBAL;
7757 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007758
willy tarreau9fe663a2005-12-17 13:02:59 +01007759 switch (confsect) {
7760 case CFG_LISTEN:
7761 if (cfg_parse_listen(file, linenum, args) < 0)
7762 return -1;
7763 break;
7764 case CFG_GLOBAL:
7765 if (cfg_parse_global(file, linenum, args) < 0)
7766 return -1;
7767 break;
7768 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007769 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007770 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007771 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007772
7773
willy tarreau0f7af912005-12-17 12:21:26 +01007774 }
7775 fclose(f);
7776
7777 /*
7778 * Now, check for the integrity of all that we have collected.
7779 */
7780
Willy TARREAU3759f982006-03-01 22:44:17 +01007781 /* will be needed further to delay some tasks */
7782 tv_now(&now);
7783
willy tarreau0f7af912005-12-17 12:21:26 +01007784 if ((curproxy = proxy) == NULL) {
7785 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7786 file);
7787 return -1;
7788 }
7789
7790 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007791 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007792 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007793 curproxy = curproxy->next;
7794 continue;
7795 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007796
7797 if (curproxy->listen == NULL) {
7798 Alert("parsing %s : listener %s has no listen address. Please either specify a valid address on the <listen> line, or use the <bind> keyword.\n", file, curproxy->id);
7799 cfgerr++;
7800 }
7801 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007802 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007803 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007804 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7805 file, curproxy->id);
7806 cfgerr++;
7807 }
7808 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7809 if (curproxy->options & PR_O_TRANSP) {
7810 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7811 file, curproxy->id);
7812 cfgerr++;
7813 }
7814 else if (curproxy->srv == NULL) {
7815 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7816 file, curproxy->id);
7817 cfgerr++;
7818 }
willy tarreaua1598082005-12-17 13:08:06 +01007819 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007820 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7821 file, curproxy->id);
7822 }
7823 }
7824 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007825 if (curproxy->cookie_name != NULL) {
7826 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7827 file, curproxy->id);
7828 }
7829 if ((newsrv = curproxy->srv) != NULL) {
7830 Warning("parsing %s : servers will be ignored for listener %s.\n",
7831 file, curproxy->id);
7832 }
willy tarreaue39cd132005-12-17 13:00:18 +01007833 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007834 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7835 file, curproxy->id);
7836 }
willy tarreaue39cd132005-12-17 13:00:18 +01007837 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007838 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7839 file, curproxy->id);
7840 }
7841 }
7842 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7843 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7844 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7845 file, curproxy->id);
7846 cfgerr++;
7847 }
7848 else {
7849 while (newsrv != NULL) {
7850 /* nothing to check for now */
7851 newsrv = newsrv->next;
7852 }
7853 }
7854 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007855
7856 if (curproxy->options & PR_O_LOGASAP)
7857 curproxy->to_log &= ~LW_BYTES;
7858
willy tarreau8337c6b2005-12-17 13:41:01 +01007859 if (curproxy->errmsg.msg400 == NULL) {
7860 curproxy->errmsg.msg400 = (char *)HTTP_400;
7861 curproxy->errmsg.len400 = strlen(HTTP_400);
7862 }
7863 if (curproxy->errmsg.msg403 == NULL) {
7864 curproxy->errmsg.msg403 = (char *)HTTP_403;
7865 curproxy->errmsg.len403 = strlen(HTTP_403);
7866 }
7867 if (curproxy->errmsg.msg408 == NULL) {
7868 curproxy->errmsg.msg408 = (char *)HTTP_408;
7869 curproxy->errmsg.len408 = strlen(HTTP_408);
7870 }
7871 if (curproxy->errmsg.msg500 == NULL) {
7872 curproxy->errmsg.msg500 = (char *)HTTP_500;
7873 curproxy->errmsg.len500 = strlen(HTTP_500);
7874 }
7875 if (curproxy->errmsg.msg502 == NULL) {
7876 curproxy->errmsg.msg502 = (char *)HTTP_502;
7877 curproxy->errmsg.len502 = strlen(HTTP_502);
7878 }
7879 if (curproxy->errmsg.msg503 == NULL) {
7880 curproxy->errmsg.msg503 = (char *)HTTP_503;
7881 curproxy->errmsg.len503 = strlen(HTTP_503);
7882 }
7883 if (curproxy->errmsg.msg504 == NULL) {
7884 curproxy->errmsg.msg504 = (char *)HTTP_504;
7885 curproxy->errmsg.len504 = strlen(HTTP_504);
7886 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007887
7888 /* now we'll start this proxy's health checks if any */
7889 /* 1- count the checkers to run simultaneously */
7890 nbchk = 0;
7891 mininter = 0;
7892 newsrv = curproxy->srv;
7893 while (newsrv != NULL) {
7894 if (newsrv->state & SRV_CHECKED) {
7895 if (!mininter || mininter > newsrv->inter)
7896 mininter = newsrv->inter;
7897 nbchk++;
7898 }
7899 newsrv = newsrv->next;
7900 }
7901
7902 /* 2- start them as far as possible from each others while respecting
7903 * their own intervals. For this, we will start them after their own
7904 * interval added to the min interval divided by the number of servers,
7905 * weighted by the server's position in the list.
7906 */
7907 if (nbchk > 0) {
7908 struct task *t;
7909 int srvpos;
7910
7911 newsrv = curproxy->srv;
7912 srvpos = 0;
7913 while (newsrv != NULL) {
7914 /* should this server be checked ? */
7915 if (newsrv->state & SRV_CHECKED) {
7916 if ((t = pool_alloc(task)) == NULL) {
7917 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7918 return -1;
7919 }
7920
7921 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7922 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7923 t->state = TASK_IDLE;
7924 t->process = process_chk;
7925 t->context = newsrv;
7926
7927 /* check this every ms */
7928 tv_delayfrom(&t->expire, &now,
7929 newsrv->inter + mininter * srvpos / nbchk);
7930 task_queue(t);
7931 //task_wakeup(&rq, t);
7932 srvpos++;
7933 }
7934 newsrv = newsrv->next;
7935 }
7936 }
7937
willy tarreau0f7af912005-12-17 12:21:26 +01007938 curproxy = curproxy->next;
7939 }
7940 if (cfgerr > 0) {
7941 Alert("Errors found in configuration file, aborting.\n");
7942 return -1;
7943 }
7944 else
7945 return 0;
7946}
7947
7948
7949/*
7950 * This function initializes all the necessary variables. It only returns
7951 * if everything is OK. If something fails, it exits.
7952 */
7953void init(int argc, char **argv) {
7954 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007955 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007956 char *old_argv = *argv;
7957 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007958 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007959
7960 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007961 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007962 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007963 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007964 exit(1);
7965 }
7966
willy tarreau746e26b2006-03-25 11:14:35 +01007967#ifdef HAPROXY_MEMMAX
7968 global.rlimit_memmax = HAPROXY_MEMMAX;
7969#endif
7970
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007971 /* initialize the libc's localtime structures once for all so that we
7972 * won't be missing memory if we want to send alerts under OOM conditions.
7973 */
7974 tv_now(&now);
7975 localtime(&now.tv_sec);
7976
willy tarreau4302f492005-12-18 01:00:37 +01007977 /* initialize the log header encoding map : '{|}"#' should be encoded with
7978 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7979 * URL encoding only requires '"', '#' to be encoded as well as non-
7980 * printable characters above.
7981 */
7982 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7983 memset(url_encode_map, 0, sizeof(url_encode_map));
7984 for (i = 0; i < 32; i++) {
7985 FD_SET(i, hdr_encode_map);
7986 FD_SET(i, url_encode_map);
7987 }
7988 for (i = 127; i < 256; i++) {
7989 FD_SET(i, hdr_encode_map);
7990 FD_SET(i, url_encode_map);
7991 }
7992
7993 tmp = "\"#{|}";
7994 while (*tmp) {
7995 FD_SET(*tmp, hdr_encode_map);
7996 tmp++;
7997 }
7998
7999 tmp = "\"#";
8000 while (*tmp) {
8001 FD_SET(*tmp, url_encode_map);
8002 tmp++;
8003 }
8004
willy tarreau64a3cc32005-12-18 01:13:11 +01008005 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8006#if defined(ENABLE_POLL)
8007 cfg_polling_mechanism |= POLL_USE_POLL;
8008#endif
8009#if defined(ENABLE_EPOLL)
8010 cfg_polling_mechanism |= POLL_USE_EPOLL;
8011#endif
8012
willy tarreau0f7af912005-12-17 12:21:26 +01008013 pid = getpid();
8014 progname = *argv;
8015 while ((tmp = strchr(progname, '/')) != NULL)
8016 progname = tmp + 1;
8017
8018 argc--; argv++;
8019 while (argc > 0) {
8020 char *flag;
8021
8022 if (**argv == '-') {
8023 flag = *argv+1;
8024
8025 /* 1 arg */
8026 if (*flag == 'v') {
8027 display_version();
8028 exit(0);
8029 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008030#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008031 else if (*flag == 'd' && flag[1] == 'e')
8032 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008033#endif
8034#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008035 else if (*flag == 'd' && flag[1] == 'p')
8036 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008037#endif
willy tarreau982249e2005-12-18 00:57:06 +01008038 else if (*flag == 'V')
8039 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008040 else if (*flag == 'd' && flag[1] == 'b')
8041 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008042 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008043 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008044 else if (*flag == 'c')
8045 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008046 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008047 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008048 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008049 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01008050#if STATTIME > 0
8051 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01008052 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01008053 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01008054 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01008055#endif
willy tarreau53e99702006-03-25 18:53:50 +01008056 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8057 /* list of pids to finish ('f') or terminate ('t') */
8058
8059 if (flag[1] == 'f')
8060 oldpids_sig = SIGUSR1; /* finish then exit */
8061 else
8062 oldpids_sig = SIGTERM; /* terminate immediately */
8063 argv++; argc--;
8064
8065 if (argc > 0) {
8066 oldpids = calloc(argc, sizeof(int));
8067 while (argc > 0) {
8068 oldpids[nb_oldpids] = atol(*argv);
8069 if (oldpids[nb_oldpids] <= 0)
8070 usage(old_argv);
8071 argc--; argv++;
8072 nb_oldpids++;
8073 }
8074 }
8075 }
willy tarreau0f7af912005-12-17 12:21:26 +01008076 else { /* >=2 args */
8077 argv++; argc--;
8078 if (argc == 0)
8079 usage(old_argv);
8080
8081 switch (*flag) {
8082 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008083 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008084 case 'N' : cfg_maxpconn = atol(*argv); break;
8085 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008086 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008087 default: usage(old_argv);
8088 }
8089 }
8090 }
8091 else
8092 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008093 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008094 }
8095
willy tarreaud0fb4652005-12-18 01:32:04 +01008096 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008097 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8098 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008099
willy tarreau0f7af912005-12-17 12:21:26 +01008100 if (!cfg_cfgfile)
8101 usage(old_argv);
8102
8103 gethostname(hostname, MAX_HOSTNAME_LEN);
8104
willy tarreau12350152005-12-18 01:03:27 +01008105 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008106 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008107 if (readcfgfile(cfg_cfgfile) < 0) {
8108 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8109 exit(1);
8110 }
willy tarreau12350152005-12-18 01:03:27 +01008111 if (have_appsession)
8112 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008113
willy tarreau982249e2005-12-18 00:57:06 +01008114 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008115 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8116 exit(0);
8117 }
8118
willy tarreau9fe663a2005-12-17 13:02:59 +01008119 if (cfg_maxconn > 0)
8120 global.maxconn = cfg_maxconn;
8121
willy tarreaufe2c5c12005-12-17 14:14:34 +01008122 if (cfg_pidfile) {
8123 if (global.pidfile)
8124 free(global.pidfile);
8125 global.pidfile = strdup(cfg_pidfile);
8126 }
8127
willy tarreau9fe663a2005-12-17 13:02:59 +01008128 if (global.maxconn == 0)
8129 global.maxconn = DEFAULT_MAXCONN;
8130
Willy TARREAU203b0b62006-03-12 18:00:28 +01008131 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008132
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008133 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008134 /* command line debug mode inhibits configuration mode */
8135 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8136 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008137 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8138 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008139
8140 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8141 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8142 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8143 }
8144
8145 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008146 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8147 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008148 global.nbproc = 1;
8149 }
8150
8151 if (global.nbproc < 1)
8152 global.nbproc = 1;
8153
willy tarreau0f7af912005-12-17 12:21:26 +01008154 StaticReadEvent = (fd_set *)calloc(1,
8155 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008156 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008157 StaticWriteEvent = (fd_set *)calloc(1,
8158 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008159 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008160
8161 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008162 sizeof(struct fdtab) * (global.maxsock));
8163 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008164 fdtab[i].state = FD_STCLOSE;
8165 }
8166}
8167
8168/*
willy tarreau41310e72006-03-25 18:17:56 +01008169 * this function starts all the proxies. Its return value is composed from
8170 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8171 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008172 */
willy tarreau41310e72006-03-25 18:17:56 +01008173int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008174 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008175 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008176 int err = ERR_NONE;
8177 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008178
8179 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008180 if (curproxy->state != PR_STNEW)
8181 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008182
willy tarreau41310e72006-03-25 18:17:56 +01008183 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008184 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008185 if (listener->fd != -1)
8186 continue; /* already initialized */
8187
8188 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8189 if (verbose)
8190 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8191 curproxy->id);
8192 err |= ERR_RETRYABLE;
8193 pxerr |= 1;
8194 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008195 }
willy tarreau0f7af912005-12-17 12:21:26 +01008196
willy tarreaua41a8b42005-12-17 14:02:24 +01008197 if (fd >= global.maxsock) {
8198 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8199 curproxy->id);
8200 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008201 err |= ERR_FATAL;
8202 pxerr |= 1;
8203 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008204 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008205
willy tarreaua41a8b42005-12-17 14:02:24 +01008206 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8207 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8208 (char *) &one, sizeof(one)) == -1)) {
8209 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8210 curproxy->id);
8211 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008212 err |= ERR_FATAL;
8213 pxerr |= 1;
8214 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008215 }
willy tarreau0f7af912005-12-17 12:21:26 +01008216
willy tarreaua41a8b42005-12-17 14:02:24 +01008217 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8218 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8219 curproxy->id);
8220 }
willy tarreau0f7af912005-12-17 12:21:26 +01008221
willy tarreaua41a8b42005-12-17 14:02:24 +01008222 if (bind(fd,
8223 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008224 listener->addr.ss_family == AF_INET6 ?
8225 sizeof(struct sockaddr_in6) :
8226 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008227 if (verbose)
8228 Alert("cannot bind socket for proxy %s. Aborting.\n",
8229 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008230 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008231 err |= ERR_RETRYABLE;
8232 pxerr |= 1;
8233 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008234 }
willy tarreau0f7af912005-12-17 12:21:26 +01008235
willy tarreaua41a8b42005-12-17 14:02:24 +01008236 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008237 if (verbose)
8238 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8239 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008240 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008241 err |= ERR_RETRYABLE;
8242 pxerr |= 1;
8243 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008244 }
willy tarreau0f7af912005-12-17 12:21:26 +01008245
willy tarreau41310e72006-03-25 18:17:56 +01008246 /* the socket is ready */
8247 listener->fd = fd;
8248
willy tarreaua41a8b42005-12-17 14:02:24 +01008249 /* the function for the accept() event */
8250 fdtab[fd].read = &event_accept;
8251 fdtab[fd].write = NULL; /* never called */
8252 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008253 fdtab[fd].state = FD_STLISTEN;
8254 FD_SET(fd, StaticReadEvent);
8255 fd_insert(fd);
8256 listeners++;
8257 }
willy tarreau41310e72006-03-25 18:17:56 +01008258
8259 if (!pxerr) {
8260 curproxy->state = PR_STRUN;
8261 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8262 }
willy tarreau0f7af912005-12-17 12:21:26 +01008263 }
willy tarreau41310e72006-03-25 18:17:56 +01008264
8265 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008266}
8267
willy tarreaub952e1d2005-12-18 01:31:20 +01008268int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008269
8270 appsess *temp1,*temp2;
8271 temp1 = (appsess *)key1;
8272 temp2 = (appsess *)key2;
8273
8274 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8275 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8276
8277 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8278}/* end match_str */
8279
willy tarreaub952e1d2005-12-18 01:31:20 +01008280void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008281 appsess *temp1;
8282
8283 //printf("destroy called\n");
8284 temp1 = (appsess *)data;
8285
8286 if (temp1->sessid)
8287 pool_free_to(apools.sessid, temp1->sessid);
8288
8289 if (temp1->serverid)
8290 pool_free_to(apools.serverid, temp1->serverid);
8291
8292 pool_free(appsess, temp1);
8293} /* end destroy */
8294
8295void appsession_cleanup( void )
8296{
8297 struct proxy *p = proxy;
8298
8299 while(p) {
8300 chtbl_destroy(&(p->htbl_proxy));
8301 p = p->next;
8302 }
8303}/* end appsession_cleanup() */
8304
8305void pool_destroy(void **pool)
8306{
8307 void *temp, *next;
8308 next = pool;
8309 while (next) {
8310 temp = next;
8311 next = *(void **)temp;
8312 free(temp);
8313 }
8314}/* end pool_destroy() */
8315
willy tarreaub952e1d2005-12-18 01:31:20 +01008316void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008317 struct proxy *p = proxy;
8318 struct cap_hdr *h,*h_next;
8319 struct server *s,*s_next;
8320 struct listener *l,*l_next;
8321
8322 while (p) {
8323 if (p->id)
8324 free(p->id);
8325
8326 if (p->check_req)
8327 free(p->check_req);
8328
8329 if (p->cookie_name)
8330 free(p->cookie_name);
8331
8332 if (p->capture_name)
8333 free(p->capture_name);
8334
8335 /* only strup if the user have set in config.
8336 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008337 if (p->errmsg.msg400) free(p->errmsg.msg400);
8338 if (p->errmsg.msg403) free(p->errmsg.msg403);
8339 if (p->errmsg.msg408) free(p->errmsg.msg408);
8340 if (p->errmsg.msg500) free(p->errmsg.msg500);
8341 if (p->errmsg.msg502) free(p->errmsg.msg502);
8342 if (p->errmsg.msg503) free(p->errmsg.msg503);
8343 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008344 */
8345 if (p->appsession_name)
8346 free(p->appsession_name);
8347
8348 h = p->req_cap;
8349 while (h) {
8350 h_next = h->next;
8351 if (h->name)
8352 free(h->name);
8353 pool_destroy(h->pool);
8354 free(h);
8355 h = h_next;
8356 }/* end while(h) */
8357
8358 h = p->rsp_cap;
8359 while (h) {
8360 h_next = h->next;
8361 if (h->name)
8362 free(h->name);
8363
8364 pool_destroy(h->pool);
8365 free(h);
8366 h = h_next;
8367 }/* end while(h) */
8368
8369 s = p->srv;
8370 while (s) {
8371 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008372 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008373 free(s->id);
8374
willy tarreaub952e1d2005-12-18 01:31:20 +01008375 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008376 free(s->cookie);
8377
8378 free(s);
8379 s = s_next;
8380 }/* end while(s) */
8381
8382 l = p->listen;
8383 while (l) {
8384 l_next = l->next;
8385 free(l);
8386 l = l_next;
8387 }/* end while(l) */
8388
8389 pool_destroy((void **) p->req_cap_pool);
8390 pool_destroy((void **) p->rsp_cap_pool);
8391 p = p->next;
8392 }/* end while(p) */
8393
8394 if (global.chroot) free(global.chroot);
8395 if (global.pidfile) free(global.pidfile);
8396
willy tarreau12350152005-12-18 01:03:27 +01008397 if (StaticReadEvent) free(StaticReadEvent);
8398 if (StaticWriteEvent) free(StaticWriteEvent);
8399 if (fdtab) free(fdtab);
8400
8401 pool_destroy(pool_session);
8402 pool_destroy(pool_buffer);
8403 pool_destroy(pool_fdtab);
8404 pool_destroy(pool_requri);
8405 pool_destroy(pool_task);
8406 pool_destroy(pool_capture);
8407 pool_destroy(pool_appsess);
8408
8409 if (have_appsession) {
8410 pool_destroy(apools.serverid);
8411 pool_destroy(apools.sessid);
8412 }
8413} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008414
willy tarreau41310e72006-03-25 18:17:56 +01008415/* sends the signal <sig> to all pids found in <oldpids> */
8416static void tell_old_pids(int sig) {
8417 int p;
8418 for (p = 0; p < nb_oldpids; p++)
8419 kill(oldpids[p], sig);
8420}
8421
willy tarreau0f7af912005-12-17 12:21:26 +01008422int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008423 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008424 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008425 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008426 init(argc, argv);
8427
willy tarreau0f7af912005-12-17 12:21:26 +01008428 signal(SIGQUIT, dump);
8429 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008430 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008431#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008432 signal(SIGINT, sig_int);
8433 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008434#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008435
8436 /* on very high loads, a sigpipe sometimes happen just between the
8437 * getsockopt() which tells "it's OK to write", and the following write :-(
8438 */
willy tarreau3242e862005-12-17 12:27:53 +01008439#ifndef MSG_NOSIGNAL
8440 signal(SIGPIPE, SIG_IGN);
8441#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008442
willy tarreau41310e72006-03-25 18:17:56 +01008443 /* We will loop at most 100 times with 10 ms delay each time.
8444 * That's at most 1 second. We only send a signal to old pids
8445 * if we cannot grab at least one port.
8446 */
8447 retry = MAX_START_RETRIES;
8448 err = ERR_NONE;
8449 while (retry >= 0) {
8450 struct timeval w;
8451 err = start_proxies(retry == 0 || nb_oldpids == 0);
8452 if (err != ERR_RETRYABLE)
8453 break;
8454 if (nb_oldpids == 0)
8455 break;
8456
8457 tell_old_pids(SIGTTOU);
8458 /* give some time to old processes to stop listening */
8459 w.tv_sec = 0;
8460 w.tv_usec = 10*1000;
8461 select(0, NULL, NULL, NULL, &w);
8462 retry--;
8463 }
8464
8465 /* Note: start_proxies() sends an alert when it fails. */
8466 if (err != ERR_NONE) {
8467 if (retry != MAX_START_RETRIES && nb_oldpids)
8468 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008469 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008470 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008471
8472 if (listeners == 0) {
8473 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008474 /* Note: we don't have to send anything to the old pids because we
8475 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008476 exit(1);
8477 }
8478
willy tarreaudbd3bef2006-01-20 19:35:18 +01008479 /* prepare pause/play signals */
8480 signal(SIGTTOU, sig_pause);
8481 signal(SIGTTIN, sig_listen);
8482
Willy TARREAUe3283d12006-03-01 22:15:29 +01008483 if (global.mode & MODE_DAEMON) {
8484 global.mode &= ~MODE_VERBOSE;
8485 global.mode |= MODE_QUIET;
8486 }
8487
willy tarreaud0fb4652005-12-18 01:32:04 +01008488 /* MODE_QUIET can inhibit alerts and warnings below this line */
8489
8490 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008491 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008492 /* detach from the tty */
8493 fclose(stdin); fclose(stdout); fclose(stderr);
8494 close(0); close(1); close(2);
8495 }
willy tarreau0f7af912005-12-17 12:21:26 +01008496
willy tarreaufe2c5c12005-12-17 14:14:34 +01008497 /* open log & pid files before the chroot */
8498 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8499 int pidfd;
8500 unlink(global.pidfile);
8501 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8502 if (pidfd < 0) {
8503 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008504 if (nb_oldpids)
8505 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008506 exit(1);
8507 }
8508 pidfile = fdopen(pidfd, "w");
8509 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008510
8511 /* chroot if needed */
8512 if (global.chroot != NULL) {
8513 if (chroot(global.chroot) == -1) {
8514 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008515 if (nb_oldpids)
8516 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008517 }
8518 chdir("/");
8519 }
8520
willy tarreaub1285d52005-12-18 01:20:14 +01008521 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008522 if (!global.rlimit_nofile)
8523 global.rlimit_nofile = global.maxsock;
8524
willy tarreaub1285d52005-12-18 01:20:14 +01008525 if (global.rlimit_nofile) {
8526 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8527 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8528 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8529 }
willy tarreau746e26b2006-03-25 11:14:35 +01008530 }
8531
8532 if (global.rlimit_memmax) {
8533 limit.rlim_cur = limit.rlim_max =
8534 global.rlimit_memmax * 1048576 / global.nbproc;
8535#ifdef RLIMIT_AS
8536 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8537 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8538 argv[0], global.rlimit_memmax);
8539 }
8540#else
8541 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8542 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8543 argv[0], global.rlimit_memmax);
8544 }
8545#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008546 }
8547
willy tarreau41310e72006-03-25 18:17:56 +01008548 if (nb_oldpids)
8549 tell_old_pids(oldpids_sig);
8550
8551 /* Note that any error at this stage will be fatal because we will not
8552 * be able to restart the old pids.
8553 */
8554
willy tarreau9fe663a2005-12-17 13:02:59 +01008555 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008556 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008557 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8558 exit(1);
8559 }
8560
willy tarreau036e1ce2005-12-17 13:46:33 +01008561 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008562 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8563 exit(1);
8564 }
8565
willy tarreaub1285d52005-12-18 01:20:14 +01008566 /* check ulimits */
8567 limit.rlim_cur = limit.rlim_max = 0;
8568 getrlimit(RLIMIT_NOFILE, &limit);
8569 if (limit.rlim_cur < global.maxsock) {
8570 Warning("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
8571 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8572 }
8573
willy tarreau9fe663a2005-12-17 13:02:59 +01008574 if (global.mode & MODE_DAEMON) {
8575 int ret = 0;
8576 int proc;
8577
8578 /* the father launches the required number of processes */
8579 for (proc = 0; proc < global.nbproc; proc++) {
8580 ret = fork();
8581 if (ret < 0) {
8582 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008583 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008584 exit(1); /* there has been an error */
8585 }
8586 else if (ret == 0) /* child breaks here */
8587 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008588 if (pidfile != NULL) {
8589 fprintf(pidfile, "%d\n", ret);
8590 fflush(pidfile);
8591 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008592 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008593 /* close the pidfile both in children and father */
8594 if (pidfile != NULL)
8595 fclose(pidfile);
8596 free(global.pidfile);
8597
willy tarreau9fe663a2005-12-17 13:02:59 +01008598 if (proc == global.nbproc)
8599 exit(0); /* parent must leave */
8600
willy tarreau750a4722005-12-17 13:21:24 +01008601 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8602 * that we can detach from the TTY. We MUST NOT do it in other cases since
8603 * it would have already be done, and 0-2 would have been affected to listening
8604 * sockets
8605 */
8606 if (!(global.mode & MODE_QUIET)) {
8607 /* detach from the tty */
8608 fclose(stdin); fclose(stdout); fclose(stderr);
8609 close(0); close(1); close(2); /* close all fd's */
8610 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8611 }
willy tarreaua1598082005-12-17 13:08:06 +01008612 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008613 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008614 }
8615
willy tarreau1c2ad212005-12-18 01:11:29 +01008616#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008617 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008618 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8619 epoll_loop(POLL_LOOP_ACTION_RUN);
8620 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008621 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008622 }
8623 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008624 Warning("epoll() is not available. Using poll()/select() instead.\n");
8625 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008626 }
8627 }
8628#endif
8629
8630#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008631 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008632 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8633 poll_loop(POLL_LOOP_ACTION_RUN);
8634 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008635 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008636 }
8637 else {
8638 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008639 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008640 }
8641 }
8642#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008643 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008644 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8645 select_loop(POLL_LOOP_ACTION_RUN);
8646 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008647 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008648 }
8649 }
8650
willy tarreau0f7af912005-12-17 12:21:26 +01008651
willy tarreau12350152005-12-18 01:03:27 +01008652 /* Free all Hash Keys and all Hash elements */
8653 appsession_cleanup();
8654 /* Do some cleanup */
8655 deinit();
8656
willy tarreau0f7af912005-12-17 12:21:26 +01008657 exit(0);
8658}
willy tarreau12350152005-12-18 01:03:27 +01008659
8660#if defined(DEBUG_HASH)
8661static void print_table(const CHTbl *htbl) {
8662
8663 ListElmt *element;
8664 int i;
8665 appsess *asession;
8666
8667 /*****************************************************************************
8668 * *
8669 * Display the chained hash table. *
8670 * *
8671 *****************************************************************************/
8672
8673 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8674
8675 for (i = 0; i < TBLSIZ; i++) {
8676 fprintf(stdout, "Bucket[%03d]\n", i);
8677
8678 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8679 //fprintf(stdout, "%c", *(char *)list_data(element));
8680 asession = (appsess *)list_data(element);
8681 fprintf(stdout, "ELEM :%s:", asession->sessid);
8682 fprintf(stdout, " Server :%s: \n", asession->serverid);
8683 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8684 }
8685
8686 fprintf(stdout, "\n");
8687 }
8688 return;
8689} /* end print_table */
8690#endif
8691
8692static int appsession_init(void)
8693{
8694 static int initialized = 0;
8695 int idlen;
8696 struct server *s;
8697 struct proxy *p = proxy;
8698
8699 if (!initialized) {
8700 if (!appsession_task_init()) {
8701 apools.sessid = NULL;
8702 apools.serverid = NULL;
8703 apools.ser_waste = 0;
8704 apools.ser_use = 0;
8705 apools.ser_msize = sizeof(void *);
8706 apools.ses_waste = 0;
8707 apools.ses_use = 0;
8708 apools.ses_msize = sizeof(void *);
8709 while (p) {
8710 s = p->srv;
8711 if (apools.ses_msize < p->appsession_len)
8712 apools.ses_msize = p->appsession_len;
8713 while (s) {
8714 idlen = strlen(s->id);
8715 if (apools.ser_msize < idlen)
8716 apools.ser_msize = idlen;
8717 s = s->next;
8718 }
8719 p = p->next;
8720 }
8721 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8722 apools.ses_msize ++;
8723 }
8724 else {
8725 fprintf(stderr, "appsession_task_init failed\n");
8726 return -1;
8727 }
8728 initialized ++;
8729 }
8730 return 0;
8731}
8732
8733static int appsession_task_init(void)
8734{
8735 static int initialized = 0;
8736 struct task *t;
8737 if (!initialized) {
8738 if ((t = pool_alloc(task)) == NULL)
8739 return -1;
8740 t->next = t->prev = t->rqnext = NULL;
8741 t->wq = LIST_HEAD(wait_queue);
8742 t->state = TASK_IDLE;
8743 t->context = NULL;
8744 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8745 task_queue(t);
8746 t->process = appsession_refresh;
8747 initialized ++;
8748 }
8749 return 0;
8750}
8751
8752static int appsession_refresh(struct task *t) {
8753 struct proxy *p = proxy;
8754 CHTbl *htbl;
8755 ListElmt *element, *last;
8756 int i;
8757 appsess *asession;
8758 void *data;
8759
8760 while (p) {
8761 if (p->appsession_name != NULL) {
8762 htbl = &p->htbl_proxy;
8763 /* if we ever give up the use of TBLSIZ, we need to change this */
8764 for (i = 0; i < TBLSIZ; i++) {
8765 last = NULL;
8766 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8767 asession = (appsess *)list_data(element);
8768 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8769 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8770 int len;
8771 /*
8772 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8773 */
8774 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8775 asession->sessid, asession->serverid?asession->serverid:"(null)");
8776 write(1, trash, len);
8777 }
8778 /* delete the expired element from within the hash table */
8779 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8780 && (htbl->table[i].destroy != NULL)) {
8781 htbl->table[i].destroy(data);
8782 }
8783 if (last == NULL) {/* patient lost his head, get a new one */
8784 element = list_head(&htbl->table[i]);
8785 if (element == NULL) break; /* no heads left, go to next patient */
8786 }
8787 else
8788 element = last;
8789 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8790 else
8791 last = element;
8792 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8793 }
8794 }
8795 p = p->next;
8796 }
8797 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8798 return TBLCHKINT;
8799} /* end appsession_refresh */
8800