blob: df6f5d664f20dea16cb0c5569c822bef5e3b0f63 [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
willy tarreaue0dd2692006-03-30 16:27:34 +020091#define HAPROXY_VERSION "1.2.11.1"
willy tarreaubfad5742006-03-23 14:19:11 +010092#endif
93
94#ifndef HAPROXY_DATE
willy tarreaue0dd2692006-03-30 16:27:34 +020095#define HAPROXY_DATE "2006/03/30"
willy tarreaubfad5742006-03-23 14:19:11 +010096#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 tarreau06a12052006-03-30 14:06:51 +02005344 s->state |= SRV_RUNNING;
5345
willy tarreau535ae7a2005-12-17 12:58:00 +01005346 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005347 recount_servers(s->proxy);
5348 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5349 s->state & SRV_BACKUP ? "Backup " : "",
5350 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5351 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5352 send_log(s->proxy, LOG_NOTICE,
5353 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5354 s->state & SRV_BACKUP ? "Backup " : "",
5355 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5356 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005357 }
willy tarreauef900ab2005-12-17 12:52:52 +01005358
willy tarreaue47c8d72005-12-17 12:55:52 +01005359 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005360 }
willy tarreauef900ab2005-12-17 12:52:52 +01005361 s->curfd = -1; /* no check running anymore */
5362 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005363 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005364 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5365 tv_delayfrom(&t->expire, &t->expire, s->inter);
5366 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005367 }
5368 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5369 //fprintf(stderr, "process_chk: 10\n");
5370 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005371 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005372 s->health--; /* still good */
5373 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005374 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005375
willy tarreau62084d42006-03-24 18:57:41 +01005376 if (s->health == s->rise) {
5377 recount_servers(s->proxy);
5378 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5379 s->state & SRV_BACKUP ? "Backup " : "",
5380 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5381 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5382 send_log(s->proxy, LOG_ALERT,
5383 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5384 s->state & SRV_BACKUP ? "Backup " : "",
5385 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5386 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5387
5388 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5389 Alert("Proxy %s has no server available !\n", s->proxy->id);
5390 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5391 }
5392 }
willy tarreauef900ab2005-12-17 12:52:52 +01005393
willy tarreau5cbea6f2005-12-17 12:48:26 +01005394 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005395 }
5396 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005397 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005398 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005399 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5400 tv_delayfrom(&t->expire, &t->expire, s->inter);
5401 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005402 }
5403 /* if result is 0 and there's no timeout, we have to wait again */
5404 }
5405 //fprintf(stderr, "process_chk: 11\n");
5406 s->result = 0;
5407 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005408 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005409}
5410
5411
willy tarreau5cbea6f2005-12-17 12:48:26 +01005412
willy tarreau0f7af912005-12-17 12:21:26 +01005413#if STATTIME > 0
5414int stats(void);
5415#endif
5416
5417/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005418 * This does 4 things :
5419 * - wake up all expired tasks
5420 * - call all runnable tasks
5421 * - call maintain_proxies() to enable/disable the listeners
5422 * - return the delay till next event in ms, -1 = wait indefinitely
5423 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5424 *
willy tarreau0f7af912005-12-17 12:21:26 +01005425 */
5426
willy tarreau1c2ad212005-12-18 01:11:29 +01005427int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005428 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005429 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005430 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005431
willy tarreaub952e1d2005-12-18 01:31:20 +01005432 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005433
willy tarreau1c2ad212005-12-18 01:11:29 +01005434 /* look for expired tasks and add them to the run queue.
5435 */
5436 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5437 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5438 tnext = t->next;
5439 if (t->state & TASK_RUNNING)
5440 continue;
5441
willy tarreaub952e1d2005-12-18 01:31:20 +01005442 if (tv_iseternity(&t->expire))
5443 continue;
5444
willy tarreau1c2ad212005-12-18 01:11:29 +01005445 /* wakeup expired entries. It doesn't matter if they are
5446 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005447 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005448 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005449 task_wakeup(&rq, t);
5450 }
5451 else {
5452 /* first non-runnable task. Use its expiration date as an upper bound */
5453 int temp_time = tv_remain(&now, &t->expire);
5454 if (temp_time)
5455 next_time = temp_time;
5456 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005457 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005458 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005459
willy tarreau1c2ad212005-12-18 01:11:29 +01005460 /* process each task in the run queue now. Each task may be deleted
5461 * since we only use tnext.
5462 */
5463 tnext = rq;
5464 while ((t = tnext) != NULL) {
5465 int temp_time;
5466
5467 tnext = t->rqnext;
5468 task_sleep(&rq, t);
5469 temp_time = t->process(t);
5470 next_time = MINTIME(temp_time, next_time);
5471 }
5472
5473 /* maintain all proxies in a consistent state. This should quickly become a task */
5474 time2 = maintain_proxies();
5475 return MINTIME(time2, next_time);
5476}
5477
5478
5479#if defined(ENABLE_EPOLL)
5480
5481/*
5482 * Main epoll() loop.
5483 */
5484
5485/* does 3 actions :
5486 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5487 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5488 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5489 *
5490 * returns 0 if initialization failed, !0 otherwise.
5491 */
5492
5493int epoll_loop(int action) {
5494 int next_time;
5495 int status;
5496 int fd;
5497
5498 int fds, count;
5499 int pr, pw, sr, sw;
5500 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5501 struct epoll_event ev;
5502
5503 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005504 static struct epoll_event *epoll_events = NULL;
5505 static int epoll_fd;
5506
5507 if (action == POLL_LOOP_ACTION_INIT) {
5508 epoll_fd = epoll_create(global.maxsock + 1);
5509 if (epoll_fd < 0)
5510 return 0;
5511 else {
5512 epoll_events = (struct epoll_event*)
5513 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5514 PrevReadEvent = (fd_set *)
5515 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5516 PrevWriteEvent = (fd_set *)
5517 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005518 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005519 return 1;
5520 }
5521 else if (action == POLL_LOOP_ACTION_CLEAN) {
5522 if (PrevWriteEvent) free(PrevWriteEvent);
5523 if (PrevReadEvent) free(PrevReadEvent);
5524 if (epoll_events) free(epoll_events);
5525 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005526 epoll_fd = 0;
5527 return 1;
5528 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005529
willy tarreau1c2ad212005-12-18 01:11:29 +01005530 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005531
willy tarreau1c2ad212005-12-18 01:11:29 +01005532 tv_now(&now);
5533
5534 while (1) {
5535 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005536
5537 /* stop when there's no connection left and we don't allow them anymore */
5538 if (!actconn && listeners == 0)
5539 break;
5540
willy tarreau0f7af912005-12-17 12:21:26 +01005541#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005542 {
5543 int time2;
5544 time2 = stats();
5545 next_time = MINTIME(time2, next_time);
5546 }
willy tarreau0f7af912005-12-17 12:21:26 +01005547#endif
5548
willy tarreau1c2ad212005-12-18 01:11:29 +01005549 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5550
5551 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5552 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5553
5554 if ((ro^rn) | (wo^wn)) {
5555 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5556#define FDSETS_ARE_INT_ALIGNED
5557#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005558
willy tarreauad90a0c2005-12-18 01:09:15 +01005559#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5560#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005561 pr = (ro >> count) & 1;
5562 pw = (wo >> count) & 1;
5563 sr = (rn >> count) & 1;
5564 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005565#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005566 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5567 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5568 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5569 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005570#endif
5571#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005572 pr = FD_ISSET(fd, PrevReadEvent);
5573 pw = FD_ISSET(fd, PrevWriteEvent);
5574 sr = FD_ISSET(fd, StaticReadEvent);
5575 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005576#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005577 if (!((sr^pr) | (sw^pw)))
5578 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005579
willy tarreau1c2ad212005-12-18 01:11:29 +01005580 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5581 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005582
willy tarreaub952e1d2005-12-18 01:31:20 +01005583#ifdef EPOLL_CTL_MOD_WORKAROUND
5584 /* I encountered a rarely reproducible problem with
5585 * EPOLL_CTL_MOD where a modified FD (systematically
5586 * the one in epoll_events[0], fd#7) would sometimes
5587 * be set EPOLL_OUT while asked for a read ! This is
5588 * with the 2.4 epoll patch. The workaround is to
5589 * delete then recreate in case of modification.
5590 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5591 * nor RHEL kernels.
5592 */
5593
5594 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5595 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5596
5597 if ((sr | sw))
5598 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5599#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005600 if ((pr | pw)) {
5601 /* the file-descriptor already exists... */
5602 if ((sr | sw)) {
5603 /* ...and it will still exist */
5604 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5605 // perror("epoll_ctl(MOD)");
5606 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005607 }
5608 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005609 /* ...and it will be removed */
5610 if (fdtab[fd].state != FD_STCLOSE &&
5611 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5612 // perror("epoll_ctl(DEL)");
5613 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005614 }
5615 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005616 } else {
5617 /* the file-descriptor did not exist, let's add it */
5618 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5619 // perror("epoll_ctl(ADD)");
5620 // exit(1);
5621 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005622 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005623#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005624 }
5625 ((int*)PrevReadEvent)[fds] = rn;
5626 ((int*)PrevWriteEvent)[fds] = wn;
5627 }
5628 }
5629
5630 /* now let's wait for events */
5631 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5632 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005633
willy tarreau1c2ad212005-12-18 01:11:29 +01005634 for (count = 0; count < status; count++) {
5635 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005636
5637 if (FD_ISSET(fd, StaticReadEvent)) {
5638 if (fdtab[fd].state == FD_STCLOSE)
5639 continue;
5640 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5641 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005642 }
willy tarreau05be12b2006-03-19 19:35:00 +01005643
5644 if (FD_ISSET(fd, StaticWriteEvent)) {
5645 if (fdtab[fd].state == FD_STCLOSE)
5646 continue;
5647 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5648 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005649 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005650 }
5651 }
5652 return 1;
5653}
5654#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005655
willy tarreauad90a0c2005-12-18 01:09:15 +01005656
willy tarreau5cbea6f2005-12-17 12:48:26 +01005657
willy tarreau1c2ad212005-12-18 01:11:29 +01005658#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005659
willy tarreau1c2ad212005-12-18 01:11:29 +01005660/*
5661 * Main poll() loop.
5662 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005663
willy tarreau1c2ad212005-12-18 01:11:29 +01005664/* does 3 actions :
5665 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5666 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5667 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5668 *
5669 * returns 0 if initialization failed, !0 otherwise.
5670 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005671
willy tarreau1c2ad212005-12-18 01:11:29 +01005672int poll_loop(int action) {
5673 int next_time;
5674 int status;
5675 int fd, nbfd;
5676
5677 int fds, count;
5678 int sr, sw;
5679 unsigned rn, wn; /* read new, write new */
5680
5681 /* private data */
5682 static struct pollfd *poll_events = NULL;
5683
5684 if (action == POLL_LOOP_ACTION_INIT) {
5685 poll_events = (struct pollfd*)
5686 calloc(1, sizeof(struct pollfd) * global.maxsock);
5687 return 1;
5688 }
5689 else if (action == POLL_LOOP_ACTION_CLEAN) {
5690 if (poll_events)
5691 free(poll_events);
5692 return 1;
5693 }
5694
5695 /* OK, it's POLL_LOOP_ACTION_RUN */
5696
5697 tv_now(&now);
5698
5699 while (1) {
5700 next_time = process_runnable_tasks();
5701
5702 /* stop when there's no connection left and we don't allow them anymore */
5703 if (!actconn && listeners == 0)
5704 break;
5705
5706#if STATTIME > 0
5707 {
5708 int time2;
5709 time2 = stats();
5710 next_time = MINTIME(time2, next_time);
5711 }
5712#endif
5713
5714
5715 nbfd = 0;
5716 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5717
5718 rn = ((int*)StaticReadEvent)[fds];
5719 wn = ((int*)StaticWriteEvent)[fds];
5720
5721 if ((rn|wn)) {
5722 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5723#define FDSETS_ARE_INT_ALIGNED
5724#ifdef FDSETS_ARE_INT_ALIGNED
5725
5726#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5727#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5728 sr = (rn >> count) & 1;
5729 sw = (wn >> count) & 1;
5730#else
5731 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5732 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5733#endif
5734#else
5735 sr = FD_ISSET(fd, StaticReadEvent);
5736 sw = FD_ISSET(fd, StaticWriteEvent);
5737#endif
5738 if ((sr|sw)) {
5739 poll_events[nbfd].fd = fd;
5740 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5741 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005742 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005743 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005744 }
5745 }
5746
5747 /* now let's wait for events */
5748 status = poll(poll_events, nbfd, next_time);
5749 tv_now(&now);
5750
5751 for (count = 0; status > 0 && count < nbfd; count++) {
5752 fd = poll_events[count].fd;
5753
5754 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5755 continue;
5756
5757 /* ok, we found one active fd */
5758 status--;
5759
willy tarreau05be12b2006-03-19 19:35:00 +01005760 if (FD_ISSET(fd, StaticReadEvent)) {
5761 if (fdtab[fd].state == FD_STCLOSE)
5762 continue;
5763 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5764 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005765 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005766
willy tarreau05be12b2006-03-19 19:35:00 +01005767 if (FD_ISSET(fd, StaticWriteEvent)) {
5768 if (fdtab[fd].state == FD_STCLOSE)
5769 continue;
5770 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5771 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005772 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005773 }
5774 }
5775 return 1;
5776}
willy tarreauad90a0c2005-12-18 01:09:15 +01005777#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005778
willy tarreauad90a0c2005-12-18 01:09:15 +01005779
willy tarreauad90a0c2005-12-18 01:09:15 +01005780
willy tarreau1c2ad212005-12-18 01:11:29 +01005781/*
5782 * Main select() loop.
5783 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005784
willy tarreau1c2ad212005-12-18 01:11:29 +01005785/* does 3 actions :
5786 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5787 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5788 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5789 *
5790 * returns 0 if initialization failed, !0 otherwise.
5791 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005792
willy tarreauad90a0c2005-12-18 01:09:15 +01005793
willy tarreau1c2ad212005-12-18 01:11:29 +01005794int select_loop(int action) {
5795 int next_time;
5796 int status;
5797 int fd,i;
5798 struct timeval delta;
5799 int readnotnull, writenotnull;
5800 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005801
willy tarreau1c2ad212005-12-18 01:11:29 +01005802 if (action == POLL_LOOP_ACTION_INIT) {
5803 ReadEvent = (fd_set *)
5804 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5805 WriteEvent = (fd_set *)
5806 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5807 return 1;
5808 }
5809 else if (action == POLL_LOOP_ACTION_CLEAN) {
5810 if (WriteEvent) free(WriteEvent);
5811 if (ReadEvent) free(ReadEvent);
5812 return 1;
5813 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005814
willy tarreau1c2ad212005-12-18 01:11:29 +01005815 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005816
willy tarreau1c2ad212005-12-18 01:11:29 +01005817 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005818
willy tarreau1c2ad212005-12-18 01:11:29 +01005819 while (1) {
5820 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005821
willy tarreau1c2ad212005-12-18 01:11:29 +01005822 /* stop when there's no connection left and we don't allow them anymore */
5823 if (!actconn && listeners == 0)
5824 break;
5825
5826#if STATTIME > 0
5827 {
5828 int time2;
5829 time2 = stats();
5830 next_time = MINTIME(time2, next_time);
5831 }
5832#endif
5833
willy tarreau1c2ad212005-12-18 01:11:29 +01005834 if (next_time > 0) { /* FIXME */
5835 /* Convert to timeval */
5836 /* to avoid eventual select loops due to timer precision */
5837 next_time += SCHEDULER_RESOLUTION;
5838 delta.tv_sec = next_time / 1000;
5839 delta.tv_usec = (next_time % 1000) * 1000;
5840 }
5841 else if (next_time == 0) { /* allow select to return immediately when needed */
5842 delta.tv_sec = delta.tv_usec = 0;
5843 }
5844
5845
5846 /* let's restore fdset state */
5847
5848 readnotnull = 0; writenotnull = 0;
5849 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5850 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5851 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5852 }
5853
5854 // /* just a verification code, needs to be removed for performance */
5855 // for (i=0; i<maxfd; i++) {
5856 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5857 // abort();
5858 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5859 // abort();
5860 //
5861 // }
5862
5863 status = select(maxfd,
5864 readnotnull ? ReadEvent : NULL,
5865 writenotnull ? WriteEvent : NULL,
5866 NULL,
5867 (next_time >= 0) ? &delta : NULL);
5868
5869 /* this is an experiment on the separation of the select work */
5870 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5871 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5872
5873 tv_now(&now);
5874
5875 if (status > 0) { /* must proceed with events */
5876
5877 int fds;
5878 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005879
willy tarreau1c2ad212005-12-18 01:11:29 +01005880 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5881 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5882 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5883
5884 /* if we specify read first, the accepts and zero reads will be
5885 * seen first. Moreover, system buffers will be flushed faster.
5886 */
willy tarreau05be12b2006-03-19 19:35:00 +01005887 if (FD_ISSET(fd, ReadEvent)) {
5888 if (fdtab[fd].state == FD_STCLOSE)
5889 continue;
5890 fdtab[fd].read(fd);
5891 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005892
willy tarreau05be12b2006-03-19 19:35:00 +01005893 if (FD_ISSET(fd, WriteEvent)) {
5894 if (fdtab[fd].state == FD_STCLOSE)
5895 continue;
5896 fdtab[fd].write(fd);
5897 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005898 }
5899 }
5900 else {
5901 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005902 }
willy tarreau0f7af912005-12-17 12:21:26 +01005903 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005904 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005905}
5906
5907
5908#if STATTIME > 0
5909/*
5910 * Display proxy statistics regularly. It is designed to be called from the
5911 * select_loop().
5912 */
5913int stats(void) {
5914 static int lines;
5915 static struct timeval nextevt;
5916 static struct timeval lastevt;
5917 static struct timeval starttime = {0,0};
5918 unsigned long totaltime, deltatime;
5919 int ret;
5920
willy tarreau750a4722005-12-17 13:21:24 +01005921 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005922 deltatime = (tv_diff(&lastevt, &now)?:1);
5923 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005924
willy tarreau9fe663a2005-12-17 13:02:59 +01005925 if (global.mode & MODE_STATS) {
5926 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005927 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005928 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5929 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005930 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005931 actconn, totalconn,
5932 stats_tsk_new, stats_tsk_good,
5933 stats_tsk_left, stats_tsk_right,
5934 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5935 }
5936 }
5937
5938 tv_delayfrom(&nextevt, &now, STATTIME);
5939
5940 lastevt=now;
5941 }
5942 ret = tv_remain(&now, &nextevt);
5943 return ret;
5944}
5945#endif
5946
5947
5948/*
5949 * this function enables proxies when there are enough free sessions,
5950 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005951 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005952 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005953 */
5954static int maintain_proxies(void) {
5955 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005956 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005957 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005958
5959 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005960 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005961
5962 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005963 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005964 while (p) {
5965 if (p->nbconn < p->maxconn) {
5966 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005967 for (l = p->listen; l != NULL; l = l->next) {
5968 FD_SET(l->fd, StaticReadEvent);
5969 }
willy tarreau0f7af912005-12-17 12:21:26 +01005970 p->state = PR_STRUN;
5971 }
5972 }
5973 else {
5974 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005975 for (l = p->listen; l != NULL; l = l->next) {
5976 FD_CLR(l->fd, StaticReadEvent);
5977 }
willy tarreau0f7af912005-12-17 12:21:26 +01005978 p->state = PR_STIDLE;
5979 }
5980 }
5981 p = p->next;
5982 }
5983 }
5984 else { /* block all proxies */
5985 while (p) {
5986 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005987 for (l = p->listen; l != NULL; l = l->next) {
5988 FD_CLR(l->fd, StaticReadEvent);
5989 }
willy tarreau0f7af912005-12-17 12:21:26 +01005990 p->state = PR_STIDLE;
5991 }
5992 p = p->next;
5993 }
5994 }
5995
willy tarreau5cbea6f2005-12-17 12:48:26 +01005996 if (stopping) {
5997 p = proxy;
5998 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005999 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006000 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006001 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006002 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006003 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006004 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006005
willy tarreaua41a8b42005-12-17 14:02:24 +01006006 for (l = p->listen; l != NULL; l = l->next) {
6007 fd_delete(l->fd);
6008 listeners--;
6009 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006010 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006011 }
6012 else {
6013 tleft = MINTIME(t, tleft);
6014 }
6015 }
6016 p = p->next;
6017 }
6018 }
6019 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006020}
6021
6022/*
6023 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006024 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6025 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006026 */
6027static void soft_stop(void) {
6028 struct proxy *p;
6029
6030 stopping = 1;
6031 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006032 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006033 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006034 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006035 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006036 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006037 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006038 }
willy tarreau0f7af912005-12-17 12:21:26 +01006039 p = p->next;
6040 }
6041}
6042
willy tarreaudbd3bef2006-01-20 19:35:18 +01006043static void pause_proxy(struct proxy *p) {
6044 struct listener *l;
6045 for (l = p->listen; l != NULL; l = l->next) {
6046 shutdown(l->fd, SHUT_RD);
6047 FD_CLR(l->fd, StaticReadEvent);
6048 p->state = PR_STPAUSED;
6049 }
6050}
6051
6052/*
6053 * This function temporarily disables listening so that another new instance
6054 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006055 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006056 * the proxy, or a SIGTTIN can be sent to listen again.
6057 */
6058static void pause_proxies(void) {
6059 struct proxy *p;
6060
6061 p = proxy;
6062 tv_now(&now); /* else, the old time before select will be used */
6063 while (p) {
6064 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6065 Warning("Pausing proxy %s.\n", p->id);
6066 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6067 pause_proxy(p);
6068 }
6069 p = p->next;
6070 }
6071}
6072
6073
6074/*
6075 * This function reactivates listening. This can be used after a call to
6076 * sig_pause(), for example when a new instance has failed starting up.
6077 * It is designed to be called upon reception of a SIGTTIN.
6078 */
6079static void listen_proxies(void) {
6080 struct proxy *p;
6081 struct listener *l;
6082
6083 p = proxy;
6084 tv_now(&now); /* else, the old time before select will be used */
6085 while (p) {
6086 if (p->state == PR_STPAUSED) {
6087 Warning("Enabling proxy %s.\n", p->id);
6088 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6089
6090 for (l = p->listen; l != NULL; l = l->next) {
6091 if (listen(l->fd, p->maxconn) == 0) {
6092 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6093 FD_SET(l->fd, StaticReadEvent);
6094 p->state = PR_STRUN;
6095 }
6096 else
6097 p->state = PR_STIDLE;
6098 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006099 int port;
6100
6101 if (l->addr.ss_family == AF_INET6)
6102 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6103 else
6104 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6105
willy tarreaudbd3bef2006-01-20 19:35:18 +01006106 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006107 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006108 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006109 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006110 /* Another port might have been enabled. Let's stop everything. */
6111 pause_proxy(p);
6112 break;
6113 }
6114 }
6115 }
6116 p = p->next;
6117 }
6118}
6119
6120
willy tarreau0f7af912005-12-17 12:21:26 +01006121/*
6122 * upon SIGUSR1, let's have a soft stop.
6123 */
6124void sig_soft_stop(int sig) {
6125 soft_stop();
6126 signal(sig, SIG_IGN);
6127}
6128
willy tarreaudbd3bef2006-01-20 19:35:18 +01006129/*
6130 * upon SIGTTOU, we pause everything
6131 */
6132void sig_pause(int sig) {
6133 pause_proxies();
6134 signal(sig, sig_pause);
6135}
willy tarreau0f7af912005-12-17 12:21:26 +01006136
willy tarreau8337c6b2005-12-17 13:41:01 +01006137/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006138 * upon SIGTTIN, let's have a soft stop.
6139 */
6140void sig_listen(int sig) {
6141 listen_proxies();
6142 signal(sig, sig_listen);
6143}
6144
6145/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006146 * this function dumps every server's state when the process receives SIGHUP.
6147 */
6148void sig_dump_state(int sig) {
6149 struct proxy *p = proxy;
6150
6151 Warning("SIGHUP received, dumping servers states.\n");
6152 while (p) {
6153 struct server *s = p->srv;
6154
6155 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6156 while (s) {
6157 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006158 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
6159 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006160 }
6161 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006162 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
6163 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006164 }
6165 s = s->next;
6166 }
willy tarreaudd07e972005-12-18 00:48:48 +01006167
willy tarreau62084d42006-03-24 18:57:41 +01006168 if (p->srv_act == 0) {
6169 if (p->srv_bck) {
6170 Warning("SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6171 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6172 } else {
6173 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6174 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
6175 }
6176 }
willy tarreaudd07e972005-12-18 00:48:48 +01006177
willy tarreau8337c6b2005-12-17 13:41:01 +01006178 p = p->next;
6179 }
6180 signal(sig, sig_dump_state);
6181}
6182
willy tarreau0f7af912005-12-17 12:21:26 +01006183void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006184 struct task *t, *tnext;
6185 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006186
willy tarreau5cbea6f2005-12-17 12:48:26 +01006187 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6188 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6189 tnext = t->next;
6190 s = t->context;
6191 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6192 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6193 "req=%d, rep=%d, clifd=%d\n",
6194 s, tv_remain(&now, &t->expire),
6195 s->cli_state,
6196 s->srv_state,
6197 FD_ISSET(s->cli_fd, StaticReadEvent),
6198 FD_ISSET(s->cli_fd, StaticWriteEvent),
6199 FD_ISSET(s->srv_fd, StaticReadEvent),
6200 FD_ISSET(s->srv_fd, StaticWriteEvent),
6201 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6202 );
willy tarreau0f7af912005-12-17 12:21:26 +01006203 }
willy tarreau12350152005-12-18 01:03:27 +01006204}
6205
willy tarreau64a3cc32005-12-18 01:13:11 +01006206#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006207static void fast_stop(void)
6208{
6209 struct proxy *p;
6210 p = proxy;
6211 while (p) {
6212 p->grace = 0;
6213 p = p->next;
6214 }
6215 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006216}
6217
willy tarreau12350152005-12-18 01:03:27 +01006218void sig_int(int sig) {
6219 /* This would normally be a hard stop,
6220 but we want to be sure about deallocation,
6221 and so on, so we do a soft stop with
6222 0 GRACE time
6223 */
6224 fast_stop();
6225 /* If we are killed twice, we decide to die*/
6226 signal(sig, SIG_DFL);
6227}
6228
6229void sig_term(int sig) {
6230 /* This would normally be a hard stop,
6231 but we want to be sure about deallocation,
6232 and so on, so we do a soft stop with
6233 0 GRACE time
6234 */
6235 fast_stop();
6236 /* If we are killed twice, we decide to die*/
6237 signal(sig, SIG_DFL);
6238}
willy tarreau64a3cc32005-12-18 01:13:11 +01006239#endif
willy tarreau12350152005-12-18 01:03:27 +01006240
willy tarreauc1f47532005-12-18 01:08:26 +01006241/* returns the pointer to an error in the replacement string, or NULL if OK */
6242char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006243 struct hdr_exp *exp;
6244
willy tarreauc1f47532005-12-18 01:08:26 +01006245 if (replace != NULL) {
6246 char *err;
6247 err = check_replace_string(replace);
6248 if (err)
6249 return err;
6250 }
6251
willy tarreaue39cd132005-12-17 13:00:18 +01006252 while (*head != NULL)
6253 head = &(*head)->next;
6254
6255 exp = calloc(1, sizeof(struct hdr_exp));
6256
6257 exp->preg = preg;
6258 exp->replace = replace;
6259 exp->action = action;
6260 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006261
6262 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006263}
6264
willy tarreau9fe663a2005-12-17 13:02:59 +01006265
willy tarreau0f7af912005-12-17 12:21:26 +01006266/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006267 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006268 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006269int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006270
willy tarreau9fe663a2005-12-17 13:02:59 +01006271 if (!strcmp(args[0], "global")) { /* new section */
6272 /* no option, nothing special to do */
6273 return 0;
6274 }
6275 else if (!strcmp(args[0], "daemon")) {
6276 global.mode |= MODE_DAEMON;
6277 }
6278 else if (!strcmp(args[0], "debug")) {
6279 global.mode |= MODE_DEBUG;
6280 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006281 else if (!strcmp(args[0], "noepoll")) {
6282 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6283 }
6284 else if (!strcmp(args[0], "nopoll")) {
6285 cfg_polling_mechanism &= ~POLL_USE_POLL;
6286 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006287 else if (!strcmp(args[0], "quiet")) {
6288 global.mode |= MODE_QUIET;
6289 }
6290 else if (!strcmp(args[0], "stats")) {
6291 global.mode |= MODE_STATS;
6292 }
6293 else if (!strcmp(args[0], "uid")) {
6294 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006295 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006296 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006297 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006298 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006299 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006300 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006301 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006302 global.uid = atol(args[1]);
6303 }
6304 else if (!strcmp(args[0], "gid")) {
6305 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006306 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006307 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006308 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006309 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006310 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006311 return -1;
6312 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006313 global.gid = atol(args[1]);
6314 }
6315 else if (!strcmp(args[0], "nbproc")) {
6316 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006317 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006318 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006319 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006320 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006321 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006322 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006323 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006324 global.nbproc = atol(args[1]);
6325 }
6326 else if (!strcmp(args[0], "maxconn")) {
6327 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006328 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006329 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006330 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006331 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006332 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006333 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006334 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006335 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006336#ifdef SYSTEM_MAXCONN
6337 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6338 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);
6339 global.maxconn = DEFAULT_MAXCONN;
6340 }
6341#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006342 }
willy tarreaub1285d52005-12-18 01:20:14 +01006343 else if (!strcmp(args[0], "ulimit-n")) {
6344 if (global.rlimit_nofile != 0) {
6345 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6346 return 0;
6347 }
6348 if (*(args[1]) == 0) {
6349 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6350 return -1;
6351 }
6352 global.rlimit_nofile = atol(args[1]);
6353 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006354 else if (!strcmp(args[0], "chroot")) {
6355 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006356 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006357 return 0;
6358 }
6359 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006360 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006361 return -1;
6362 }
6363 global.chroot = strdup(args[1]);
6364 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006365 else if (!strcmp(args[0], "pidfile")) {
6366 if (global.pidfile != NULL) {
6367 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6368 return 0;
6369 }
6370 if (*(args[1]) == 0) {
6371 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6372 return -1;
6373 }
6374 global.pidfile = strdup(args[1]);
6375 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006376 else if (!strcmp(args[0], "log")) { /* syslog server address */
6377 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006378 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006379
6380 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006381 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006382 return -1;
6383 }
6384
6385 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6386 if (!strcmp(log_facilities[facility], args[2]))
6387 break;
6388
6389 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006390 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006391 exit(1);
6392 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006393
6394 level = 7; /* max syslog level = debug */
6395 if (*(args[3])) {
6396 while (level >= 0 && strcmp(log_levels[level], args[3]))
6397 level--;
6398 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006399 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006400 exit(1);
6401 }
6402 }
6403
willy tarreau9fe663a2005-12-17 13:02:59 +01006404 sa = str2sa(args[1]);
6405 if (!sa->sin_port)
6406 sa->sin_port = htons(SYSLOG_PORT);
6407
6408 if (global.logfac1 == -1) {
6409 global.logsrv1 = *sa;
6410 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006411 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006412 }
6413 else if (global.logfac2 == -1) {
6414 global.logsrv2 = *sa;
6415 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006416 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006417 }
6418 else {
6419 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6420 return -1;
6421 }
6422
6423 }
6424 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006425 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006426 return -1;
6427 }
6428 return 0;
6429}
6430
6431
willy tarreaua41a8b42005-12-17 14:02:24 +01006432void init_default_instance() {
6433 memset(&defproxy, 0, sizeof(defproxy));
6434 defproxy.mode = PR_MODE_TCP;
6435 defproxy.state = PR_STNEW;
6436 defproxy.maxconn = cfg_maxpconn;
6437 defproxy.conn_retries = CONN_RETRIES;
6438 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6439}
6440
willy tarreau9fe663a2005-12-17 13:02:59 +01006441/*
6442 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6443 */
6444int cfg_parse_listen(char *file, int linenum, char **args) {
6445 static struct proxy *curproxy = NULL;
6446 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006447 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006448 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006449
6450 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006451 if (!*args[1]) {
6452 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6453 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006454 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006455 return -1;
6456 }
6457
6458 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006459 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006460 return -1;
6461 }
6462 curproxy->next = proxy;
6463 proxy = curproxy;
6464 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006465
6466 /* parse the listener address if any */
6467 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006468 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006469 if (!curproxy->listen)
6470 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006471 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006472 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006473
willy tarreau9fe663a2005-12-17 13:02:59 +01006474 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006475 curproxy->state = defproxy.state;
6476 curproxy->maxconn = defproxy.maxconn;
6477 curproxy->conn_retries = defproxy.conn_retries;
6478 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006479
6480 if (defproxy.check_req)
6481 curproxy->check_req = strdup(defproxy.check_req);
6482 curproxy->check_len = defproxy.check_len;
6483
6484 if (defproxy.cookie_name)
6485 curproxy->cookie_name = strdup(defproxy.cookie_name);
6486 curproxy->cookie_len = defproxy.cookie_len;
6487
6488 if (defproxy.capture_name)
6489 curproxy->capture_name = strdup(defproxy.capture_name);
6490 curproxy->capture_namelen = defproxy.capture_namelen;
6491 curproxy->capture_len = defproxy.capture_len;
6492
6493 if (defproxy.errmsg.msg400)
6494 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6495 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6496
6497 if (defproxy.errmsg.msg403)
6498 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6499 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6500
6501 if (defproxy.errmsg.msg408)
6502 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6503 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6504
6505 if (defproxy.errmsg.msg500)
6506 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6507 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6508
6509 if (defproxy.errmsg.msg502)
6510 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6511 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6512
6513 if (defproxy.errmsg.msg503)
6514 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6515 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6516
6517 if (defproxy.errmsg.msg504)
6518 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6519 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6520
willy tarreaua41a8b42005-12-17 14:02:24 +01006521 curproxy->clitimeout = defproxy.clitimeout;
6522 curproxy->contimeout = defproxy.contimeout;
6523 curproxy->srvtimeout = defproxy.srvtimeout;
6524 curproxy->mode = defproxy.mode;
6525 curproxy->logfac1 = defproxy.logfac1;
6526 curproxy->logsrv1 = defproxy.logsrv1;
6527 curproxy->loglev1 = defproxy.loglev1;
6528 curproxy->logfac2 = defproxy.logfac2;
6529 curproxy->logsrv2 = defproxy.logsrv2;
6530 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006531 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006532 curproxy->grace = defproxy.grace;
6533 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006534 curproxy->mon_net = defproxy.mon_net;
6535 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006536 return 0;
6537 }
6538 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006539 /* some variables may have already been initialized earlier */
6540 if (defproxy.check_req) free(defproxy.check_req);
6541 if (defproxy.cookie_name) free(defproxy.cookie_name);
6542 if (defproxy.capture_name) free(defproxy.capture_name);
6543 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6544 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6545 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6546 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6547 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6548 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6549 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6550
6551 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006552 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006553 return 0;
6554 }
6555 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006556 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006557 return -1;
6558 }
6559
willy tarreaua41a8b42005-12-17 14:02:24 +01006560 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6561 if (curproxy == &defproxy) {
6562 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6563 return -1;
6564 }
6565
6566 if (strchr(args[1], ':') == NULL) {
6567 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6568 file, linenum, args[0]);
6569 return -1;
6570 }
6571 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006572 if (!curproxy->listen)
6573 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006574 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006575 return 0;
6576 }
willy tarreaub1285d52005-12-18 01:20:14 +01006577 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6578 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6579 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6580 file, linenum, args[0]);
6581 return -1;
6582 }
6583 /* flush useless bits */
6584 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6585 return 0;
6586 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006587 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006588 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6589 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6590 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6591 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006592 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006593 return -1;
6594 }
6595 }
6596 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006597 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006598 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006599 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6600 curproxy->state = PR_STNEW;
6601 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006602 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6603 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006604// if (curproxy == &defproxy) {
6605// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6606// return -1;
6607// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006608
willy tarreau9fe663a2005-12-17 13:02:59 +01006609 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006610// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6611// file, linenum);
6612// return 0;
6613 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006614 }
6615
6616 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006617 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6618 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006619 return -1;
6620 }
6621 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006622 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006623
6624 cur_arg = 2;
6625 while (*(args[cur_arg])) {
6626 if (!strcmp(args[cur_arg], "rewrite")) {
6627 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006628 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 else if (!strcmp(args[cur_arg], "indirect")) {
6630 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006631 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006632 else if (!strcmp(args[cur_arg], "insert")) {
6633 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006634 }
willy tarreau240afa62005-12-17 13:14:35 +01006635 else if (!strcmp(args[cur_arg], "nocache")) {
6636 curproxy->options |= PR_O_COOK_NOC;
6637 }
willy tarreaucd878942005-12-17 13:27:43 +01006638 else if (!strcmp(args[cur_arg], "postonly")) {
6639 curproxy->options |= PR_O_COOK_POST;
6640 }
willy tarreau0174f312005-12-18 01:02:42 +01006641 else if (!strcmp(args[cur_arg], "prefix")) {
6642 curproxy->options |= PR_O_COOK_PFX;
6643 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006644 else {
willy tarreau0174f312005-12-18 01:02:42 +01006645 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006646 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006647 return -1;
6648 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006649 cur_arg++;
6650 }
willy tarreau0174f312005-12-18 01:02:42 +01006651 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6652 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6653 file, linenum);
6654 return -1;
6655 }
6656
6657 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6658 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006659 file, linenum);
6660 return -1;
6661 }
willy tarreau12350152005-12-18 01:03:27 +01006662 }/* end else if (!strcmp(args[0], "cookie")) */
6663 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6664// if (curproxy == &defproxy) {
6665// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6666// return -1;
6667// }
6668
6669 if (curproxy->appsession_name != NULL) {
6670// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6671// file, linenum);
6672// return 0;
6673 free(curproxy->appsession_name);
6674 }
6675
6676 if (*(args[5]) == 0) {
6677 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6678 file, linenum, args[0]);
6679 return -1;
6680 }
6681 have_appsession = 1;
6682 curproxy->appsession_name = strdup(args[1]);
6683 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6684 curproxy->appsession_len = atoi(args[3]);
6685 curproxy->appsession_timeout = atoi(args[5]);
6686 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6687 if (rc) {
6688 Alert("Error Init Appsession Hashtable.\n");
6689 return -1;
6690 }
6691 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006692 else if (!strcmp(args[0], "capture")) {
6693 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6694 // if (curproxy == &defproxy) {
6695 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6696 // return -1;
6697 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006698
willy tarreau4302f492005-12-18 01:00:37 +01006699 if (curproxy->capture_name != NULL) {
6700 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6701 // file, linenum, args[0]);
6702 // return 0;
6703 free(curproxy->capture_name);
6704 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006705
willy tarreau4302f492005-12-18 01:00:37 +01006706 if (*(args[4]) == 0) {
6707 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6708 file, linenum, args[0]);
6709 return -1;
6710 }
6711 curproxy->capture_name = strdup(args[2]);
6712 curproxy->capture_namelen = strlen(curproxy->capture_name);
6713 curproxy->capture_len = atol(args[4]);
6714 if (curproxy->capture_len >= CAPTURE_LEN) {
6715 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6716 file, linenum, CAPTURE_LEN - 1);
6717 curproxy->capture_len = CAPTURE_LEN - 1;
6718 }
6719 curproxy->to_log |= LW_COOKIE;
6720 }
6721 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6722 struct cap_hdr *hdr;
6723
6724 if (curproxy == &defproxy) {
6725 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6726 return -1;
6727 }
6728
6729 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6730 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6731 file, linenum, args[0], args[1]);
6732 return -1;
6733 }
6734
6735 hdr = calloc(sizeof(struct cap_hdr), 1);
6736 hdr->next = curproxy->req_cap;
6737 hdr->name = strdup(args[3]);
6738 hdr->namelen = strlen(args[3]);
6739 hdr->len = atol(args[5]);
6740 hdr->index = curproxy->nb_req_cap++;
6741 curproxy->req_cap = hdr;
6742 curproxy->to_log |= LW_REQHDR;
6743 }
6744 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6745 struct cap_hdr *hdr;
6746
6747 if (curproxy == &defproxy) {
6748 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6749 return -1;
6750 }
6751
6752 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6753 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6754 file, linenum, args[0], args[1]);
6755 return -1;
6756 }
6757 hdr = calloc(sizeof(struct cap_hdr), 1);
6758 hdr->next = curproxy->rsp_cap;
6759 hdr->name = strdup(args[3]);
6760 hdr->namelen = strlen(args[3]);
6761 hdr->len = atol(args[5]);
6762 hdr->index = curproxy->nb_rsp_cap++;
6763 curproxy->rsp_cap = hdr;
6764 curproxy->to_log |= LW_RSPHDR;
6765 }
6766 else {
6767 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006768 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006769 return -1;
6770 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006771 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006772 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006773 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006774 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006775 return 0;
6776 }
6777 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006778 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6779 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006780 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006781 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006782 curproxy->contimeout = atol(args[1]);
6783 }
6784 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006785 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006786 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6787 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006788 return 0;
6789 }
6790 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006791 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6792 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006793 return -1;
6794 }
6795 curproxy->clitimeout = atol(args[1]);
6796 }
6797 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006798 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006799 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006800 return 0;
6801 }
6802 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006803 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6804 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006805 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006806 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006807 curproxy->srvtimeout = atol(args[1]);
6808 }
6809 else if (!strcmp(args[0], "retries")) { /* connection retries */
6810 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006811 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6812 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006813 return -1;
6814 }
6815 curproxy->conn_retries = atol(args[1]);
6816 }
6817 else if (!strcmp(args[0], "option")) {
6818 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006819 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006820 return -1;
6821 }
6822 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006823 /* enable reconnections to dispatch */
6824 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006825#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006826 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006827 /* enable transparent proxy connections */
6828 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006829#endif
6830 else if (!strcmp(args[1], "keepalive"))
6831 /* enable keep-alive */
6832 curproxy->options |= PR_O_KEEPALIVE;
6833 else if (!strcmp(args[1], "forwardfor"))
6834 /* insert x-forwarded-for field */
6835 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006836 else if (!strcmp(args[1], "logasap"))
6837 /* log as soon as possible, without waiting for the session to complete */
6838 curproxy->options |= PR_O_LOGASAP;
6839 else if (!strcmp(args[1], "httpclose"))
6840 /* force connection: close in both directions in HTTP mode */
6841 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006842 else if (!strcmp(args[1], "forceclose"))
6843 /* force connection: close in both directions in HTTP mode and enforce end of session */
6844 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006845 else if (!strcmp(args[1], "checkcache"))
6846 /* require examination of cacheability of the 'set-cookie' field */
6847 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006848 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006849 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006850 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006851 else if (!strcmp(args[1], "tcplog"))
6852 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006853 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006854 else if (!strcmp(args[1], "dontlognull")) {
6855 /* don't log empty requests */
6856 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006857 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006858 else if (!strcmp(args[1], "tcpka")) {
6859 /* enable TCP keep-alives on client and server sessions */
6860 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6861 }
6862 else if (!strcmp(args[1], "clitcpka")) {
6863 /* enable TCP keep-alives on client sessions */
6864 curproxy->options |= PR_O_TCP_CLI_KA;
6865 }
6866 else if (!strcmp(args[1], "srvtcpka")) {
6867 /* enable TCP keep-alives on server sessions */
6868 curproxy->options |= PR_O_TCP_SRV_KA;
6869 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006870 else if (!strcmp(args[1], "allbackups")) {
6871 /* Use all backup servers simultaneously */
6872 curproxy->options |= PR_O_USE_ALL_BK;
6873 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006874 else if (!strcmp(args[1], "httpchk")) {
6875 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006876 if (curproxy->check_req != NULL) {
6877 free(curproxy->check_req);
6878 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006879 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006880 if (!*args[2]) { /* no argument */
6881 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6882 curproxy->check_len = strlen(DEF_CHECK_REQ);
6883 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006884 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6885 curproxy->check_req = (char *)malloc(reqlen);
6886 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6887 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006888 } else { /* more arguments : METHOD URI [HTTP_VER] */
6889 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6890 if (*args[4])
6891 reqlen += strlen(args[4]);
6892 else
6893 reqlen += strlen("HTTP/1.0");
6894
6895 curproxy->check_req = (char *)malloc(reqlen);
6896 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6897 "%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 +01006898 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006899 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006900 else if (!strcmp(args[1], "persist")) {
6901 /* persist on using the server specified by the cookie, even when it's down */
6902 curproxy->options |= PR_O_PERSIST;
6903 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006904 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006905 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006906 return -1;
6907 }
6908 return 0;
6909 }
6910 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6911 /* enable reconnections to dispatch */
6912 curproxy->options |= PR_O_REDISP;
6913 }
willy tarreaua1598082005-12-17 13:08:06 +01006914#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006915 else if (!strcmp(args[0], "transparent")) {
6916 /* enable transparent proxy connections */
6917 curproxy->options |= PR_O_TRANSP;
6918 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006919#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006920 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6921 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006922 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006923 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006924 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006925 curproxy->maxconn = atol(args[1]);
6926 }
6927 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6928 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006929 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006930 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006931 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006932 curproxy->grace = atol(args[1]);
6933 }
6934 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006935 if (curproxy == &defproxy) {
6936 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6937 return -1;
6938 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006939 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006940 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006941 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006942 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006943 curproxy->dispatch_addr = *str2sa(args[1]);
6944 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006945 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006946 if (*(args[1])) {
6947 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006948 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006949 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006950 else if (!strcmp(args[1], "source")) {
6951 curproxy->options |= PR_O_BALANCE_SH;
6952 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006953 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01006954 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006955 return -1;
6956 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006957 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006958 else /* if no option is set, use round-robin by default */
6959 curproxy->options |= PR_O_BALANCE_RR;
6960 }
6961 else if (!strcmp(args[0], "server")) { /* server address */
6962 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006963 char *rport;
6964 char *raddr;
6965 short realport;
6966 int do_check;
6967
6968 if (curproxy == &defproxy) {
6969 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6970 return -1;
6971 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006972
willy tarreaua41a8b42005-12-17 14:02:24 +01006973 if (!*args[2]) {
6974 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006975 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006976 return -1;
6977 }
6978 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6979 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6980 return -1;
6981 }
willy tarreau0174f312005-12-18 01:02:42 +01006982
6983 if (curproxy->srv == NULL)
6984 curproxy->srv = newsrv;
6985 else
6986 curproxy->cursrv->next = newsrv;
6987 curproxy->cursrv = newsrv;
6988
6989 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006990 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006991
6992 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006993 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006994 newsrv->id = strdup(args[1]);
6995
6996 /* several ways to check the port component :
6997 * - IP => port=+0, relative
6998 * - IP: => port=+0, relative
6999 * - IP:N => port=N, absolute
7000 * - IP:+N => port=+N, relative
7001 * - IP:-N => port=-N, relative
7002 */
7003 raddr = strdup(args[2]);
7004 rport = strchr(raddr, ':');
7005 if (rport) {
7006 *rport++ = 0;
7007 realport = atol(rport);
7008 if (!isdigit((int)*rport))
7009 newsrv->state |= SRV_MAPPORTS;
7010 } else {
7011 realport = 0;
7012 newsrv->state |= SRV_MAPPORTS;
7013 }
7014
7015 newsrv->addr = *str2sa(raddr);
7016 newsrv->addr.sin_port = htons(realport);
7017 free(raddr);
7018
willy tarreau9fe663a2005-12-17 13:02:59 +01007019 newsrv->curfd = -1; /* no health-check in progress */
7020 newsrv->inter = DEF_CHKINTR;
7021 newsrv->rise = DEF_RISETIME;
7022 newsrv->fall = DEF_FALLTIME;
7023 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7024 cur_arg = 3;
7025 while (*args[cur_arg]) {
7026 if (!strcmp(args[cur_arg], "cookie")) {
7027 newsrv->cookie = strdup(args[cur_arg + 1]);
7028 newsrv->cklen = strlen(args[cur_arg + 1]);
7029 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007030 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007031 else if (!strcmp(args[cur_arg], "rise")) {
7032 newsrv->rise = atol(args[cur_arg + 1]);
7033 newsrv->health = newsrv->rise;
7034 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007035 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007036 else if (!strcmp(args[cur_arg], "fall")) {
7037 newsrv->fall = atol(args[cur_arg + 1]);
7038 cur_arg += 2;
7039 }
7040 else if (!strcmp(args[cur_arg], "inter")) {
7041 newsrv->inter = atol(args[cur_arg + 1]);
7042 cur_arg += 2;
7043 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007044 else if (!strcmp(args[cur_arg], "port")) {
7045 newsrv->check_port = atol(args[cur_arg + 1]);
7046 cur_arg += 2;
7047 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007048 else if (!strcmp(args[cur_arg], "backup")) {
7049 newsrv->state |= SRV_BACKUP;
7050 cur_arg ++;
7051 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007052 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007053 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007054 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007055 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007056 }
willy tarreau0174f312005-12-18 01:02:42 +01007057 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7058 if (!*args[cur_arg + 1]) {
7059 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7060 file, linenum, "source");
7061 return -1;
7062 }
7063 newsrv->state |= SRV_BIND_SRC;
7064 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7065 cur_arg += 2;
7066 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007067 else {
willy tarreau0174f312005-12-18 01:02:42 +01007068 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 +01007069 file, linenum, newsrv->id);
7070 return -1;
7071 }
7072 }
7073
7074 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007075 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7076 newsrv->check_port = realport; /* by default */
7077 if (!newsrv->check_port) {
7078 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 +01007079 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007080 return -1;
7081 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007082 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007083 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007084
willy tarreau62084d42006-03-24 18:57:41 +01007085 if (newsrv->state & SRV_BACKUP)
7086 curproxy->srv_bck++;
7087 else
7088 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007089 }
7090 else if (!strcmp(args[0], "log")) { /* syslog server address */
7091 struct sockaddr_in *sa;
7092 int facility;
7093
7094 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7095 curproxy->logfac1 = global.logfac1;
7096 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007097 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007098 curproxy->logfac2 = global.logfac2;
7099 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007100 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007101 }
7102 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007103 int level;
7104
willy tarreau0f7af912005-12-17 12:21:26 +01007105 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7106 if (!strcmp(log_facilities[facility], args[2]))
7107 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007108
willy tarreau0f7af912005-12-17 12:21:26 +01007109 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007110 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007111 exit(1);
7112 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007113
willy tarreau8337c6b2005-12-17 13:41:01 +01007114 level = 7; /* max syslog level = debug */
7115 if (*(args[3])) {
7116 while (level >= 0 && strcmp(log_levels[level], args[3]))
7117 level--;
7118 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007119 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007120 exit(1);
7121 }
7122 }
7123
willy tarreau0f7af912005-12-17 12:21:26 +01007124 sa = str2sa(args[1]);
7125 if (!sa->sin_port)
7126 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007127
willy tarreau0f7af912005-12-17 12:21:26 +01007128 if (curproxy->logfac1 == -1) {
7129 curproxy->logsrv1 = *sa;
7130 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007131 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007132 }
7133 else if (curproxy->logfac2 == -1) {
7134 curproxy->logsrv2 = *sa;
7135 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007136 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007137 }
7138 else {
7139 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007140 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007141 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007142 }
7143 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007144 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007145 file, linenum);
7146 return -1;
7147 }
7148 }
willy tarreaua1598082005-12-17 13:08:06 +01007149 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007150 if (!*args[1]) {
7151 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007152 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007153 return -1;
7154 }
7155
7156 curproxy->source_addr = *str2sa(args[1]);
7157 curproxy->options |= PR_O_BIND_SRC;
7158 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007159 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7160 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007161 if (curproxy == &defproxy) {
7162 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7163 return -1;
7164 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007165
7166 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007167 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7168 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007169 return -1;
7170 }
7171
7172 preg = calloc(1, sizeof(regex_t));
7173 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007174 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007175 return -1;
7176 }
7177
willy tarreauc1f47532005-12-18 01:08:26 +01007178 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7179 if (err) {
7180 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7181 file, linenum, *err);
7182 return -1;
7183 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007184 }
7185 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7186 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007187 if (curproxy == &defproxy) {
7188 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7189 return -1;
7190 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007191
7192 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007193 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007194 return -1;
7195 }
7196
7197 preg = calloc(1, sizeof(regex_t));
7198 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007199 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007200 return -1;
7201 }
7202
7203 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7204 }
7205 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7206 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007207 if (curproxy == &defproxy) {
7208 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7209 return -1;
7210 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007211
7212 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007213 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007214 return -1;
7215 }
7216
7217 preg = calloc(1, sizeof(regex_t));
7218 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007219 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007220 return -1;
7221 }
7222
7223 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7224 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007225 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7226 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007227 if (curproxy == &defproxy) {
7228 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7229 return -1;
7230 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007231
7232 if (*(args[1]) == 0) {
7233 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7234 return -1;
7235 }
7236
7237 preg = calloc(1, sizeof(regex_t));
7238 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7239 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7240 return -1;
7241 }
7242
7243 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7244 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007245 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7246 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007247 if (curproxy == &defproxy) {
7248 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7249 return -1;
7250 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007251
7252 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007253 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007254 return -1;
7255 }
7256
7257 preg = calloc(1, sizeof(regex_t));
7258 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007259 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007260 return -1;
7261 }
7262
7263 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7264 }
7265 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7266 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007267 if (curproxy == &defproxy) {
7268 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7269 return -1;
7270 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007271
7272 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007273 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7274 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007275 return -1;
7276 }
7277
7278 preg = calloc(1, sizeof(regex_t));
7279 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007280 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007281 return -1;
7282 }
7283
willy tarreauc1f47532005-12-18 01:08:26 +01007284 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7285 if (err) {
7286 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7287 file, linenum, *err);
7288 return -1;
7289 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007290 }
7291 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7292 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007293 if (curproxy == &defproxy) {
7294 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7295 return -1;
7296 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007297
7298 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007299 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007300 return -1;
7301 }
7302
7303 preg = calloc(1, sizeof(regex_t));
7304 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007305 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007306 return -1;
7307 }
7308
7309 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7310 }
7311 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7312 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007313 if (curproxy == &defproxy) {
7314 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7315 return -1;
7316 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007317
7318 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007319 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007320 return -1;
7321 }
7322
7323 preg = calloc(1, sizeof(regex_t));
7324 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007325 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007326 return -1;
7327 }
7328
7329 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7330 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007331 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7332 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007333 if (curproxy == &defproxy) {
7334 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7335 return -1;
7336 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007337
7338 if (*(args[1]) == 0) {
7339 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7340 return -1;
7341 }
7342
7343 preg = calloc(1, sizeof(regex_t));
7344 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7345 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7346 return -1;
7347 }
7348
7349 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7350 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007351 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7352 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007353 if (curproxy == &defproxy) {
7354 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7355 return -1;
7356 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007357
7358 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007359 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007360 return -1;
7361 }
7362
7363 preg = calloc(1, sizeof(regex_t));
7364 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007365 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 return -1;
7367 }
7368
7369 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7370 }
7371 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007372 if (curproxy == &defproxy) {
7373 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7374 return -1;
7375 }
7376
willy tarreau9fe663a2005-12-17 13:02:59 +01007377 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007378 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007379 return 0;
7380 }
7381
7382 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007383 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007384 return -1;
7385 }
7386
willy tarreau4302f492005-12-18 01:00:37 +01007387 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7388 }
7389 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7390 regex_t *preg;
7391
7392 if (*(args[1]) == 0 || *(args[2]) == 0) {
7393 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7394 file, linenum, args[0]);
7395 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007396 }
willy tarreau4302f492005-12-18 01:00:37 +01007397
7398 preg = calloc(1, sizeof(regex_t));
7399 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7400 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7401 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007402 }
willy tarreau4302f492005-12-18 01:00:37 +01007403
willy tarreauc1f47532005-12-18 01:08:26 +01007404 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7405 if (err) {
7406 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7407 file, linenum, *err);
7408 return -1;
7409 }
willy tarreau4302f492005-12-18 01:00:37 +01007410 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007411 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7412 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007413 if (curproxy == &defproxy) {
7414 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7415 return -1;
7416 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007417
7418 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007419 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007420 return -1;
7421 }
willy tarreaue39cd132005-12-17 13:00:18 +01007422
willy tarreau9fe663a2005-12-17 13:02:59 +01007423 preg = calloc(1, sizeof(regex_t));
7424 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007425 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007426 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007427 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007428
willy tarreauc1f47532005-12-18 01:08:26 +01007429 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7430 if (err) {
7431 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7432 file, linenum, *err);
7433 return -1;
7434 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007435 }
willy tarreau982249e2005-12-18 00:57:06 +01007436 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7437 regex_t *preg;
7438 if (curproxy == &defproxy) {
7439 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7440 return -1;
7441 }
7442
7443 if (*(args[1]) == 0) {
7444 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7445 return -1;
7446 }
7447
7448 preg = calloc(1, sizeof(regex_t));
7449 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7450 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7451 return -1;
7452 }
7453
willy tarreauc1f47532005-12-18 01:08:26 +01007454 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7455 if (err) {
7456 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7457 file, linenum, *err);
7458 return -1;
7459 }
willy tarreau982249e2005-12-18 00:57:06 +01007460 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007461 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007462 regex_t *preg;
7463 if (curproxy == &defproxy) {
7464 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7465 return -1;
7466 }
willy tarreaue39cd132005-12-17 13:00:18 +01007467
willy tarreaua41a8b42005-12-17 14:02:24 +01007468 if (*(args[1]) == 0 || *(args[2]) == 0) {
7469 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7470 file, linenum, args[0]);
7471 return -1;
7472 }
willy tarreaue39cd132005-12-17 13:00:18 +01007473
willy tarreaua41a8b42005-12-17 14:02:24 +01007474 preg = calloc(1, sizeof(regex_t));
7475 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7476 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7477 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007478 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007479
willy tarreauc1f47532005-12-18 01:08:26 +01007480 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7481 if (err) {
7482 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7483 file, linenum, *err);
7484 return -1;
7485 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007486 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007487 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7488 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007489 if (curproxy == &defproxy) {
7490 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7491 return -1;
7492 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007493
7494 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007495 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007496 return -1;
7497 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007498
willy tarreau9fe663a2005-12-17 13:02:59 +01007499 preg = calloc(1, sizeof(regex_t));
7500 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007501 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007502 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007503 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007504
willy tarreauc1f47532005-12-18 01:08:26 +01007505 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7506 if (err) {
7507 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7508 file, linenum, *err);
7509 return -1;
7510 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007511 }
willy tarreau982249e2005-12-18 00:57:06 +01007512 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7513 regex_t *preg;
7514 if (curproxy == &defproxy) {
7515 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7516 return -1;
7517 }
7518
7519 if (*(args[1]) == 0) {
7520 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7521 return -1;
7522 }
7523
7524 preg = calloc(1, sizeof(regex_t));
7525 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7526 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7527 return -1;
7528 }
7529
willy tarreauc1f47532005-12-18 01:08:26 +01007530 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7531 if (err) {
7532 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7533 file, linenum, *err);
7534 return -1;
7535 }
willy tarreau982249e2005-12-18 00:57:06 +01007536 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007537 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007538 if (curproxy == &defproxy) {
7539 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7540 return -1;
7541 }
7542
willy tarreau9fe663a2005-12-17 13:02:59 +01007543 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007544 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007545 return 0;
7546 }
7547
7548 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007549 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007550 return -1;
7551 }
7552
7553 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7554 }
willy tarreauc1f47532005-12-18 01:08:26 +01007555 else if (!strcmp(args[0], "errorloc") ||
7556 !strcmp(args[0], "errorloc302") ||
7557 !strcmp(args[0], "errorloc303")) { /* error location */
7558 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007559 char *err;
7560
willy tarreaueedaa9f2005-12-17 14:08:03 +01007561 // if (curproxy == &defproxy) {
7562 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7563 // return -1;
7564 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007565
willy tarreau8337c6b2005-12-17 13:41:01 +01007566 if (*(args[2]) == 0) {
7567 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7568 return -1;
7569 }
7570
7571 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007572 if (!strcmp(args[0], "errorloc303")) {
7573 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7574 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7575 } else {
7576 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7577 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7578 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007579
7580 if (errnum == 400) {
7581 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007582 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007583 free(curproxy->errmsg.msg400);
7584 }
7585 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007586 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007587 }
7588 else if (errnum == 403) {
7589 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007590 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007591 free(curproxy->errmsg.msg403);
7592 }
7593 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007594 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007595 }
7596 else if (errnum == 408) {
7597 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007598 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007599 free(curproxy->errmsg.msg408);
7600 }
7601 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007602 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007603 }
7604 else if (errnum == 500) {
7605 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007606 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007607 free(curproxy->errmsg.msg500);
7608 }
7609 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007610 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007611 }
7612 else if (errnum == 502) {
7613 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007614 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007615 free(curproxy->errmsg.msg502);
7616 }
7617 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007618 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007619 }
7620 else if (errnum == 503) {
7621 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007622 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007623 free(curproxy->errmsg.msg503);
7624 }
7625 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007626 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007627 }
7628 else if (errnum == 504) {
7629 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007630 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007631 free(curproxy->errmsg.msg504);
7632 }
7633 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007634 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007635 }
7636 else {
7637 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7638 free(err);
7639 }
7640 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007641 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007642 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007643 return -1;
7644 }
7645 return 0;
7646}
willy tarreaue39cd132005-12-17 13:00:18 +01007647
willy tarreau5cbea6f2005-12-17 12:48:26 +01007648
willy tarreau9fe663a2005-12-17 13:02:59 +01007649/*
7650 * This function reads and parses the configuration file given in the argument.
7651 * returns 0 if OK, -1 if error.
7652 */
7653int readcfgfile(char *file) {
7654 char thisline[256];
7655 char *line;
7656 FILE *f;
7657 int linenum = 0;
7658 char *end;
7659 char *args[MAX_LINE_ARGS];
7660 int arg;
7661 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007662 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007663 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007664
willy tarreau9fe663a2005-12-17 13:02:59 +01007665 struct proxy *curproxy = NULL;
7666 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007667
willy tarreau9fe663a2005-12-17 13:02:59 +01007668 if ((f=fopen(file,"r")) == NULL)
7669 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007670
willy tarreaueedaa9f2005-12-17 14:08:03 +01007671 init_default_instance();
7672
willy tarreau9fe663a2005-12-17 13:02:59 +01007673 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7674 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007675
willy tarreau9fe663a2005-12-17 13:02:59 +01007676 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007677
willy tarreau9fe663a2005-12-17 13:02:59 +01007678 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007679 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007680 line++;
7681
7682 arg = 0;
7683 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007684
willy tarreau9fe663a2005-12-17 13:02:59 +01007685 while (*line && arg < MAX_LINE_ARGS) {
7686 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7687 * C equivalent value. Other combinations left unchanged (eg: \1).
7688 */
7689 if (*line == '\\') {
7690 int skip = 0;
7691 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7692 *line = line[1];
7693 skip = 1;
7694 }
7695 else if (line[1] == 'r') {
7696 *line = '\r';
7697 skip = 1;
7698 }
7699 else if (line[1] == 'n') {
7700 *line = '\n';
7701 skip = 1;
7702 }
7703 else if (line[1] == 't') {
7704 *line = '\t';
7705 skip = 1;
7706 }
willy tarreauc1f47532005-12-18 01:08:26 +01007707 else if (line[1] == 'x') {
7708 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7709 unsigned char hex1, hex2;
7710 hex1 = toupper(line[2]) - '0';
7711 hex2 = toupper(line[3]) - '0';
7712 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7713 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7714 *line = (hex1<<4) + hex2;
7715 skip = 3;
7716 }
7717 else {
7718 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7719 return -1;
7720 }
7721 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007722 if (skip) {
7723 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7724 end -= skip;
7725 }
7726 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007727 }
willy tarreaua1598082005-12-17 13:08:06 +01007728 else if (*line == '#' || *line == '\n' || *line == '\r') {
7729 /* end of string, end of loop */
7730 *line = 0;
7731 break;
7732 }
willy tarreauc29948c2005-12-17 13:10:27 +01007733 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007734 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007735 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007736 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007737 line++;
7738 args[++arg] = line;
7739 }
7740 else {
7741 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007742 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007743 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007744
willy tarreau9fe663a2005-12-17 13:02:59 +01007745 /* empty line */
7746 if (!**args)
7747 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007748
willy tarreau9fe663a2005-12-17 13:02:59 +01007749 /* zero out remaining args */
7750 while (++arg < MAX_LINE_ARGS) {
7751 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007752 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007753
willy tarreaua41a8b42005-12-17 14:02:24 +01007754 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007755 confsect = CFG_LISTEN;
7756 else if (!strcmp(args[0], "global")) /* global config */
7757 confsect = CFG_GLOBAL;
7758 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007759
willy tarreau9fe663a2005-12-17 13:02:59 +01007760 switch (confsect) {
7761 case CFG_LISTEN:
7762 if (cfg_parse_listen(file, linenum, args) < 0)
7763 return -1;
7764 break;
7765 case CFG_GLOBAL:
7766 if (cfg_parse_global(file, linenum, args) < 0)
7767 return -1;
7768 break;
7769 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007770 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007771 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007772 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007773
7774
willy tarreau0f7af912005-12-17 12:21:26 +01007775 }
7776 fclose(f);
7777
7778 /*
7779 * Now, check for the integrity of all that we have collected.
7780 */
7781
Willy TARREAU3759f982006-03-01 22:44:17 +01007782 /* will be needed further to delay some tasks */
7783 tv_now(&now);
7784
willy tarreau0f7af912005-12-17 12:21:26 +01007785 if ((curproxy = proxy) == NULL) {
7786 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7787 file);
7788 return -1;
7789 }
7790
7791 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007792 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007793 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007794 curproxy = curproxy->next;
7795 continue;
7796 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007797
7798 if (curproxy->listen == NULL) {
7799 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);
7800 cfgerr++;
7801 }
7802 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007803 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007804 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007805 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7806 file, curproxy->id);
7807 cfgerr++;
7808 }
7809 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7810 if (curproxy->options & PR_O_TRANSP) {
7811 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7812 file, curproxy->id);
7813 cfgerr++;
7814 }
7815 else if (curproxy->srv == NULL) {
7816 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7817 file, curproxy->id);
7818 cfgerr++;
7819 }
willy tarreaua1598082005-12-17 13:08:06 +01007820 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007821 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7822 file, curproxy->id);
7823 }
7824 }
7825 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007826 if (curproxy->cookie_name != NULL) {
7827 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7828 file, curproxy->id);
7829 }
7830 if ((newsrv = curproxy->srv) != NULL) {
7831 Warning("parsing %s : servers will be ignored for listener %s.\n",
7832 file, curproxy->id);
7833 }
willy tarreaue39cd132005-12-17 13:00:18 +01007834 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007835 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7836 file, curproxy->id);
7837 }
willy tarreaue39cd132005-12-17 13:00:18 +01007838 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007839 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7840 file, curproxy->id);
7841 }
7842 }
7843 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7844 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7845 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7846 file, curproxy->id);
7847 cfgerr++;
7848 }
7849 else {
7850 while (newsrv != NULL) {
7851 /* nothing to check for now */
7852 newsrv = newsrv->next;
7853 }
7854 }
7855 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007856
7857 if (curproxy->options & PR_O_LOGASAP)
7858 curproxy->to_log &= ~LW_BYTES;
7859
willy tarreau8337c6b2005-12-17 13:41:01 +01007860 if (curproxy->errmsg.msg400 == NULL) {
7861 curproxy->errmsg.msg400 = (char *)HTTP_400;
7862 curproxy->errmsg.len400 = strlen(HTTP_400);
7863 }
7864 if (curproxy->errmsg.msg403 == NULL) {
7865 curproxy->errmsg.msg403 = (char *)HTTP_403;
7866 curproxy->errmsg.len403 = strlen(HTTP_403);
7867 }
7868 if (curproxy->errmsg.msg408 == NULL) {
7869 curproxy->errmsg.msg408 = (char *)HTTP_408;
7870 curproxy->errmsg.len408 = strlen(HTTP_408);
7871 }
7872 if (curproxy->errmsg.msg500 == NULL) {
7873 curproxy->errmsg.msg500 = (char *)HTTP_500;
7874 curproxy->errmsg.len500 = strlen(HTTP_500);
7875 }
7876 if (curproxy->errmsg.msg502 == NULL) {
7877 curproxy->errmsg.msg502 = (char *)HTTP_502;
7878 curproxy->errmsg.len502 = strlen(HTTP_502);
7879 }
7880 if (curproxy->errmsg.msg503 == NULL) {
7881 curproxy->errmsg.msg503 = (char *)HTTP_503;
7882 curproxy->errmsg.len503 = strlen(HTTP_503);
7883 }
7884 if (curproxy->errmsg.msg504 == NULL) {
7885 curproxy->errmsg.msg504 = (char *)HTTP_504;
7886 curproxy->errmsg.len504 = strlen(HTTP_504);
7887 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007888
7889 /* now we'll start this proxy's health checks if any */
7890 /* 1- count the checkers to run simultaneously */
7891 nbchk = 0;
7892 mininter = 0;
7893 newsrv = curproxy->srv;
7894 while (newsrv != NULL) {
7895 if (newsrv->state & SRV_CHECKED) {
7896 if (!mininter || mininter > newsrv->inter)
7897 mininter = newsrv->inter;
7898 nbchk++;
7899 }
7900 newsrv = newsrv->next;
7901 }
7902
7903 /* 2- start them as far as possible from each others while respecting
7904 * their own intervals. For this, we will start them after their own
7905 * interval added to the min interval divided by the number of servers,
7906 * weighted by the server's position in the list.
7907 */
7908 if (nbchk > 0) {
7909 struct task *t;
7910 int srvpos;
7911
7912 newsrv = curproxy->srv;
7913 srvpos = 0;
7914 while (newsrv != NULL) {
7915 /* should this server be checked ? */
7916 if (newsrv->state & SRV_CHECKED) {
7917 if ((t = pool_alloc(task)) == NULL) {
7918 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7919 return -1;
7920 }
7921
7922 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7923 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7924 t->state = TASK_IDLE;
7925 t->process = process_chk;
7926 t->context = newsrv;
7927
7928 /* check this every ms */
7929 tv_delayfrom(&t->expire, &now,
7930 newsrv->inter + mininter * srvpos / nbchk);
7931 task_queue(t);
7932 //task_wakeup(&rq, t);
7933 srvpos++;
7934 }
7935 newsrv = newsrv->next;
7936 }
7937 }
7938
willy tarreau0f7af912005-12-17 12:21:26 +01007939 curproxy = curproxy->next;
7940 }
7941 if (cfgerr > 0) {
7942 Alert("Errors found in configuration file, aborting.\n");
7943 return -1;
7944 }
7945 else
7946 return 0;
7947}
7948
7949
7950/*
7951 * This function initializes all the necessary variables. It only returns
7952 * if everything is OK. If something fails, it exits.
7953 */
7954void init(int argc, char **argv) {
7955 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007956 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007957 char *old_argv = *argv;
7958 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007959 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007960
7961 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007962 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007963 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007964 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007965 exit(1);
7966 }
7967
willy tarreau746e26b2006-03-25 11:14:35 +01007968#ifdef HAPROXY_MEMMAX
7969 global.rlimit_memmax = HAPROXY_MEMMAX;
7970#endif
7971
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007972 /* initialize the libc's localtime structures once for all so that we
7973 * won't be missing memory if we want to send alerts under OOM conditions.
7974 */
7975 tv_now(&now);
7976 localtime(&now.tv_sec);
7977
willy tarreau4302f492005-12-18 01:00:37 +01007978 /* initialize the log header encoding map : '{|}"#' should be encoded with
7979 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7980 * URL encoding only requires '"', '#' to be encoded as well as non-
7981 * printable characters above.
7982 */
7983 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7984 memset(url_encode_map, 0, sizeof(url_encode_map));
7985 for (i = 0; i < 32; i++) {
7986 FD_SET(i, hdr_encode_map);
7987 FD_SET(i, url_encode_map);
7988 }
7989 for (i = 127; i < 256; i++) {
7990 FD_SET(i, hdr_encode_map);
7991 FD_SET(i, url_encode_map);
7992 }
7993
7994 tmp = "\"#{|}";
7995 while (*tmp) {
7996 FD_SET(*tmp, hdr_encode_map);
7997 tmp++;
7998 }
7999
8000 tmp = "\"#";
8001 while (*tmp) {
8002 FD_SET(*tmp, url_encode_map);
8003 tmp++;
8004 }
8005
willy tarreau64a3cc32005-12-18 01:13:11 +01008006 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8007#if defined(ENABLE_POLL)
8008 cfg_polling_mechanism |= POLL_USE_POLL;
8009#endif
8010#if defined(ENABLE_EPOLL)
8011 cfg_polling_mechanism |= POLL_USE_EPOLL;
8012#endif
8013
willy tarreau0f7af912005-12-17 12:21:26 +01008014 pid = getpid();
8015 progname = *argv;
8016 while ((tmp = strchr(progname, '/')) != NULL)
8017 progname = tmp + 1;
8018
8019 argc--; argv++;
8020 while (argc > 0) {
8021 char *flag;
8022
8023 if (**argv == '-') {
8024 flag = *argv+1;
8025
8026 /* 1 arg */
8027 if (*flag == 'v') {
8028 display_version();
8029 exit(0);
8030 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008031#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008032 else if (*flag == 'd' && flag[1] == 'e')
8033 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008034#endif
8035#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008036 else if (*flag == 'd' && flag[1] == 'p')
8037 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008038#endif
willy tarreau982249e2005-12-18 00:57:06 +01008039 else if (*flag == 'V')
8040 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008041 else if (*flag == 'd' && flag[1] == 'b')
8042 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008043 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008044 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008045 else if (*flag == 'c')
8046 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008047 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008048 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008049 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008050 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01008051#if STATTIME > 0
8052 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01008053 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01008054 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01008055 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01008056#endif
willy tarreau53e99702006-03-25 18:53:50 +01008057 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8058 /* list of pids to finish ('f') or terminate ('t') */
8059
8060 if (flag[1] == 'f')
8061 oldpids_sig = SIGUSR1; /* finish then exit */
8062 else
8063 oldpids_sig = SIGTERM; /* terminate immediately */
8064 argv++; argc--;
8065
8066 if (argc > 0) {
8067 oldpids = calloc(argc, sizeof(int));
8068 while (argc > 0) {
8069 oldpids[nb_oldpids] = atol(*argv);
8070 if (oldpids[nb_oldpids] <= 0)
8071 usage(old_argv);
8072 argc--; argv++;
8073 nb_oldpids++;
8074 }
8075 }
8076 }
willy tarreau0f7af912005-12-17 12:21:26 +01008077 else { /* >=2 args */
8078 argv++; argc--;
8079 if (argc == 0)
8080 usage(old_argv);
8081
8082 switch (*flag) {
8083 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008084 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008085 case 'N' : cfg_maxpconn = atol(*argv); break;
8086 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008087 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008088 default: usage(old_argv);
8089 }
8090 }
8091 }
8092 else
8093 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008094 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008095 }
8096
willy tarreaud0fb4652005-12-18 01:32:04 +01008097 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008098 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8099 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008100
willy tarreau0f7af912005-12-17 12:21:26 +01008101 if (!cfg_cfgfile)
8102 usage(old_argv);
8103
8104 gethostname(hostname, MAX_HOSTNAME_LEN);
8105
willy tarreau12350152005-12-18 01:03:27 +01008106 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008107 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008108 if (readcfgfile(cfg_cfgfile) < 0) {
8109 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8110 exit(1);
8111 }
willy tarreau12350152005-12-18 01:03:27 +01008112 if (have_appsession)
8113 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008114
willy tarreau982249e2005-12-18 00:57:06 +01008115 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008116 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8117 exit(0);
8118 }
8119
willy tarreau9fe663a2005-12-17 13:02:59 +01008120 if (cfg_maxconn > 0)
8121 global.maxconn = cfg_maxconn;
8122
willy tarreaufe2c5c12005-12-17 14:14:34 +01008123 if (cfg_pidfile) {
8124 if (global.pidfile)
8125 free(global.pidfile);
8126 global.pidfile = strdup(cfg_pidfile);
8127 }
8128
willy tarreau9fe663a2005-12-17 13:02:59 +01008129 if (global.maxconn == 0)
8130 global.maxconn = DEFAULT_MAXCONN;
8131
Willy TARREAU203b0b62006-03-12 18:00:28 +01008132 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008133
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008134 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008135 /* command line debug mode inhibits configuration mode */
8136 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8137 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008138 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8139 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008140
8141 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8142 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8143 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8144 }
8145
8146 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008147 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8148 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008149 global.nbproc = 1;
8150 }
8151
8152 if (global.nbproc < 1)
8153 global.nbproc = 1;
8154
willy tarreau0f7af912005-12-17 12:21:26 +01008155 StaticReadEvent = (fd_set *)calloc(1,
8156 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008157 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008158 StaticWriteEvent = (fd_set *)calloc(1,
8159 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008160 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008161
8162 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008163 sizeof(struct fdtab) * (global.maxsock));
8164 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008165 fdtab[i].state = FD_STCLOSE;
8166 }
8167}
8168
8169/*
willy tarreau41310e72006-03-25 18:17:56 +01008170 * this function starts all the proxies. Its return value is composed from
8171 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8172 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008173 */
willy tarreau41310e72006-03-25 18:17:56 +01008174int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008175 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008176 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008177 int err = ERR_NONE;
8178 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008179
8180 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008181 if (curproxy->state != PR_STNEW)
8182 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008183
willy tarreau41310e72006-03-25 18:17:56 +01008184 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008185 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008186 if (listener->fd != -1)
8187 continue; /* already initialized */
8188
8189 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8190 if (verbose)
8191 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8192 curproxy->id);
8193 err |= ERR_RETRYABLE;
8194 pxerr |= 1;
8195 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008196 }
willy tarreau0f7af912005-12-17 12:21:26 +01008197
willy tarreaua41a8b42005-12-17 14:02:24 +01008198 if (fd >= global.maxsock) {
8199 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8200 curproxy->id);
8201 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008202 err |= ERR_FATAL;
8203 pxerr |= 1;
8204 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008205 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008206
willy tarreaua41a8b42005-12-17 14:02:24 +01008207 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8208 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8209 (char *) &one, sizeof(one)) == -1)) {
8210 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8211 curproxy->id);
8212 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008213 err |= ERR_FATAL;
8214 pxerr |= 1;
8215 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008216 }
willy tarreau0f7af912005-12-17 12:21:26 +01008217
willy tarreaua41a8b42005-12-17 14:02:24 +01008218 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8219 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8220 curproxy->id);
8221 }
willy tarreau0f7af912005-12-17 12:21:26 +01008222
willy tarreaua41a8b42005-12-17 14:02:24 +01008223 if (bind(fd,
8224 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008225 listener->addr.ss_family == AF_INET6 ?
8226 sizeof(struct sockaddr_in6) :
8227 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008228 if (verbose)
8229 Alert("cannot bind socket for proxy %s. Aborting.\n",
8230 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008231 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008232 err |= ERR_RETRYABLE;
8233 pxerr |= 1;
8234 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008235 }
willy tarreau0f7af912005-12-17 12:21:26 +01008236
willy tarreaua41a8b42005-12-17 14:02:24 +01008237 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008238 if (verbose)
8239 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8240 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008241 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008242 err |= ERR_RETRYABLE;
8243 pxerr |= 1;
8244 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008245 }
willy tarreau0f7af912005-12-17 12:21:26 +01008246
willy tarreau41310e72006-03-25 18:17:56 +01008247 /* the socket is ready */
8248 listener->fd = fd;
8249
willy tarreaua41a8b42005-12-17 14:02:24 +01008250 /* the function for the accept() event */
8251 fdtab[fd].read = &event_accept;
8252 fdtab[fd].write = NULL; /* never called */
8253 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008254 fdtab[fd].state = FD_STLISTEN;
8255 FD_SET(fd, StaticReadEvent);
8256 fd_insert(fd);
8257 listeners++;
8258 }
willy tarreau41310e72006-03-25 18:17:56 +01008259
8260 if (!pxerr) {
8261 curproxy->state = PR_STRUN;
8262 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8263 }
willy tarreau0f7af912005-12-17 12:21:26 +01008264 }
willy tarreau41310e72006-03-25 18:17:56 +01008265
8266 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008267}
8268
willy tarreaub952e1d2005-12-18 01:31:20 +01008269int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008270
8271 appsess *temp1,*temp2;
8272 temp1 = (appsess *)key1;
8273 temp2 = (appsess *)key2;
8274
8275 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8276 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8277
8278 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8279}/* end match_str */
8280
willy tarreaub952e1d2005-12-18 01:31:20 +01008281void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008282 appsess *temp1;
8283
8284 //printf("destroy called\n");
8285 temp1 = (appsess *)data;
8286
8287 if (temp1->sessid)
8288 pool_free_to(apools.sessid, temp1->sessid);
8289
8290 if (temp1->serverid)
8291 pool_free_to(apools.serverid, temp1->serverid);
8292
8293 pool_free(appsess, temp1);
8294} /* end destroy */
8295
8296void appsession_cleanup( void )
8297{
8298 struct proxy *p = proxy;
8299
8300 while(p) {
8301 chtbl_destroy(&(p->htbl_proxy));
8302 p = p->next;
8303 }
8304}/* end appsession_cleanup() */
8305
8306void pool_destroy(void **pool)
8307{
8308 void *temp, *next;
8309 next = pool;
8310 while (next) {
8311 temp = next;
8312 next = *(void **)temp;
8313 free(temp);
8314 }
8315}/* end pool_destroy() */
8316
willy tarreaub952e1d2005-12-18 01:31:20 +01008317void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008318 struct proxy *p = proxy;
8319 struct cap_hdr *h,*h_next;
8320 struct server *s,*s_next;
8321 struct listener *l,*l_next;
8322
8323 while (p) {
8324 if (p->id)
8325 free(p->id);
8326
8327 if (p->check_req)
8328 free(p->check_req);
8329
8330 if (p->cookie_name)
8331 free(p->cookie_name);
8332
8333 if (p->capture_name)
8334 free(p->capture_name);
8335
8336 /* only strup if the user have set in config.
8337 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008338 if (p->errmsg.msg400) free(p->errmsg.msg400);
8339 if (p->errmsg.msg403) free(p->errmsg.msg403);
8340 if (p->errmsg.msg408) free(p->errmsg.msg408);
8341 if (p->errmsg.msg500) free(p->errmsg.msg500);
8342 if (p->errmsg.msg502) free(p->errmsg.msg502);
8343 if (p->errmsg.msg503) free(p->errmsg.msg503);
8344 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008345 */
8346 if (p->appsession_name)
8347 free(p->appsession_name);
8348
8349 h = p->req_cap;
8350 while (h) {
8351 h_next = h->next;
8352 if (h->name)
8353 free(h->name);
8354 pool_destroy(h->pool);
8355 free(h);
8356 h = h_next;
8357 }/* end while(h) */
8358
8359 h = p->rsp_cap;
8360 while (h) {
8361 h_next = h->next;
8362 if (h->name)
8363 free(h->name);
8364
8365 pool_destroy(h->pool);
8366 free(h);
8367 h = h_next;
8368 }/* end while(h) */
8369
8370 s = p->srv;
8371 while (s) {
8372 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008373 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008374 free(s->id);
8375
willy tarreaub952e1d2005-12-18 01:31:20 +01008376 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008377 free(s->cookie);
8378
8379 free(s);
8380 s = s_next;
8381 }/* end while(s) */
8382
8383 l = p->listen;
8384 while (l) {
8385 l_next = l->next;
8386 free(l);
8387 l = l_next;
8388 }/* end while(l) */
8389
8390 pool_destroy((void **) p->req_cap_pool);
8391 pool_destroy((void **) p->rsp_cap_pool);
8392 p = p->next;
8393 }/* end while(p) */
8394
8395 if (global.chroot) free(global.chroot);
8396 if (global.pidfile) free(global.pidfile);
8397
willy tarreau12350152005-12-18 01:03:27 +01008398 if (StaticReadEvent) free(StaticReadEvent);
8399 if (StaticWriteEvent) free(StaticWriteEvent);
8400 if (fdtab) free(fdtab);
8401
8402 pool_destroy(pool_session);
8403 pool_destroy(pool_buffer);
8404 pool_destroy(pool_fdtab);
8405 pool_destroy(pool_requri);
8406 pool_destroy(pool_task);
8407 pool_destroy(pool_capture);
8408 pool_destroy(pool_appsess);
8409
8410 if (have_appsession) {
8411 pool_destroy(apools.serverid);
8412 pool_destroy(apools.sessid);
8413 }
8414} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008415
willy tarreau41310e72006-03-25 18:17:56 +01008416/* sends the signal <sig> to all pids found in <oldpids> */
8417static void tell_old_pids(int sig) {
8418 int p;
8419 for (p = 0; p < nb_oldpids; p++)
8420 kill(oldpids[p], sig);
8421}
8422
willy tarreau0f7af912005-12-17 12:21:26 +01008423int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008424 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008425 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008426 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008427 init(argc, argv);
8428
willy tarreau0f7af912005-12-17 12:21:26 +01008429 signal(SIGQUIT, dump);
8430 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008431 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008432#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008433 signal(SIGINT, sig_int);
8434 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008435#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008436
8437 /* on very high loads, a sigpipe sometimes happen just between the
8438 * getsockopt() which tells "it's OK to write", and the following write :-(
8439 */
willy tarreau3242e862005-12-17 12:27:53 +01008440#ifndef MSG_NOSIGNAL
8441 signal(SIGPIPE, SIG_IGN);
8442#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008443
willy tarreau41310e72006-03-25 18:17:56 +01008444 /* We will loop at most 100 times with 10 ms delay each time.
8445 * That's at most 1 second. We only send a signal to old pids
8446 * if we cannot grab at least one port.
8447 */
8448 retry = MAX_START_RETRIES;
8449 err = ERR_NONE;
8450 while (retry >= 0) {
8451 struct timeval w;
8452 err = start_proxies(retry == 0 || nb_oldpids == 0);
8453 if (err != ERR_RETRYABLE)
8454 break;
8455 if (nb_oldpids == 0)
8456 break;
8457
8458 tell_old_pids(SIGTTOU);
8459 /* give some time to old processes to stop listening */
8460 w.tv_sec = 0;
8461 w.tv_usec = 10*1000;
8462 select(0, NULL, NULL, NULL, &w);
8463 retry--;
8464 }
8465
8466 /* Note: start_proxies() sends an alert when it fails. */
8467 if (err != ERR_NONE) {
8468 if (retry != MAX_START_RETRIES && nb_oldpids)
8469 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008470 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008471 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008472
8473 if (listeners == 0) {
8474 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008475 /* Note: we don't have to send anything to the old pids because we
8476 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008477 exit(1);
8478 }
8479
willy tarreaudbd3bef2006-01-20 19:35:18 +01008480 /* prepare pause/play signals */
8481 signal(SIGTTOU, sig_pause);
8482 signal(SIGTTIN, sig_listen);
8483
Willy TARREAUe3283d12006-03-01 22:15:29 +01008484 if (global.mode & MODE_DAEMON) {
8485 global.mode &= ~MODE_VERBOSE;
8486 global.mode |= MODE_QUIET;
8487 }
8488
willy tarreaud0fb4652005-12-18 01:32:04 +01008489 /* MODE_QUIET can inhibit alerts and warnings below this line */
8490
8491 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008492 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008493 /* detach from the tty */
8494 fclose(stdin); fclose(stdout); fclose(stderr);
8495 close(0); close(1); close(2);
8496 }
willy tarreau0f7af912005-12-17 12:21:26 +01008497
willy tarreaufe2c5c12005-12-17 14:14:34 +01008498 /* open log & pid files before the chroot */
8499 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8500 int pidfd;
8501 unlink(global.pidfile);
8502 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8503 if (pidfd < 0) {
8504 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008505 if (nb_oldpids)
8506 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008507 exit(1);
8508 }
8509 pidfile = fdopen(pidfd, "w");
8510 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008511
8512 /* chroot if needed */
8513 if (global.chroot != NULL) {
8514 if (chroot(global.chroot) == -1) {
8515 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008516 if (nb_oldpids)
8517 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008518 }
8519 chdir("/");
8520 }
8521
willy tarreaub1285d52005-12-18 01:20:14 +01008522 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008523 if (!global.rlimit_nofile)
8524 global.rlimit_nofile = global.maxsock;
8525
willy tarreaub1285d52005-12-18 01:20:14 +01008526 if (global.rlimit_nofile) {
8527 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8528 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8529 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8530 }
willy tarreau746e26b2006-03-25 11:14:35 +01008531 }
8532
8533 if (global.rlimit_memmax) {
8534 limit.rlim_cur = limit.rlim_max =
8535 global.rlimit_memmax * 1048576 / global.nbproc;
8536#ifdef RLIMIT_AS
8537 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8538 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8539 argv[0], global.rlimit_memmax);
8540 }
8541#else
8542 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8543 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8544 argv[0], global.rlimit_memmax);
8545 }
8546#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008547 }
8548
willy tarreau41310e72006-03-25 18:17:56 +01008549 if (nb_oldpids)
8550 tell_old_pids(oldpids_sig);
8551
8552 /* Note that any error at this stage will be fatal because we will not
8553 * be able to restart the old pids.
8554 */
8555
willy tarreau9fe663a2005-12-17 13:02:59 +01008556 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008557 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008558 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8559 exit(1);
8560 }
8561
willy tarreau036e1ce2005-12-17 13:46:33 +01008562 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008563 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8564 exit(1);
8565 }
8566
willy tarreaub1285d52005-12-18 01:20:14 +01008567 /* check ulimits */
8568 limit.rlim_cur = limit.rlim_max = 0;
8569 getrlimit(RLIMIT_NOFILE, &limit);
8570 if (limit.rlim_cur < global.maxsock) {
8571 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",
8572 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8573 }
8574
willy tarreau9fe663a2005-12-17 13:02:59 +01008575 if (global.mode & MODE_DAEMON) {
8576 int ret = 0;
8577 int proc;
8578
8579 /* the father launches the required number of processes */
8580 for (proc = 0; proc < global.nbproc; proc++) {
8581 ret = fork();
8582 if (ret < 0) {
8583 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008584 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008585 exit(1); /* there has been an error */
8586 }
8587 else if (ret == 0) /* child breaks here */
8588 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008589 if (pidfile != NULL) {
8590 fprintf(pidfile, "%d\n", ret);
8591 fflush(pidfile);
8592 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008593 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008594 /* close the pidfile both in children and father */
8595 if (pidfile != NULL)
8596 fclose(pidfile);
8597 free(global.pidfile);
8598
willy tarreau9fe663a2005-12-17 13:02:59 +01008599 if (proc == global.nbproc)
8600 exit(0); /* parent must leave */
8601
willy tarreau750a4722005-12-17 13:21:24 +01008602 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8603 * that we can detach from the TTY. We MUST NOT do it in other cases since
8604 * it would have already be done, and 0-2 would have been affected to listening
8605 * sockets
8606 */
8607 if (!(global.mode & MODE_QUIET)) {
8608 /* detach from the tty */
8609 fclose(stdin); fclose(stdout); fclose(stderr);
8610 close(0); close(1); close(2); /* close all fd's */
8611 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8612 }
willy tarreaua1598082005-12-17 13:08:06 +01008613 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008614 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008615 }
8616
willy tarreau1c2ad212005-12-18 01:11:29 +01008617#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008618 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008619 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8620 epoll_loop(POLL_LOOP_ACTION_RUN);
8621 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008622 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008623 }
8624 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008625 Warning("epoll() is not available. Using poll()/select() instead.\n");
8626 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008627 }
8628 }
8629#endif
8630
8631#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008632 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008633 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8634 poll_loop(POLL_LOOP_ACTION_RUN);
8635 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008636 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008637 }
8638 else {
8639 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008640 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008641 }
8642 }
8643#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008644 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008645 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8646 select_loop(POLL_LOOP_ACTION_RUN);
8647 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008648 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008649 }
8650 }
8651
willy tarreau0f7af912005-12-17 12:21:26 +01008652
willy tarreau12350152005-12-18 01:03:27 +01008653 /* Free all Hash Keys and all Hash elements */
8654 appsession_cleanup();
8655 /* Do some cleanup */
8656 deinit();
8657
willy tarreau0f7af912005-12-17 12:21:26 +01008658 exit(0);
8659}
willy tarreau12350152005-12-18 01:03:27 +01008660
8661#if defined(DEBUG_HASH)
8662static void print_table(const CHTbl *htbl) {
8663
8664 ListElmt *element;
8665 int i;
8666 appsess *asession;
8667
8668 /*****************************************************************************
8669 * *
8670 * Display the chained hash table. *
8671 * *
8672 *****************************************************************************/
8673
8674 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8675
8676 for (i = 0; i < TBLSIZ; i++) {
8677 fprintf(stdout, "Bucket[%03d]\n", i);
8678
8679 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8680 //fprintf(stdout, "%c", *(char *)list_data(element));
8681 asession = (appsess *)list_data(element);
8682 fprintf(stdout, "ELEM :%s:", asession->sessid);
8683 fprintf(stdout, " Server :%s: \n", asession->serverid);
8684 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8685 }
8686
8687 fprintf(stdout, "\n");
8688 }
8689 return;
8690} /* end print_table */
8691#endif
8692
8693static int appsession_init(void)
8694{
8695 static int initialized = 0;
8696 int idlen;
8697 struct server *s;
8698 struct proxy *p = proxy;
8699
8700 if (!initialized) {
8701 if (!appsession_task_init()) {
8702 apools.sessid = NULL;
8703 apools.serverid = NULL;
8704 apools.ser_waste = 0;
8705 apools.ser_use = 0;
8706 apools.ser_msize = sizeof(void *);
8707 apools.ses_waste = 0;
8708 apools.ses_use = 0;
8709 apools.ses_msize = sizeof(void *);
8710 while (p) {
8711 s = p->srv;
8712 if (apools.ses_msize < p->appsession_len)
8713 apools.ses_msize = p->appsession_len;
8714 while (s) {
8715 idlen = strlen(s->id);
8716 if (apools.ser_msize < idlen)
8717 apools.ser_msize = idlen;
8718 s = s->next;
8719 }
8720 p = p->next;
8721 }
8722 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8723 apools.ses_msize ++;
8724 }
8725 else {
8726 fprintf(stderr, "appsession_task_init failed\n");
8727 return -1;
8728 }
8729 initialized ++;
8730 }
8731 return 0;
8732}
8733
8734static int appsession_task_init(void)
8735{
8736 static int initialized = 0;
8737 struct task *t;
8738 if (!initialized) {
8739 if ((t = pool_alloc(task)) == NULL)
8740 return -1;
8741 t->next = t->prev = t->rqnext = NULL;
8742 t->wq = LIST_HEAD(wait_queue);
8743 t->state = TASK_IDLE;
8744 t->context = NULL;
8745 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8746 task_queue(t);
8747 t->process = appsession_refresh;
8748 initialized ++;
8749 }
8750 return 0;
8751}
8752
8753static int appsession_refresh(struct task *t) {
8754 struct proxy *p = proxy;
8755 CHTbl *htbl;
8756 ListElmt *element, *last;
8757 int i;
8758 appsess *asession;
8759 void *data;
8760
8761 while (p) {
8762 if (p->appsession_name != NULL) {
8763 htbl = &p->htbl_proxy;
8764 /* if we ever give up the use of TBLSIZ, we need to change this */
8765 for (i = 0; i < TBLSIZ; i++) {
8766 last = NULL;
8767 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8768 asession = (appsess *)list_data(element);
8769 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8770 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8771 int len;
8772 /*
8773 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8774 */
8775 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8776 asession->sessid, asession->serverid?asession->serverid:"(null)");
8777 write(1, trash, len);
8778 }
8779 /* delete the expired element from within the hash table */
8780 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8781 && (htbl->table[i].destroy != NULL)) {
8782 htbl->table[i].destroy(data);
8783 }
8784 if (last == NULL) {/* patient lost his head, get a new one */
8785 element = list_head(&htbl->table[i]);
8786 if (element == NULL) break; /* no heads left, go to next patient */
8787 }
8788 else
8789 element = last;
8790 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8791 else
8792 last = element;
8793 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8794 }
8795 }
8796 p = p->next;
8797 }
8798 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8799 return TBLCHKINT;
8800} /* end appsession_refresh */
8801