blob: cb1cda34d88782a9e1d9d9d0e99f3a95c470e73a [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 tarreauc1364612006-04-07 16:28:28 +0200514 int cur_sess; /* number of currently active sessions (including syn_sent) */
515 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau535ae7a2005-12-17 12:58:00 +0100516 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100517};
518
willy tarreau5cbea6f2005-12-17 12:48:26 +0100519/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100520struct task {
521 struct task *next, *prev; /* chaining ... */
522 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100523 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100524 int state; /* task state : IDLE or RUNNING */
525 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100526 int (*process)(struct task *t); /* the function which processes the task */
527 void *context; /* the task's context */
528};
529
530/* WARNING: if new fields are added, they must be initialized in event_accept() */
531struct session {
532 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100533 /* application specific below */
534 struct timeval crexpire; /* expiration date for a client read */
535 struct timeval cwexpire; /* expiration date for a client write */
536 struct timeval srexpire; /* expiration date for a server read */
537 struct timeval swexpire; /* expiration date for a server write */
538 struct timeval cnexpire; /* expiration date for a connect */
539 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
540 struct proxy *proxy; /* the proxy this socket belongs to */
541 int cli_fd; /* the client side fd */
542 int srv_fd; /* the server side fd */
543 int cli_state; /* state of the client side */
544 int srv_state; /* state of the server side */
545 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100546 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100547 struct buffer *req; /* request buffer */
548 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100549 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100550 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100551 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100552 char **req_cap; /* array of captured request headers (may be NULL) */
553 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100554 struct {
555 int logwait; /* log fields waiting to be collected : LW_* */
556 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
557 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
558 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
559 long t_data; /* delay before the first data byte from the server ... */
560 unsigned long t_close; /* total session duration */
561 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100562 char *cli_cookie; /* cookie presented by the client, in capture mode */
563 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100564 int status; /* HTTP status from the server, negative if from proxy */
565 long long bytes; /* number of bytes transferred from the server */
566 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100567 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100568};
569
willy tarreaua41a8b42005-12-17 14:02:24 +0100570struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100571 int fd; /* the listen socket */
572 struct sockaddr_storage addr; /* the address we listen to */
573 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100574};
575
576
willy tarreau0f7af912005-12-17 12:21:26 +0100577struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100578 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100579 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 +0100580 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100581 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100582 struct server *srv, *cursrv; /* known servers, current server */
willy tarreau62084d42006-03-24 18:57:41 +0100583 int srv_act, srv_bck; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100584 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100585 int cookie_len; /* strlen(cookie_name), computed only once */
586 char *appsession_name; /* name of the cookie to look for */
587 int appsession_name_len; /* strlen(appsession_name), computed only once */
588 int appsession_len; /* length of the appsession cookie value to be used */
589 int appsession_timeout;
590 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100591 char *capture_name; /* beginning of the name of the cookie to capture */
592 int capture_namelen; /* length of the cookie name to match */
593 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100594 int clitimeout; /* client I/O timeout (in milliseconds) */
595 int srvtimeout; /* server I/O timeout (in milliseconds) */
596 int contimeout; /* connect timeout (in milliseconds) */
597 char *id; /* proxy id */
598 int nbconn; /* # of active sessions */
willy tarreaub1c331f2006-04-07 18:23:29 +0200599 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100600 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100601 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100602 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100603 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100604 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100605 struct proxy *next;
606 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100607 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100608 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100609 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100610 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100611 int nb_reqadd, nb_rspadd;
612 struct hdr_exp *req_exp; /* regular expressions for request headers */
613 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100614 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
615 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
616 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
617 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100618 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100619 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100620 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
621 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100622 struct {
623 char *msg400; /* message for error 400 */
624 int len400; /* message length for error 400 */
625 char *msg403; /* message for error 403 */
626 int len403; /* message length for error 403 */
627 char *msg408; /* message for error 408 */
628 int len408; /* message length for error 408 */
629 char *msg500; /* message for error 500 */
630 int len500; /* message length for error 500 */
631 char *msg502; /* message for error 502 */
632 int len502; /* message length for error 502 */
633 char *msg503; /* message for error 503 */
634 int len503; /* message length for error 503 */
635 char *msg504; /* message for error 504 */
636 int len504; /* message length for error 504 */
637 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100638};
639
640/* info about one given fd */
641struct fdtab {
642 int (*read)(int fd); /* read function */
643 int (*write)(int fd); /* write function */
644 struct task *owner; /* the session (or proxy) associated with this fd */
645 int state; /* the state of this fd */
646};
647
648/*********************************************************************/
649
willy tarreaub952e1d2005-12-18 01:31:20 +0100650int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100651int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100652char *cfg_cfgfile = NULL; /* configuration file */
653char *progname = NULL; /* program name */
654int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100655
656/* global options */
657static struct {
658 int uid;
659 int gid;
660 int nbproc;
661 int maxconn;
662 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100663 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100664 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100665 int mode;
666 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100667 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100668 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100669 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100670 struct sockaddr_in logsrv1, logsrv2;
671} global = {
672 logfac1 : -1,
673 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100674 loglev1 : 7, /* max syslog level : debug */
675 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100676 /* others NULL OK */
677};
678
willy tarreau0f7af912005-12-17 12:21:26 +0100679/*********************************************************************/
680
willy tarreau1c2ad212005-12-18 01:11:29 +0100681fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100682 *StaticWriteEvent;
683
willy tarreau64a3cc32005-12-18 01:13:11 +0100684int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100685
willy tarreau0f7af912005-12-17 12:21:26 +0100686void **pool_session = NULL,
687 **pool_buffer = NULL,
688 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100689 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100690 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100691 **pool_capture = NULL,
692 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100693
694struct proxy *proxy = NULL; /* list of all existing proxies */
695struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100696struct task *rq = NULL; /* global run queue */
697struct task wait_queue = { /* global wait queue */
698 prev:LIST_HEAD(wait_queue),
699 next:LIST_HEAD(wait_queue)
700};
willy tarreau0f7af912005-12-17 12:21:26 +0100701
willy tarreau0f7af912005-12-17 12:21:26 +0100702static int totalconn = 0; /* total # of terminated sessions */
703static int actconn = 0; /* # of active sessions */
704static int maxfd = 0; /* # of the highest fd + 1 */
705static int listeners = 0; /* # of listeners */
706static int stopping = 0; /* non zero means stopping in progress */
707static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100708static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100709
willy tarreau53e99702006-03-25 18:53:50 +0100710/* Here we store informations about the pids of the processes we may pause
711 * or kill. We will send them a signal every 10 ms until we can bind to all
712 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100713 */
willy tarreau53e99702006-03-25 18:53:50 +0100714#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100715static int nb_oldpids = 0;
716static int *oldpids = NULL;
717static int oldpids_sig; /* use USR1 or TERM */
718
willy tarreau08dedbe2005-12-18 01:13:48 +0100719#if defined(ENABLE_EPOLL)
720/* FIXME: this is dirty, but at the moment, there's no other solution to remove
721 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
722 * structure with pointers to functions such as init_fd() and close_fd(), plus
723 * a private structure with several pointers to places such as below.
724 */
725
726static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
727#endif
728
willy tarreau0f7af912005-12-17 12:21:26 +0100729static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100730/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100731static char trash[BUFSIZE];
732
willy tarreaudd07e972005-12-18 00:48:48 +0100733const int zero = 0;
734const int one = 1;
735
willy tarreau0f7af912005-12-17 12:21:26 +0100736/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100737 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100738 */
739
740#define MAX_SYSLOG_LEN 1024
741#define NB_LOG_FACILITIES 24
742const char *log_facilities[NB_LOG_FACILITIES] = {
743 "kern", "user", "mail", "daemon",
744 "auth", "syslog", "lpr", "news",
745 "uucp", "cron", "auth2", "ftp",
746 "ntp", "audit", "alert", "cron2",
747 "local0", "local1", "local2", "local3",
748 "local4", "local5", "local6", "local7"
749};
750
751
752#define NB_LOG_LEVELS 8
753const char *log_levels[NB_LOG_LEVELS] = {
754 "emerg", "alert", "crit", "err",
755 "warning", "notice", "info", "debug"
756};
757
758#define SYSLOG_PORT 514
759
760const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
761 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100762
willy tarreaub1285d52005-12-18 01:20:14 +0100763const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100764const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
765const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
766const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
767 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
768 unknown, Set-cookie Rewritten */
769
willy tarreau0f7af912005-12-17 12:21:26 +0100770#define MAX_HOSTNAME_LEN 32
771static char hostname[MAX_HOSTNAME_LEN] = "";
772
willy tarreau8337c6b2005-12-17 13:41:01 +0100773const char *HTTP_302 =
774 "HTTP/1.0 302 Found\r\n"
775 "Cache-Control: no-cache\r\n"
776 "Connection: close\r\n"
777 "Location: "; /* not terminated since it will be concatenated with the URL */
778
willy tarreauc1f47532005-12-18 01:08:26 +0100779/* same as 302 except that the browser MUST retry with the GET method */
780const char *HTTP_303 =
781 "HTTP/1.0 303 See Other\r\n"
782 "Cache-Control: no-cache\r\n"
783 "Connection: close\r\n"
784 "Location: "; /* not terminated since it will be concatenated with the URL */
785
willy tarreaua1598082005-12-17 13:08:06 +0100786const char *HTTP_400 =
787 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100788 "Cache-Control: no-cache\r\n"
789 "Connection: close\r\n"
790 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100791 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100792
willy tarreaua1598082005-12-17 13:08:06 +0100793const char *HTTP_403 =
794 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100795 "Cache-Control: no-cache\r\n"
796 "Connection: close\r\n"
797 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100798 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
799
willy tarreau8337c6b2005-12-17 13:41:01 +0100800const char *HTTP_408 =
801 "HTTP/1.0 408 Request Time-out\r\n"
802 "Cache-Control: no-cache\r\n"
803 "Connection: close\r\n"
804 "\r\n"
805 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
806
willy tarreau750a4722005-12-17 13:21:24 +0100807const char *HTTP_500 =
808 "HTTP/1.0 500 Server Error\r\n"
809 "Cache-Control: no-cache\r\n"
810 "Connection: close\r\n"
811 "\r\n"
812 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100813
814const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100815 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100816 "Cache-Control: no-cache\r\n"
817 "Connection: close\r\n"
818 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100819 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
820
821const char *HTTP_503 =
822 "HTTP/1.0 503 Service Unavailable\r\n"
823 "Cache-Control: no-cache\r\n"
824 "Connection: close\r\n"
825 "\r\n"
826 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
827
828const char *HTTP_504 =
829 "HTTP/1.0 504 Gateway Time-out\r\n"
830 "Cache-Control: no-cache\r\n"
831 "Connection: close\r\n"
832 "\r\n"
833 "<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 +0100834
willy tarreau0f7af912005-12-17 12:21:26 +0100835/*********************************************************************/
836/* statistics ******************************************************/
837/*********************************************************************/
838
willy tarreau750a4722005-12-17 13:21:24 +0100839#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100840static int stats_tsk_lsrch, stats_tsk_rsrch,
841 stats_tsk_good, stats_tsk_right, stats_tsk_left,
842 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100843#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100844
845
846/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100847/* debugging *******************************************************/
848/*********************************************************************/
849#ifdef DEBUG_FULL
850static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
851static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
852#endif
853
854/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100855/* function prototypes *********************************************/
856/*********************************************************************/
857
858int event_accept(int fd);
859int event_cli_read(int fd);
860int event_cli_write(int fd);
861int event_srv_read(int fd);
862int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100863int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100864
willy tarreau12350152005-12-18 01:03:27 +0100865static int appsession_task_init(void);
866static int appsession_init(void);
867static int appsession_refresh(struct task *t);
868
willy tarreau0f7af912005-12-17 12:21:26 +0100869/*********************************************************************/
870/* general purpose functions ***************************************/
871/*********************************************************************/
872
873void display_version() {
874 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100875 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100876}
877
878/*
879 * This function prints the command line usage and exits
880 */
881void usage(char *name) {
882 display_version();
883 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100884 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100885#if STATTIME > 0
886 "sl"
887#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100888 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
889 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100890 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100891 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100892 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100893#if STATTIME > 0
894 " -s enables statistics output\n"
895 " -l enables long statistics format\n"
896#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100897 " -D goes daemon ; implies -q\n"
898 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100899 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100900 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100901 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100902 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100903 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100904#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100905 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100906#endif
907#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100908 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100909#endif
willy tarreau53e99702006-03-25 18:53:50 +0100910 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100911 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100912 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100913 exit(1);
914}
915
916
917/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100918 * Displays the message on stderr with the date and pid. Overrides the quiet
919 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100920 */
921void Alert(char *fmt, ...) {
922 va_list argp;
923 struct timeval tv;
924 struct tm *tm;
925
willy tarreaud0fb4652005-12-18 01:32:04 +0100926 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100927 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100928
willy tarreau5cbea6f2005-12-17 12:48:26 +0100929 gettimeofday(&tv, NULL);
930 tm=localtime(&tv.tv_sec);
931 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100932 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100933 vfprintf(stderr, fmt, argp);
934 fflush(stderr);
935 va_end(argp);
936 }
willy tarreau0f7af912005-12-17 12:21:26 +0100937}
938
939
940/*
941 * Displays the message on stderr with the date and pid.
942 */
943void Warning(char *fmt, ...) {
944 va_list argp;
945 struct timeval tv;
946 struct tm *tm;
947
willy tarreau982249e2005-12-18 00:57:06 +0100948 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100949 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100950
willy tarreau5cbea6f2005-12-17 12:48:26 +0100951 gettimeofday(&tv, NULL);
952 tm=localtime(&tv.tv_sec);
953 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100954 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100955 vfprintf(stderr, fmt, argp);
956 fflush(stderr);
957 va_end(argp);
958 }
959}
960
961/*
962 * Displays the message on <out> only if quiet mode is not set.
963 */
964void qfprintf(FILE *out, char *fmt, ...) {
965 va_list argp;
966
willy tarreau982249e2005-12-18 00:57:06 +0100967 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100968 va_start(argp, fmt);
969 vfprintf(out, fmt, argp);
970 fflush(out);
971 va_end(argp);
972 }
willy tarreau0f7af912005-12-17 12:21:26 +0100973}
974
975
976/*
977 * converts <str> to a struct sockaddr_in* which is locally allocated.
978 * The format is "addr:port", where "addr" can be empty or "*" to indicate
979 * INADDR_ANY.
980 */
981struct sockaddr_in *str2sa(char *str) {
982 static struct sockaddr_in sa;
983 char *c;
984 int port;
985
willy tarreaua1598082005-12-17 13:08:06 +0100986 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100987 str=strdup(str);
988
989 if ((c=strrchr(str,':')) != NULL) {
990 *c++=0;
991 port=atol(c);
992 }
993 else
994 port=0;
995
996 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
997 sa.sin_addr.s_addr = INADDR_ANY;
998 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100999 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001000 struct hostent *he;
1001
1002 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001003 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001004 }
1005 else
1006 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1007 }
1008 sa.sin_port=htons(port);
1009 sa.sin_family=AF_INET;
1010
1011 free(str);
1012 return &sa;
1013}
1014
willy tarreaub1285d52005-12-18 01:20:14 +01001015/*
1016 * converts <str> to a two struct in_addr* which are locally allocated.
1017 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1018 * is optionnal and either in the dotted or CIDR notation.
1019 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1020 */
1021int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1022 char *c;
1023 unsigned long len;
1024
1025 memset(mask, 0, sizeof(*mask));
1026 memset(addr, 0, sizeof(*addr));
1027 str=strdup(str);
1028
1029 if ((c = strrchr(str, '/')) != NULL) {
1030 *c++ = 0;
1031 /* c points to the mask */
1032 if (strchr(c, '.') != NULL) { /* dotted notation */
1033 if (!inet_pton(AF_INET, c, mask))
1034 return 0;
1035 }
1036 else { /* mask length */
1037 char *err;
1038 len = strtol(c, &err, 10);
1039 if (!*c || (err && *err) || (unsigned)len > 32)
1040 return 0;
1041 if (len)
1042 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1043 else
1044 mask->s_addr = 0;
1045 }
1046 }
1047 else {
1048 mask->s_addr = 0xFFFFFFFF;
1049 }
1050 if (!inet_pton(AF_INET, str, addr)) {
1051 struct hostent *he;
1052
1053 if ((he = gethostbyname(str)) == NULL) {
1054 return 0;
1055 }
1056 else
1057 *addr = *(struct in_addr *) *(he->h_addr_list);
1058 }
1059 free(str);
1060 return 1;
1061}
1062
willy tarreau9fe663a2005-12-17 13:02:59 +01001063
1064/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001065 * converts <str> to a list of listeners which are dynamically allocated.
1066 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1067 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1068 * - <port> is a numerical port from 1 to 65535 ;
1069 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1070 * This can be repeated as many times as necessary, separated by a coma.
1071 * The <tail> argument is a pointer to a current list which should be appended
1072 * to the tail of the new list. The pointer to the new list is returned.
1073 */
1074struct listener *str2listener(char *str, struct listener *tail) {
1075 struct listener *l;
1076 char *c, *next, *range, *dupstr;
1077 int port, end;
1078
1079 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001080
willy tarreaua41a8b42005-12-17 14:02:24 +01001081 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001082 struct sockaddr_storage ss;
1083
willy tarreaua41a8b42005-12-17 14:02:24 +01001084 str = next;
1085 /* 1) look for the end of the first address */
1086 if ((next = strrchr(str, ',')) != NULL) {
1087 *next++ = 0;
1088 }
1089
willy tarreau8a86dbf2005-12-18 00:45:59 +01001090 /* 2) look for the addr/port delimiter, it's the last colon. */
1091 if ((range = strrchr(str, ':')) == NULL) {
1092 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001093 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001094 }
1095
1096 *range++ = 0;
1097
1098 if (strrchr(str, ':') != NULL) {
1099 /* IPv6 address contains ':' */
1100 memset(&ss, 0, sizeof(ss));
1101 ss.ss_family = AF_INET6;
1102
1103 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1104 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001105 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001106 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001107 }
1108 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001109 memset(&ss, 0, sizeof(ss));
1110 ss.ss_family = AF_INET;
1111
1112 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1113 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1114 }
1115 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1116 struct hostent *he;
1117
1118 if ((he = gethostbyname(str)) == NULL) {
1119 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001120 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001121 }
1122 else
1123 ((struct sockaddr_in *)&ss)->sin_addr =
1124 *(struct in_addr *) *(he->h_addr_list);
1125 }
1126 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001127
1128 /* 3) look for the port-end delimiter */
1129 if ((c = strchr(range, '-')) != NULL) {
1130 *c++ = 0;
1131 end = atol(c);
1132 }
1133 else {
1134 end = atol(range);
1135 }
1136
willy tarreaud0fb4652005-12-18 01:32:04 +01001137 port = atol(range);
1138
1139 if (port < 1 || port > 65535) {
1140 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1141 goto fail;
1142 }
1143
1144 if (end < 1 || end > 65535) {
1145 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1146 goto fail;
1147 }
1148
1149 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001150 l = (struct listener *)calloc(1, sizeof(struct listener));
1151 l->next = tail;
1152 tail = l;
1153
willy tarreau41310e72006-03-25 18:17:56 +01001154 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001155 l->addr = ss;
1156 if (ss.ss_family == AF_INET6)
1157 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1158 else
1159 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1160
willy tarreaua41a8b42005-12-17 14:02:24 +01001161 } /* end for(port) */
1162 } /* end while(next) */
1163 free(dupstr);
1164 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001165 fail:
1166 free(dupstr);
1167 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001168}
1169
willy tarreau4302f492005-12-18 01:00:37 +01001170
1171#define FD_SETS_ARE_BITFIELDS
1172#ifdef FD_SETS_ARE_BITFIELDS
1173/*
1174 * This map is used with all the FD_* macros to check whether a particular bit
1175 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1176 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1177 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1178 * exclusively to the macros.
1179 */
1180fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1181fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1182
1183#else
1184#error "Check if your OS uses bitfields for fd_sets"
1185#endif
1186
1187/* will try to encode the string <string> replacing all characters tagged in
1188 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1189 * prefixed by <escape>, and will store the result between <start> (included
1190 *) and <stop> (excluded), and will always terminate the string with a '\0'
1191 * before <stop>. The position of the '\0' is returned if the conversion
1192 * completes. If bytes are missing between <start> and <stop>, then the
1193 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1194 * cannot even be stored so we return <start> without writing the 0.
1195 * The input string must also be zero-terminated.
1196 */
1197char hextab[16] = "0123456789ABCDEF";
1198char *encode_string(char *start, char *stop,
1199 const char escape, const fd_set *map,
1200 const char *string)
1201{
1202 if (start < stop) {
1203 stop--; /* reserve one byte for the final '\0' */
1204 while (start < stop && *string != 0) {
1205 if (!FD_ISSET((unsigned char)(*string), map))
1206 *start++ = *string;
1207 else {
1208 if (start + 3 >= stop)
1209 break;
1210 *start++ = escape;
1211 *start++ = hextab[(*string >> 4) & 15];
1212 *start++ = hextab[*string & 15];
1213 }
1214 string++;
1215 }
1216 *start = '\0';
1217 }
1218 return start;
1219}
willy tarreaua41a8b42005-12-17 14:02:24 +01001220
1221/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001222 * This function sends a syslog message to both log servers of a proxy,
1223 * or to global log servers if the proxy is NULL.
1224 * It also tries not to waste too much time computing the message header.
1225 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001226 */
1227void send_log(struct proxy *p, int level, char *message, ...) {
1228 static int logfd = -1; /* syslog UDP socket */
1229 static long tvsec = -1; /* to force the string to be initialized */
1230 struct timeval tv;
1231 va_list argp;
1232 static char logmsg[MAX_SYSLOG_LEN];
1233 static char *dataptr = NULL;
1234 int fac_level;
1235 int hdr_len, data_len;
1236 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001237 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001238 int nbloggers = 0;
1239 char *log_ptr;
1240
1241 if (logfd < 0) {
1242 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1243 return;
1244 }
1245
1246 if (level < 0 || progname == NULL || message == NULL)
1247 return;
1248
1249 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001250 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001251 /* this string is rebuild only once a second */
1252 struct tm *tm = localtime(&tv.tv_sec);
1253 tvsec = tv.tv_sec;
1254
willy tarreauc29948c2005-12-17 13:10:27 +01001255 hdr_len = snprintf(logmsg, sizeof(logmsg),
1256 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1257 monthname[tm->tm_mon],
1258 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1259 progname, pid);
1260 /* WARNING: depending upon implementations, snprintf may return
1261 * either -1 or the number of bytes that would be needed to store
1262 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001263 */
willy tarreauc29948c2005-12-17 13:10:27 +01001264 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1265 hdr_len = sizeof(logmsg);
1266
1267 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001268 }
1269
1270 va_start(argp, message);
1271 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001272 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1273 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001274 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001275 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001276
1277 if (p == NULL) {
1278 if (global.logfac1 >= 0) {
1279 sa[nbloggers] = &global.logsrv1;
1280 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001281 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001282 nbloggers++;
1283 }
1284 if (global.logfac2 >= 0) {
1285 sa[nbloggers] = &global.logsrv2;
1286 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001287 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001288 nbloggers++;
1289 }
1290 } else {
1291 if (p->logfac1 >= 0) {
1292 sa[nbloggers] = &p->logsrv1;
1293 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001294 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001295 nbloggers++;
1296 }
1297 if (p->logfac2 >= 0) {
1298 sa[nbloggers] = &p->logsrv2;
1299 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001300 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001301 nbloggers++;
1302 }
1303 }
1304
1305 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001306 /* we can filter the level of the messages that are sent to each logger */
1307 if (level > loglevel[nbloggers])
1308 continue;
1309
willy tarreauc29948c2005-12-17 13:10:27 +01001310 /* For each target, we may have a different facility.
1311 * We can also have a different log level for each message.
1312 * This induces variations in the message header length.
1313 * Since we don't want to recompute it each time, nor copy it every
1314 * time, we only change the facility in the pre-computed header,
1315 * and we change the pointer to the header accordingly.
1316 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001317 fac_level = (facilities[nbloggers] << 3) + level;
1318 log_ptr = logmsg + 3; /* last digit of the log level */
1319 do {
1320 *log_ptr = '0' + fac_level % 10;
1321 fac_level /= 10;
1322 log_ptr--;
1323 } while (fac_level && log_ptr > logmsg);
1324 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001325
willy tarreauc29948c2005-12-17 13:10:27 +01001326 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001327
1328#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001329 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001330 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1331#else
willy tarreauc29948c2005-12-17 13:10:27 +01001332 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001333 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1334#endif
1335 }
willy tarreau0f7af912005-12-17 12:21:26 +01001336}
1337
1338
1339/* sets <tv> to the current time */
1340static inline struct timeval *tv_now(struct timeval *tv) {
1341 if (tv)
1342 gettimeofday(tv, NULL);
1343 return tv;
1344}
1345
1346/*
1347 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1348 */
1349static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1350 if (!tv || !from)
1351 return NULL;
1352 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1353 tv->tv_sec = from->tv_sec + (ms/1000);
1354 while (tv->tv_usec >= 1000000) {
1355 tv->tv_usec -= 1000000;
1356 tv->tv_sec++;
1357 }
1358 return tv;
1359}
1360
1361/*
1362 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001363 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001364 */
1365static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001366 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001367 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001368 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001369 return 1;
1370 else if (tv1->tv_usec < tv2->tv_usec)
1371 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001372 else if (tv1->tv_usec > tv2->tv_usec)
1373 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001374 else
1375 return 0;
1376}
1377
1378/*
1379 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001380 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001381 */
1382unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1383 int cmp;
1384 unsigned long ret;
1385
1386
willy tarreauef900ab2005-12-17 12:52:52 +01001387 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001388 if (!cmp)
1389 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001390 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001391 struct timeval *tmp = tv1;
1392 tv1 = tv2;
1393 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001394 }
willy tarreauef900ab2005-12-17 12:52:52 +01001395 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001396 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001397 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001398 else
willy tarreauef900ab2005-12-17 12:52:52 +01001399 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001400 return (unsigned long) ret;
1401}
1402
1403/*
willy tarreau750a4722005-12-17 13:21:24 +01001404 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001405 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001406 */
1407static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1408 unsigned long ret;
1409
willy tarreau6e682ce2005-12-17 13:26:49 +01001410 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1411 if (tv2->tv_usec > tv1->tv_usec)
1412 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001413 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001414 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001415 return (unsigned long) ret;
1416}
1417
1418/*
willy tarreau0f7af912005-12-17 12:21:26 +01001419 * 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 +01001420 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001421 */
1422static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001423 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001424 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001425 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001426 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001427 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001428 else
1429 return 0;
1430 }
willy tarreau0f7af912005-12-17 12:21:26 +01001431 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001432 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001433 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001434 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001435 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001436 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001437 else
1438 return 0;
1439}
1440
1441/*
1442 * returns the remaining time between tv1=now and event=tv2
1443 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001444 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001445 */
1446static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1447 unsigned long ret;
1448
willy tarreau0f7af912005-12-17 12:21:26 +01001449 if (tv_cmp_ms(tv1, tv2) >= 0)
1450 return 0; /* event elapsed */
1451
willy tarreauef900ab2005-12-17 12:52:52 +01001452 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001453 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001454 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001455 else
willy tarreauef900ab2005-12-17 12:52:52 +01001456 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001457 return (unsigned long) ret;
1458}
1459
1460
1461/*
1462 * zeroes a struct timeval
1463 */
1464
1465static inline struct timeval *tv_eternity(struct timeval *tv) {
1466 tv->tv_sec = tv->tv_usec = 0;
1467 return tv;
1468}
1469
1470/*
1471 * returns 1 if tv is null, else 0
1472 */
1473static inline int tv_iseternity(struct timeval *tv) {
1474 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1475 return 1;
1476 else
1477 return 0;
1478}
1479
1480/*
1481 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1482 * considering that 0 is the eternity.
1483 */
1484static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1485 if (tv_iseternity(tv1))
1486 if (tv_iseternity(tv2))
1487 return 0; /* same */
1488 else
1489 return 1; /* tv1 later than tv2 */
1490 else if (tv_iseternity(tv2))
1491 return -1; /* tv2 later than tv1 */
1492
1493 if (tv1->tv_sec > tv2->tv_sec)
1494 return 1;
1495 else if (tv1->tv_sec < tv2->tv_sec)
1496 return -1;
1497 else if (tv1->tv_usec > tv2->tv_usec)
1498 return 1;
1499 else if (tv1->tv_usec < tv2->tv_usec)
1500 return -1;
1501 else
1502 return 0;
1503}
1504
1505/*
1506 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1507 * considering that 0 is the eternity.
1508 */
1509static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1510 if (tv_iseternity(tv1))
1511 if (tv_iseternity(tv2))
1512 return 0; /* same */
1513 else
1514 return 1; /* tv1 later than tv2 */
1515 else if (tv_iseternity(tv2))
1516 return -1; /* tv2 later than tv1 */
1517
willy tarreauefae1842005-12-17 12:51:03 +01001518 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001519 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001520 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001521 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001522 return -1;
1523 else
1524 return 0;
1525 }
1526 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001527 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001528 return 1;
1529 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001530 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001531 return -1;
1532 else
1533 return 0;
1534}
1535
1536/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001537 * returns the remaining time between tv1=now and event=tv2
1538 * if tv2 is passed, 0 is returned.
1539 * Returns TIME_ETERNITY if tv2 is eternity.
1540 */
1541static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1542 unsigned long ret;
1543
1544 if (tv_iseternity(tv2))
1545 return TIME_ETERNITY;
1546
1547 if (tv_cmp_ms(tv1, tv2) >= 0)
1548 return 0; /* event elapsed */
1549
1550 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1551 if (tv2->tv_usec > tv1->tv_usec)
1552 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1553 else
1554 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1555 return (unsigned long) ret;
1556}
1557
1558/*
willy tarreau0f7af912005-12-17 12:21:26 +01001559 * returns the first event between tv1 and tv2 into tvmin.
1560 * a zero tv is ignored. tvmin is returned.
1561 */
1562static inline struct timeval *tv_min(struct timeval *tvmin,
1563 struct timeval *tv1, struct timeval *tv2) {
1564
1565 if (tv_cmp2(tv1, tv2) <= 0)
1566 *tvmin = *tv1;
1567 else
1568 *tvmin = *tv2;
1569
1570 return tvmin;
1571}
1572
1573
1574
1575/***********************************************************/
1576/* fd management ***************************************/
1577/***********************************************************/
1578
1579
1580
willy tarreau5cbea6f2005-12-17 12:48:26 +01001581/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1582 * The file descriptor is also closed.
1583 */
willy tarreau0f7af912005-12-17 12:21:26 +01001584static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001585 FD_CLR(fd, StaticReadEvent);
1586 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001587#if defined(ENABLE_EPOLL)
1588 if (PrevReadEvent) {
1589 FD_CLR(fd, PrevReadEvent);
1590 FD_CLR(fd, PrevWriteEvent);
1591 }
1592#endif
1593
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594 close(fd);
1595 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001596
1597 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1598 maxfd--;
1599}
1600
1601/* recomputes the maxfd limit from the fd */
1602static inline void fd_insert(int fd) {
1603 if (fd+1 > maxfd)
1604 maxfd = fd+1;
1605}
1606
1607/*************************************************************/
1608/* task management ***************************************/
1609/*************************************************************/
1610
willy tarreau5cbea6f2005-12-17 12:48:26 +01001611/* puts the task <t> in run queue <q>, and returns <t> */
1612static inline struct task *task_wakeup(struct task **q, struct task *t) {
1613 if (t->state == TASK_RUNNING)
1614 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001615 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001616 t->rqnext = *q;
1617 t->state = TASK_RUNNING;
1618 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001619 }
1620}
1621
willy tarreau5cbea6f2005-12-17 12:48:26 +01001622/* removes the task <t> from the queue <q>
1623 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001624 * set the run queue to point to the next one, and return it
1625 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001626static inline struct task *task_sleep(struct task **q, struct task *t) {
1627 if (t->state == TASK_RUNNING) {
1628 *q = t->rqnext;
1629 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001630 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001631 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001632}
1633
1634/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001635 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001636 * from the run queue. A pointer to the task itself is returned.
1637 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001638static inline struct task *task_delete(struct task *t) {
1639 t->prev->next = t->next;
1640 t->next->prev = t->prev;
1641 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001642}
1643
1644/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001645 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001646 */
1647static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001648 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001649}
1650
willy tarreau5cbea6f2005-12-17 12:48:26 +01001651/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001652 * may be only moved or left where it was, depending on its timing requirements.
1653 * <task> is returned.
1654 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001655struct task *task_queue(struct task *task) {
1656 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001657 struct task *start_from;
1658
1659 /* first, test if the task was already in a list */
1660 if (task->prev == NULL) {
1661 // start_from = list;
1662 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001663#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001664 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001665#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001666 /* insert the unlinked <task> into the list, searching back from the last entry */
1667 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1668 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001669#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001670 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001671#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001672 }
1673
1674 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1675 // start_from = start_from->next;
1676 // stats_tsk_nsrch++;
1677 // }
1678 }
1679 else if (task->prev == list ||
1680 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1681 start_from = task->next;
1682 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001683#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001684 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001685#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001686 return task; /* it's already in the right place */
1687 }
1688
willy tarreau750a4722005-12-17 13:21:24 +01001689#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001690 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001691#endif
1692
1693 /* if the task is not at the right place, there's little chance that
1694 * it has only shifted a bit, and it will nearly always be queued
1695 * at the end of the list because of constant timeouts
1696 * (observed in real case).
1697 */
1698#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1699 start_from = list->prev; /* assume we'll queue to the end of the list */
1700 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1701 start_from = start_from->prev;
1702#if STATTIME > 0
1703 stats_tsk_lsrch++;
1704#endif
1705 }
1706#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001707 /* insert the unlinked <task> into the list, searching after position <start_from> */
1708 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1709 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001710#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001711 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001712#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001713 }
willy tarreau750a4722005-12-17 13:21:24 +01001714#endif /* WE_REALLY_... */
1715
willy tarreau0f7af912005-12-17 12:21:26 +01001716 /* we need to unlink it now */
1717 task_delete(task);
1718 }
1719 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001720#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001721 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001722#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001723#ifdef LEFT_TO_TOP /* not very good */
1724 start_from = list;
1725 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1726 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001727#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001728 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001729#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001730 }
1731#else
1732 start_from = task->prev->prev; /* valid because of the previous test above */
1733 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1734 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001735#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001736 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001737#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001738 }
1739#endif
1740 /* we need to unlink it now */
1741 task_delete(task);
1742 }
1743 task->prev = start_from;
1744 task->next = start_from->next;
1745 task->next->prev = task;
1746 start_from->next = task;
1747 return task;
1748}
1749
1750
1751/*********************************************************************/
1752/* more specific functions ***************************************/
1753/*********************************************************************/
1754
1755/* some prototypes */
1756static int maintain_proxies(void);
1757
willy tarreaub952e1d2005-12-18 01:31:20 +01001758/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001759 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1760 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001761static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001762#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001763 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1764#else
willy tarreaua1598082005-12-17 13:08:06 +01001765#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001766 return getsockname(fd, (struct sockaddr *)sa, salen);
1767#else
1768 return -1;
1769#endif
1770#endif
1771}
1772
1773/*
1774 * frees the context associated to a session. It must have been removed first.
1775 */
1776static inline void session_free(struct session *s) {
1777 if (s->req)
1778 pool_free(buffer, s->req);
1779 if (s->rep)
1780 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001781
1782 if (s->rsp_cap != NULL) {
1783 struct cap_hdr *h;
1784 for (h = s->proxy->rsp_cap; h; h = h->next) {
1785 if (s->rsp_cap[h->index] != NULL)
1786 pool_free_to(h->pool, s->rsp_cap[h->index]);
1787 }
1788 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1789 }
1790 if (s->req_cap != NULL) {
1791 struct cap_hdr *h;
1792 for (h = s->proxy->req_cap; h; h = h->next) {
1793 if (s->req_cap[h->index] != NULL)
1794 pool_free_to(h->pool, s->req_cap[h->index]);
1795 }
1796 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1797 }
1798
willy tarreaua1598082005-12-17 13:08:06 +01001799 if (s->logs.uri)
1800 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001801 if (s->logs.cli_cookie)
1802 pool_free(capture, s->logs.cli_cookie);
1803 if (s->logs.srv_cookie)
1804 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001805
willy tarreau5cbea6f2005-12-17 12:48:26 +01001806 pool_free(session, s);
1807}
1808
willy tarreau0f7af912005-12-17 12:21:26 +01001809
1810/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001811 * This function recounts the number of usable active and backup servers for
1812 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
1813 */
1814static inline void recount_servers(struct proxy *px) {
1815 struct server *srv;
1816
1817 px->srv_act = 0; px->srv_bck = 0;
1818 for (srv = px->srv; srv != NULL; srv = srv->next) {
1819 if (srv->state & SRV_RUNNING) {
1820 if (srv->state & SRV_BACKUP)
1821 px->srv_bck++;
1822 else
1823 px->srv_act++;
1824 }
1825 }
1826}
1827
1828/*
1829 * This function tries to find a running server for the proxy <px> following
1830 * the round-robin method. Depending on the number of active/backup servers,
1831 * it will either look for active servers, or for backup servers.
1832 * If any server is found, it will be returned and px->cursrv will be updated
1833 * to point to the next server. If no valid server is found, NULL is returned.
willy tarreau8337c6b2005-12-17 13:41:01 +01001834 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001835static inline struct server *get_server_rr(struct proxy *px) {
1836 struct server *srv;
willy tarreau72e583d2006-03-23 11:27:02 +01001837 struct server *end;
willy tarreau8337c6b2005-12-17 13:41:01 +01001838
willy tarreau4c8c2b52006-03-24 19:36:41 +01001839 if (px->srv_act) {
1840 srv = px->cursrv;
willy tarreau72e583d2006-03-23 11:27:02 +01001841 if (srv == NULL)
1842 srv = px->srv;
1843 end = srv;
willy tarreau8337c6b2005-12-17 13:41:01 +01001844 do {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001845 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1846 px->cursrv = srv->next;
willy tarreau8337c6b2005-12-17 13:41:01 +01001847 return srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001848 }
1849
willy tarreau8337c6b2005-12-17 13:41:01 +01001850 srv = srv->next;
willy tarreau72e583d2006-03-23 11:27:02 +01001851 if (srv == NULL)
1852 srv = px->srv;
1853 } while (srv != end);
willy tarreau4c8c2b52006-03-24 19:36:41 +01001854 /* note that theorically we should not get there */
1855 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001856
willy tarreau4c8c2b52006-03-24 19:36:41 +01001857 if (px->srv_bck) {
Willy TARREAU3481c462006-03-01 22:37:57 +01001858 /* By default, we look for the first backup server if all others are
1859 * DOWN. But in some cases, it may be desirable to load-balance across
1860 * all backup servers.
1861 */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001862 if (px->options & PR_O_USE_ALL_BK)
1863 srv = px->cursrv;
1864 else
1865 srv = px->srv;
1866
1867 if (srv == NULL)
Willy TARREAU3481c462006-03-01 22:37:57 +01001868 srv = px->srv;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001869 end = srv;
1870 do {
1871 if (srv->state & SRV_RUNNING) {
1872 px->cursrv = srv->next;
1873 return srv;
1874 }
1875 srv = srv->next;
1876 if (srv == NULL)
1877 srv = px->srv;
1878 } while (srv != end);
1879 /* note that theorically we should not get there */
1880 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001881
willy tarreau4c8c2b52006-03-24 19:36:41 +01001882 /* if we get there, it means there are no available servers at all */
willy tarreau8337c6b2005-12-17 13:41:01 +01001883 return NULL;
1884}
1885
willy tarreau62084d42006-03-24 18:57:41 +01001886
1887/*
willy tarreau1a3442d2006-03-24 21:03:20 +01001888 * This function tries to find a running server for the proxy <px> following
1889 * the source hash method. Depending on the number of active/backup servers,
1890 * it will either look for active servers, or for backup servers.
1891 * If any server is found, it will be returned. If no valid server is found,
1892 * NULL is returned.
1893 */
1894static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
1895 struct server *srv;
1896
1897 if (px->srv_act) {
1898 unsigned int h, l;
1899
1900 l = h = 0;
1901 if (px->srv_act > 1) {
1902 while ((l + sizeof (int)) <= len) {
1903 h ^= ntohl(*(unsigned int *)(&addr[l]));
1904 l += sizeof (int);
1905 }
1906 h %= px->srv_act;
1907 }
1908
1909 for (srv = px->srv; srv; srv = srv->next) {
1910 if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
1911 if (!h)
1912 return srv;
1913 h--;
1914 }
1915 }
1916 /* note that theorically we should not get there */
1917 }
1918
1919 if (px->srv_bck) {
1920 unsigned int h, l;
1921
1922 /* By default, we look for the first backup server if all others are
1923 * DOWN. But in some cases, it may be desirable to load-balance across
1924 * all backup servers.
1925 */
1926 l = h = 0;
1927 if (px->srv_bck > 1 && px->options & PR_O_USE_ALL_BK) {
1928 while ((l + sizeof (int)) <= len) {
1929 h ^= ntohl(*(unsigned int *)(&addr[l]));
1930 l += sizeof (int);
1931 }
1932 h %= px->srv_bck;
1933 }
1934
1935 for (srv = px->srv; srv; srv = srv->next) {
1936 if (srv->state & SRV_RUNNING) {
1937 if (!h)
1938 return srv;
1939 h--;
1940 }
1941 }
1942 /* note that theorically we should not get there */
1943 }
1944
1945 /* if we get there, it means there are no available servers at all */
1946 return NULL;
1947}
1948
1949
1950/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001951 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001952 * is set, or to the dispatch server if (s->direct) is 0.
1953 * It can return one of :
1954 * - SN_ERR_NONE if everything's OK
1955 * - SN_ERR_SRVTO if there are no more servers
1956 * - SN_ERR_SRVCL if the connection was refused by the server
1957 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1958 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1959 * - SN_ERR_INTERNAL for any other purely internal errors
1960 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001961 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001962int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001963 int fd;
1964
willy tarreau12350152005-12-18 01:03:27 +01001965#ifdef DEBUG_FULL
1966 fprintf(stderr,"connect_server : s=%p\n",s);
1967#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001968
willy tarreaue39cd132005-12-17 13:00:18 +01001969 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001970 s->srv_addr = s->srv->addr;
1971 }
1972 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01001973 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001974 if (!s->proxy->srv_act && !s->proxy->srv_bck)
1975 return SN_ERR_SRVTO;
1976
willy tarreau5cbea6f2005-12-17 12:48:26 +01001977 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001978 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979
willy tarreau4c8c2b52006-03-24 19:36:41 +01001980 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01001981 s->srv_addr = srv->addr;
1982 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01001983 }
willy tarreau1a3442d2006-03-24 21:03:20 +01001984 else if (s->proxy->options & PR_O_BALANCE_SH) {
1985 struct server *srv;
1986 int len;
1987
1988 if (s->cli_addr.ss_family == AF_INET)
1989 len = 4;
1990 else if (s->cli_addr.ss_family == AF_INET6)
1991 len = 16;
1992 else /* unknown IP family */
1993 return SN_ERR_INTERNAL;
1994
1995 srv = get_server_sh(s->proxy,
1996 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1997 len);
1998 s->srv_addr = srv->addr;
1999 s->srv = srv;
2000 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002001 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01002002 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002003 }
willy tarreaua1598082005-12-17 13:08:06 +01002004 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002005 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002006 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007 }
2008 else if (s->proxy->options & PR_O_TRANSP) {
2009 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002010 socklen_t salen = sizeof(s->srv_addr);
2011
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2013 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002014 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002015 }
2016 }
willy tarreau0f7af912005-12-17 12:21:26 +01002017
willy tarreaua41a8b42005-12-17 14:02:24 +01002018 /* if this server remaps proxied ports, we'll use
2019 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01002020 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01002021 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002022 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002023
willy tarreaub952e1d2005-12-18 01:31:20 +01002024 if (!(s->proxy->options & PR_O_TRANSP) ||
2025 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002026 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2027 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2028 }
2029
willy tarreau0f7af912005-12-17 12:21:26 +01002030 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002031 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002032
2033 if (errno == ENFILE)
2034 send_log(s->proxy, LOG_EMERG,
2035 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2036 s->proxy->id, maxfd);
2037 else if (errno == EMFILE)
2038 send_log(s->proxy, LOG_EMERG,
2039 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2040 s->proxy->id, maxfd);
2041 else if (errno == ENOBUFS || errno == ENOMEM)
2042 send_log(s->proxy, LOG_EMERG,
2043 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2044 s->proxy->id, maxfd);
2045 /* this is a resource error */
2046 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002047 }
2048
willy tarreau9fe663a2005-12-17 13:02:59 +01002049 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002050 /* do not log anything there, it's a normal condition when this option
2051 * is used to serialize connections to a server !
2052 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002053 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2054 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002055 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002056 }
2057
willy tarreau0f7af912005-12-17 12:21:26 +01002058 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2059 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002060 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002061 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002062 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002063 }
2064
willy tarreaub952e1d2005-12-18 01:31:20 +01002065 if (s->proxy->options & PR_O_TCP_SRV_KA)
2066 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2067
willy tarreau0174f312005-12-18 01:02:42 +01002068 /* allow specific binding :
2069 * - server-specific at first
2070 * - proxy-specific next
2071 */
2072 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2073 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2074 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2075 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2076 s->proxy->id, s->srv->id);
2077 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002078 send_log(s->proxy, LOG_EMERG,
2079 "Cannot bind to source address before connect() for server %s/%s.\n",
2080 s->proxy->id, s->srv->id);
2081 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002082 }
2083 }
2084 else if (s->proxy->options & PR_O_BIND_SRC) {
2085 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2086 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2087 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2088 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002089 send_log(s->proxy, LOG_EMERG,
2090 "Cannot bind to source address before connect() for server %s/%s.\n",
2091 s->proxy->id, s->srv->id);
2092 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002093 }
willy tarreaua1598082005-12-17 13:08:06 +01002094 }
2095
willy tarreaub1285d52005-12-18 01:20:14 +01002096 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2097 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2098
2099 if (errno == EAGAIN || errno == EADDRINUSE) {
2100 char *msg;
2101 if (errno == EAGAIN) /* no free ports left, try again later */
2102 msg = "no free ports";
2103 else
2104 msg = "local address already in use";
2105
2106 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002107 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002108 send_log(s->proxy, LOG_EMERG,
2109 "Connect() failed for server %s/%s: %s.\n",
2110 s->proxy->id, s->srv->id, msg);
2111 return SN_ERR_RESOURCE;
2112 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002113 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002114 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002115 return SN_ERR_SRVTO;
2116 } else {
2117 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002118 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002119 close(fd);
2120 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002121 }
2122 }
2123
willy tarreau5cbea6f2005-12-17 12:48:26 +01002124 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002125 fdtab[fd].read = &event_srv_read;
2126 fdtab[fd].write = &event_srv_write;
2127 fdtab[fd].state = FD_STCONN; /* connection in progress */
2128
2129 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002130#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2131 if (PrevReadEvent) {
2132 assert(!(FD_ISSET(fd, PrevReadEvent)));
2133 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2134 }
2135#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002136
2137 fd_insert(fd);
willy tarreauc1364612006-04-07 16:28:28 +02002138 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002139
2140 if (s->proxy->contimeout)
2141 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2142 else
2143 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002144 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002145}
2146
2147/*
2148 * this function is called on a read event from a client socket.
2149 * It returns 0.
2150 */
2151int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002152 struct task *t = fdtab[fd].owner;
2153 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002154 struct buffer *b = s->req;
2155 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002156
willy tarreau12350152005-12-18 01:03:27 +01002157#ifdef DEBUG_FULL
2158 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2159#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002160
willy tarreau0f7af912005-12-17 12:21:26 +01002161 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002162#ifdef FILL_BUFFERS
2163 while (1)
2164#else
2165 do
2166#endif
2167 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002168 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2169 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002170 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002171 }
2172 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002173 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002174 }
2175 else {
2176 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002177 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2178 * since it means that the rewrite protection has been removed. This
2179 * implies that the if statement can be removed.
2180 */
2181 if (max > b->rlim - b->data)
2182 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002183 }
2184
2185 if (max == 0) { /* not anymore room to store data */
2186 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002187 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002188 }
2189
willy tarreau3242e862005-12-17 12:27:53 +01002190#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002191 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002192 int skerr;
2193 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002194
willy tarreau5cbea6f2005-12-17 12:48:26 +01002195 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2196 if (skerr)
2197 ret = -1;
2198 else
2199 ret = recv(fd, b->r, max, 0);
2200 }
willy tarreau3242e862005-12-17 12:27:53 +01002201#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002202 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002203#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002204 if (ret > 0) {
2205 b->r += ret;
2206 b->l += ret;
2207 s->res_cr = RES_DATA;
2208
2209 if (b->r == b->data + BUFSIZE) {
2210 b->r = b->data; /* wrap around the buffer */
2211 }
willy tarreaua1598082005-12-17 13:08:06 +01002212
2213 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002214 /* we hope to read more data or to get a close on next round */
2215 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002216 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002217 else if (ret == 0) {
2218 s->res_cr = RES_NULL;
2219 break;
2220 }
2221 else if (errno == EAGAIN) {/* ignore EAGAIN */
2222 break;
2223 }
2224 else {
2225 s->res_cr = RES_ERROR;
2226 fdtab[fd].state = FD_STERROR;
2227 break;
2228 }
2229 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002230#ifndef FILL_BUFFERS
2231 while (0);
2232#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002233 }
2234 else {
2235 s->res_cr = RES_ERROR;
2236 fdtab[fd].state = FD_STERROR;
2237 }
2238
willy tarreau5cbea6f2005-12-17 12:48:26 +01002239 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002240 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002241 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2242 else
2243 tv_eternity(&s->crexpire);
2244
2245 task_wakeup(&rq, t);
2246 }
willy tarreau0f7af912005-12-17 12:21:26 +01002247
willy tarreau0f7af912005-12-17 12:21:26 +01002248 return 0;
2249}
2250
2251
2252/*
2253 * this function is called on a read event from a server socket.
2254 * It returns 0.
2255 */
2256int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002257 struct task *t = fdtab[fd].owner;
2258 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002259 struct buffer *b = s->rep;
2260 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002261
willy tarreau12350152005-12-18 01:03:27 +01002262#ifdef DEBUG_FULL
2263 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2264#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002265
willy tarreau0f7af912005-12-17 12:21:26 +01002266 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002267#ifdef FILL_BUFFERS
2268 while (1)
2269#else
2270 do
2271#endif
2272 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002273 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2274 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002275 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002276 }
2277 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002278 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002279 }
2280 else {
2281 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002282 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2283 * since it means that the rewrite protection has been removed. This
2284 * implies that the if statement can be removed.
2285 */
2286 if (max > b->rlim - b->data)
2287 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002288 }
2289
2290 if (max == 0) { /* not anymore room to store data */
2291 FD_CLR(fd, StaticReadEvent);
2292 break;
2293 }
2294
willy tarreau3242e862005-12-17 12:27:53 +01002295#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002296 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002297 int skerr;
2298 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002299
willy tarreau5cbea6f2005-12-17 12:48:26 +01002300 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2301 if (skerr)
2302 ret = -1;
2303 else
2304 ret = recv(fd, b->r, max, 0);
2305 }
willy tarreau3242e862005-12-17 12:27:53 +01002306#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002307 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002308#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002309 if (ret > 0) {
2310 b->r += ret;
2311 b->l += ret;
2312 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002313
willy tarreau5cbea6f2005-12-17 12:48:26 +01002314 if (b->r == b->data + BUFSIZE) {
2315 b->r = b->data; /* wrap around the buffer */
2316 }
willy tarreaua1598082005-12-17 13:08:06 +01002317
2318 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002319 /* we hope to read more data or to get a close on next round */
2320 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002321 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002322 else if (ret == 0) {
2323 s->res_sr = RES_NULL;
2324 break;
2325 }
2326 else if (errno == EAGAIN) {/* ignore EAGAIN */
2327 break;
2328 }
2329 else {
2330 s->res_sr = RES_ERROR;
2331 fdtab[fd].state = FD_STERROR;
2332 break;
2333 }
2334 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002335#ifndef FILL_BUFFERS
2336 while (0);
2337#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002338 }
2339 else {
2340 s->res_sr = RES_ERROR;
2341 fdtab[fd].state = FD_STERROR;
2342 }
2343
willy tarreau5cbea6f2005-12-17 12:48:26 +01002344 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002345 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002346 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2347 else
2348 tv_eternity(&s->srexpire);
2349
2350 task_wakeup(&rq, t);
2351 }
willy tarreau0f7af912005-12-17 12:21:26 +01002352
willy tarreau0f7af912005-12-17 12:21:26 +01002353 return 0;
2354}
2355
2356/*
2357 * this function is called on a write event from a client socket.
2358 * It returns 0.
2359 */
2360int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002361 struct task *t = fdtab[fd].owner;
2362 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002363 struct buffer *b = s->rep;
2364 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002365
willy tarreau12350152005-12-18 01:03:27 +01002366#ifdef DEBUG_FULL
2367 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2368#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002369
2370 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002371 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002372 // max = BUFSIZE; BUG !!!!
2373 max = 0;
2374 }
2375 else if (b->r > b->w) {
2376 max = b->r - b->w;
2377 }
2378 else
2379 max = b->data + BUFSIZE - b->w;
2380
willy tarreau0f7af912005-12-17 12:21:26 +01002381 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002382 if (max == 0) {
2383 s->res_cw = RES_NULL;
2384 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002385 tv_eternity(&s->cwexpire);
2386 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002387 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002388 }
2389
willy tarreau3242e862005-12-17 12:27:53 +01002390#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002391 {
2392 int skerr;
2393 socklen_t lskerr = sizeof(skerr);
2394
2395 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2396 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002397 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002398 else
willy tarreau3242e862005-12-17 12:27:53 +01002399 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002400 }
willy tarreau3242e862005-12-17 12:27:53 +01002401#else
willy tarreau0f7af912005-12-17 12:21:26 +01002402 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002403#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002404
2405 if (ret > 0) {
2406 b->l -= ret;
2407 b->w += ret;
2408
2409 s->res_cw = RES_DATA;
2410
2411 if (b->w == b->data + BUFSIZE) {
2412 b->w = b->data; /* wrap around the buffer */
2413 }
2414 }
2415 else if (ret == 0) {
2416 /* nothing written, just make as if we were never called */
2417// s->res_cw = RES_NULL;
2418 return 0;
2419 }
2420 else if (errno == EAGAIN) /* ignore EAGAIN */
2421 return 0;
2422 else {
2423 s->res_cw = RES_ERROR;
2424 fdtab[fd].state = FD_STERROR;
2425 }
2426 }
2427 else {
2428 s->res_cw = RES_ERROR;
2429 fdtab[fd].state = FD_STERROR;
2430 }
2431
willy tarreaub1ff9db2005-12-17 13:51:03 +01002432 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002433 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002434 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2435 s->crexpire = s->cwexpire;
2436 }
willy tarreau0f7af912005-12-17 12:21:26 +01002437 else
2438 tv_eternity(&s->cwexpire);
2439
willy tarreau5cbea6f2005-12-17 12:48:26 +01002440 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002441 return 0;
2442}
2443
2444
2445/*
2446 * this function is called on a write event from a server socket.
2447 * It returns 0.
2448 */
2449int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002450 struct task *t = fdtab[fd].owner;
2451 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002452 struct buffer *b = s->req;
2453 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002454
willy tarreau12350152005-12-18 01:03:27 +01002455#ifdef DEBUG_FULL
2456 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2457#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002458
2459 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002460 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002461 // max = BUFSIZE; BUG !!!!
2462 max = 0;
2463 }
2464 else if (b->r > b->w) {
2465 max = b->r - b->w;
2466 }
2467 else
2468 max = b->data + BUFSIZE - b->w;
2469
willy tarreau0f7af912005-12-17 12:21:26 +01002470 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002471 if (max == 0) {
2472 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002473 if (s->srv_state == SV_STCONN) {
2474 int skerr;
2475 socklen_t lskerr = sizeof(skerr);
2476 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2477 if (skerr) {
2478 s->res_sw = RES_ERROR;
2479 fdtab[fd].state = FD_STERROR;
2480 task_wakeup(&rq, t);
2481 tv_eternity(&s->swexpire);
2482 FD_CLR(fd, StaticWriteEvent);
2483 return 0;
2484 }
2485 }
2486
willy tarreau0f7af912005-12-17 12:21:26 +01002487 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002488 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002489 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002490 tv_eternity(&s->swexpire);
2491 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002492 return 0;
2493 }
2494
willy tarreau3242e862005-12-17 12:27:53 +01002495#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002496 {
2497 int skerr;
2498 socklen_t lskerr = sizeof(skerr);
2499 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2500 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002501 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002502 else
willy tarreau3242e862005-12-17 12:27:53 +01002503 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002504 }
willy tarreau3242e862005-12-17 12:27:53 +01002505#else
willy tarreau0f7af912005-12-17 12:21:26 +01002506 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002507#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002508 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002509 if (ret > 0) {
2510 b->l -= ret;
2511 b->w += ret;
2512
2513 s->res_sw = RES_DATA;
2514
2515 if (b->w == b->data + BUFSIZE) {
2516 b->w = b->data; /* wrap around the buffer */
2517 }
2518 }
2519 else if (ret == 0) {
2520 /* nothing written, just make as if we were never called */
2521 // s->res_sw = RES_NULL;
2522 return 0;
2523 }
2524 else if (errno == EAGAIN) /* ignore EAGAIN */
2525 return 0;
2526 else {
2527 s->res_sw = RES_ERROR;
2528 fdtab[fd].state = FD_STERROR;
2529 }
2530 }
2531 else {
2532 s->res_sw = RES_ERROR;
2533 fdtab[fd].state = FD_STERROR;
2534 }
2535
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002536 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2537 * otherwise it could loop indefinitely !
2538 */
2539 if (s->srv_state != SV_STCONN) {
2540 if (s->proxy->srvtimeout) {
2541 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2542 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2543 s->srexpire = s->swexpire;
2544 }
2545 else
2546 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002547 }
willy tarreau0f7af912005-12-17 12:21:26 +01002548
willy tarreau5cbea6f2005-12-17 12:48:26 +01002549 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002550 return 0;
2551}
2552
2553
2554/*
willy tarreaue39cd132005-12-17 13:00:18 +01002555 * returns a message to the client ; the connection is shut down for read,
2556 * and the request is cleared so that no server connection can be initiated.
2557 * The client must be in a valid state for this (HEADER, DATA ...).
2558 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002559 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002560 */
2561void client_retnclose(struct session *s, int len, const char *msg) {
2562 FD_CLR(s->cli_fd, StaticReadEvent);
2563 FD_SET(s->cli_fd, StaticWriteEvent);
2564 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002565 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002566 shutdown(s->cli_fd, SHUT_RD);
2567 s->cli_state = CL_STSHUTR;
2568 strcpy(s->rep->data, msg);
2569 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002570 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002571 s->rep->r += len;
2572 s->req->l = 0;
2573}
2574
2575
2576/*
2577 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002578 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002579 */
2580void client_return(struct session *s, int len, const char *msg) {
2581 strcpy(s->rep->data, msg);
2582 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002583 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002584 s->rep->r += len;
2585 s->req->l = 0;
2586}
2587
willy tarreau9fe663a2005-12-17 13:02:59 +01002588/*
2589 * send a log for the session when we have enough info about it
2590 */
2591void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002592 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002593 struct proxy *p = s->proxy;
2594 int log;
2595 char *uri;
2596 char *pxid;
2597 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002598 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002599
2600 /* This is a first attempt at a better logging system.
2601 * For now, we rely on send_log() to provide the date, although it obviously
2602 * is the date of the log and not of the request, and most fields are not
2603 * computed.
2604 */
2605
willy tarreaua1598082005-12-17 13:08:06 +01002606 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002607
willy tarreau8a86dbf2005-12-18 00:45:59 +01002608 if (s->cli_addr.ss_family == AF_INET)
2609 inet_ntop(AF_INET,
2610 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2611 pn, sizeof(pn));
2612 else
2613 inet_ntop(AF_INET6,
2614 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2615 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002616
willy tarreauc1cae632005-12-17 14:12:23 +01002617 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002618 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002619 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002620
willy tarreauc1cae632005-12-17 14:12:23 +01002621 tm = localtime(&s->logs.tv_accept.tv_sec);
2622 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002623 char tmpline[MAX_SYSLOG_LEN], *h;
2624 int hdr;
2625
2626 h = tmpline;
2627 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2628 *(h++) = ' ';
2629 *(h++) = '{';
2630 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2631 if (hdr)
2632 *(h++) = '|';
2633 if (s->req_cap[hdr] != NULL)
2634 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2635 }
2636 *(h++) = '}';
2637 }
2638
2639 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2640 *(h++) = ' ';
2641 *(h++) = '{';
2642 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2643 if (hdr)
2644 *(h++) = '|';
2645 if (s->rsp_cap[hdr] != NULL)
2646 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2647 }
2648 *(h++) = '}';
2649 }
2650
2651 if (h < tmpline + sizeof(tmpline) - 4) {
2652 *(h++) = ' ';
2653 *(h++) = '"';
2654 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2655 *(h++) = '"';
2656 }
2657 *h = '\0';
2658
willy tarreauc1364612006-04-07 16:28:28 +02002659 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/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002660 pn,
2661 (s->cli_addr.ss_family == AF_INET) ?
2662 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2663 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002664 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2665 tm->tm_hour, tm->tm_min, tm->tm_sec,
2666 pxid, srv,
2667 s->logs.t_request,
2668 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2669 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002670 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2671 s->logs.status,
2672 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002673 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2674 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002675 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2676 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2677 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2678 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreauc1364612006-04-07 16:28:28 +02002679 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002680 }
2681 else {
willy tarreauc1364612006-04-07 16:28:28 +02002682 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002683 pn,
2684 (s->cli_addr.ss_family == AF_INET) ?
2685 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2686 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002687 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2688 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002689 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002690 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002691 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2692 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002693 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002694 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreauc1364612006-04-07 16:28:28 +02002695 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002696 }
2697
2698 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002699}
2700
willy tarreaue39cd132005-12-17 13:00:18 +01002701
2702/*
willy tarreau0f7af912005-12-17 12:21:26 +01002703 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002704 * to an accept. It tries to accept as many connections as possible.
2705 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002706 */
2707int event_accept(int fd) {
2708 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002709 struct session *s;
2710 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002711 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002712 int max_accept;
2713
2714 if (global.nbproc > 1)
2715 max_accept = 8; /* let other processes catch some connections too */
2716 else
2717 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002718
willy tarreauc2becdc2006-03-19 19:36:48 +01002719 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002720 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002721 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002722
willy tarreaub1285d52005-12-18 01:20:14 +01002723 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2724 switch (errno) {
2725 case EAGAIN:
2726 case EINTR:
2727 case ECONNABORTED:
2728 return 0; /* nothing more to accept */
2729 case ENFILE:
2730 send_log(p, LOG_EMERG,
2731 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2732 p->id, maxfd);
2733 return 0;
2734 case EMFILE:
2735 send_log(p, LOG_EMERG,
2736 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2737 p->id, maxfd);
2738 return 0;
2739 case ENOBUFS:
2740 case ENOMEM:
2741 send_log(p, LOG_EMERG,
2742 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2743 p->id, maxfd);
2744 return 0;
2745 default:
2746 return 0;
2747 }
2748 }
willy tarreau0f7af912005-12-17 12:21:26 +01002749
willy tarreau5cbea6f2005-12-17 12:48:26 +01002750 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2751 Alert("out of memory in event_accept().\n");
2752 FD_CLR(fd, StaticReadEvent);
2753 p->state = PR_STIDLE;
2754 close(cfd);
2755 return 0;
2756 }
willy tarreau0f7af912005-12-17 12:21:26 +01002757
willy tarreaub1285d52005-12-18 01:20:14 +01002758 /* if this session comes from a known monitoring system, we want to ignore
2759 * it as soon as possible, which means closing it immediately for TCP.
2760 */
2761 s->flags = 0;
2762 if (addr.ss_family == AF_INET &&
2763 p->mon_mask.s_addr &&
2764 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2765 if (p->mode == PR_MODE_TCP) {
2766 close(cfd);
2767 pool_free(session, s);
2768 continue;
2769 }
2770 s->flags |= SN_MONITOR;
2771 }
2772
willy tarreau5cbea6f2005-12-17 12:48:26 +01002773 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2774 Alert("out of memory in event_accept().\n");
2775 FD_CLR(fd, StaticReadEvent);
2776 p->state = PR_STIDLE;
2777 close(cfd);
2778 pool_free(session, s);
2779 return 0;
2780 }
willy tarreau0f7af912005-12-17 12:21:26 +01002781
willy tarreau5cbea6f2005-12-17 12:48:26 +01002782 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002783 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002784 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2785 close(cfd);
2786 pool_free(task, t);
2787 pool_free(session, s);
2788 return 0;
2789 }
willy tarreau0f7af912005-12-17 12:21:26 +01002790
willy tarreau5cbea6f2005-12-17 12:48:26 +01002791 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2792 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2793 (char *) &one, sizeof(one)) == -1)) {
2794 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2795 close(cfd);
2796 pool_free(task, t);
2797 pool_free(session, s);
2798 return 0;
2799 }
willy tarreau0f7af912005-12-17 12:21:26 +01002800
willy tarreaub952e1d2005-12-18 01:31:20 +01002801 if (p->options & PR_O_TCP_CLI_KA)
2802 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2803
willy tarreau9fe663a2005-12-17 13:02:59 +01002804 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2805 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2806 t->state = TASK_IDLE;
2807 t->process = process_session;
2808 t->context = s;
2809
2810 s->task = t;
2811 s->proxy = p;
2812 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2813 s->srv_state = SV_STIDLE;
2814 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002815
willy tarreau9fe663a2005-12-17 13:02:59 +01002816 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2817 s->cli_fd = cfd;
2818 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002819 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002820 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002821
willy tarreaub1285d52005-12-18 01:20:14 +01002822 if (s->flags & SN_MONITOR)
2823 s->logs.logwait = 0;
2824 else
2825 s->logs.logwait = p->to_log;
2826
willy tarreaua1598082005-12-17 13:08:06 +01002827 s->logs.tv_accept = now;
2828 s->logs.t_request = -1;
2829 s->logs.t_connect = -1;
2830 s->logs.t_data = -1;
2831 s->logs.t_close = 0;
2832 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002833 s->logs.cli_cookie = NULL;
2834 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002835 s->logs.status = -1;
2836 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002837
willy tarreau2f6ba652005-12-17 13:57:42 +01002838 s->uniq_id = totalconn;
willy tarreaub1c331f2006-04-07 18:23:29 +02002839 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01002840
willy tarreau4302f492005-12-18 01:00:37 +01002841 if (p->nb_req_cap > 0) {
2842 if ((s->req_cap =
2843 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2844 == NULL) { /* no memory */
2845 close(cfd); /* nothing can be done for this fd without memory */
2846 pool_free(task, t);
2847 pool_free(session, s);
2848 return 0;
2849 }
2850 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2851 }
2852 else
2853 s->req_cap = NULL;
2854
2855 if (p->nb_rsp_cap > 0) {
2856 if ((s->rsp_cap =
2857 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2858 == NULL) { /* no memory */
2859 if (s->req_cap != NULL)
2860 pool_free_to(p->req_cap_pool, s->req_cap);
2861 close(cfd); /* nothing can be done for this fd without memory */
2862 pool_free(task, t);
2863 pool_free(session, s);
2864 return 0;
2865 }
2866 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2867 }
2868 else
2869 s->rsp_cap = NULL;
2870
willy tarreau5cbea6f2005-12-17 12:48:26 +01002871 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2872 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002873 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002874 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002875
willy tarreau8a86dbf2005-12-18 00:45:59 +01002876 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002877 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002878 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002879 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002880
willy tarreau9fe663a2005-12-17 13:02:59 +01002881 if (p->to_log) {
2882 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002883 if (s->logs.logwait & LW_CLIP)
2884 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002885 sess_log(s);
2886 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002887 else if (s->cli_addr.ss_family == AF_INET) {
2888 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2889 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2890 sn, sizeof(sn)) &&
2891 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2892 pn, sizeof(pn))) {
2893 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2894 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2895 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2896 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2897 }
2898 }
2899 else {
2900 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2901 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2902 sn, sizeof(sn)) &&
2903 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2904 pn, sizeof(pn))) {
2905 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2906 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2907 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2908 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2909 }
2910 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002911 }
willy tarreau0f7af912005-12-17 12:21:26 +01002912
willy tarreau982249e2005-12-18 00:57:06 +01002913 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002914 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002915 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002916 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002917 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002918 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002919 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002920 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002921
willy tarreau8a86dbf2005-12-18 00:45:59 +01002922 if (s->cli_addr.ss_family == AF_INET) {
2923 char pn[INET_ADDRSTRLEN];
2924 inet_ntop(AF_INET,
2925 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2926 pn, sizeof(pn));
2927
2928 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2929 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2930 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2931 }
2932 else {
2933 char pn[INET6_ADDRSTRLEN];
2934 inet_ntop(AF_INET6,
2935 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2936 pn, sizeof(pn));
2937
2938 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2939 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2940 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2941 }
2942
willy tarreauef900ab2005-12-17 12:52:52 +01002943 write(1, trash, len);
2944 }
willy tarreau0f7af912005-12-17 12:21:26 +01002945
willy tarreau5cbea6f2005-12-17 12:48:26 +01002946 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002947 if (s->rsp_cap != NULL)
2948 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2949 if (s->req_cap != NULL)
2950 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002951 close(cfd); /* nothing can be done for this fd without memory */
2952 pool_free(task, t);
2953 pool_free(session, s);
2954 return 0;
2955 }
willy tarreau4302f492005-12-18 01:00:37 +01002956
willy tarreau5cbea6f2005-12-17 12:48:26 +01002957 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002958 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002959 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2960 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002961 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002962 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002963
willy tarreau5cbea6f2005-12-17 12:48:26 +01002964 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2965 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002966 if (s->rsp_cap != NULL)
2967 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2968 if (s->req_cap != NULL)
2969 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002970 close(cfd); /* nothing can be done for this fd without memory */
2971 pool_free(task, t);
2972 pool_free(session, s);
2973 return 0;
2974 }
2975 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002976 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002977 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 +01002978
willy tarreau5cbea6f2005-12-17 12:48:26 +01002979 fdtab[cfd].read = &event_cli_read;
2980 fdtab[cfd].write = &event_cli_write;
2981 fdtab[cfd].owner = t;
2982 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002983
willy tarreaub1285d52005-12-18 01:20:14 +01002984 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2985 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2986 /* Either we got a request from a monitoring system on an HTTP instance,
2987 * or we're in health check mode with the 'httpchk' option enabled. In
2988 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2989 */
2990 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2991 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2992 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002993 }
2994 else {
2995 FD_SET(cfd, StaticReadEvent);
2996 }
2997
willy tarreaub952e1d2005-12-18 01:31:20 +01002998#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2999 if (PrevReadEvent) {
3000 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3001 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3002 }
3003#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003004 fd_insert(cfd);
3005
3006 tv_eternity(&s->cnexpire);
3007 tv_eternity(&s->srexpire);
3008 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003009 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003010 tv_eternity(&s->cwexpire);
3011
willy tarreaub1285d52005-12-18 01:20:14 +01003012 if (s->proxy->clitimeout) {
3013 if (FD_ISSET(cfd, StaticReadEvent))
3014 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3015 if (FD_ISSET(cfd, StaticWriteEvent))
3016 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3017 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003018
willy tarreaub1285d52005-12-18 01:20:14 +01003019 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003020
3021 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003022
3023 if (p->mode != PR_MODE_HEALTH)
3024 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003025
3026 p->nbconn++;
3027 actconn++;
3028 totalconn++;
3029
willy tarreaub952e1d2005-12-18 01:31:20 +01003030 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003031 } /* end of while (p->nbconn < p->maxconn) */
3032 return 0;
3033}
willy tarreau0f7af912005-12-17 12:21:26 +01003034
willy tarreau0f7af912005-12-17 12:21:26 +01003035
willy tarreau5cbea6f2005-12-17 12:48:26 +01003036/*
3037 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003038 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3039 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003040 * or -1 if an error occured.
3041 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003042int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003043 struct task *t = fdtab[fd].owner;
3044 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003045 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003046 socklen_t lskerr = sizeof(skerr);
3047
willy tarreau05be12b2006-03-19 19:35:00 +01003048 skerr = 1;
3049 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3050 || (skerr != 0)) {
3051 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003052 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003053 fdtab[fd].state = FD_STERROR;
3054 FD_CLR(fd, StaticWriteEvent);
3055 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003056 else if (s->result != -1) {
3057 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003058 if (s->proxy->options & PR_O_HTTP_CHK) {
3059 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003060 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003061 * so we'll send the request, and won't wake the checker up now.
3062 */
3063#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003064 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003065#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003066 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003067#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003068 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003069 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3070 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3071 return 0;
3072 }
willy tarreau05be12b2006-03-19 19:35:00 +01003073 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003074 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003075 FD_CLR(fd, StaticWriteEvent);
3076 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003077 }
3078 else {
3079 /* good TCP connection is enough */
3080 s->result = 1;
3081 }
3082 }
3083
3084 task_wakeup(&rq, t);
3085 return 0;
3086}
3087
willy tarreau0f7af912005-12-17 12:21:26 +01003088
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003089/*
3090 * This function is used only for server health-checks. It handles
3091 * the server's reply to an HTTP request. It returns 1 if the server replies
3092 * 2xx or 3xx (valid responses), or -1 in other cases.
3093 */
3094int event_srv_chk_r(int fd) {
3095 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003096 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003097 struct task *t = fdtab[fd].owner;
3098 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003099 int skerr;
3100 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003101
willy tarreaua4a583a2005-12-18 01:39:19 +01003102 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003103
willy tarreau05be12b2006-03-19 19:35:00 +01003104 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3105 if (!skerr) {
3106#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003107 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003108#else
willy tarreau05be12b2006-03-19 19:35:00 +01003109 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3110 * but the connection was closed on the remote end. Fortunately, recv still
3111 * works correctly and we don't need to do the getsockopt() on linux.
3112 */
3113 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003114#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003115
3116 if ((len >= sizeof("HTTP/1.0 000")) &&
3117 !memcmp(reply, "HTTP/1.", 7) &&
3118 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3119 result = 1;
3120 }
3121
3122 if (result == -1)
3123 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003124
3125 if (s->result != -1)
3126 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003127
3128 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003129 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003130 return 0;
3131}
3132
3133
3134/*
3135 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3136 * and moves <end> just after the end of <str>.
3137 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3138 * the shift value (positive or negative) is returned.
3139 * If there's no space left, the move is not done.
3140 *
3141 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003142int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003143 int delta;
3144 int len;
3145
3146 len = strlen(str);
3147 delta = len - (end - pos);
3148
3149 if (delta + b->r >= b->data + BUFSIZE)
3150 return 0; /* no space left */
3151
3152 /* first, protect the end of the buffer */
3153 memmove(end + delta, end, b->data + b->l - end);
3154
3155 /* now, copy str over pos */
3156 memcpy(pos, str,len);
3157
willy tarreau5cbea6f2005-12-17 12:48:26 +01003158 /* we only move data after the displaced zone */
3159 if (b->r > pos) b->r += delta;
3160 if (b->w > pos) b->w += delta;
3161 if (b->h > pos) b->h += delta;
3162 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003163 b->l += delta;
3164
3165 return delta;
3166}
3167
willy tarreau8337c6b2005-12-17 13:41:01 +01003168/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003169 * len is 0.
3170 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003171int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003172 int delta;
3173
3174 delta = len - (end - pos);
3175
3176 if (delta + b->r >= b->data + BUFSIZE)
3177 return 0; /* no space left */
3178
Willy TARREAUe78ae262006-01-08 01:24:12 +01003179 if (b->data + b->l < end)
3180 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3181 return 0;
3182
willy tarreau0f7af912005-12-17 12:21:26 +01003183 /* first, protect the end of the buffer */
3184 memmove(end + delta, end, b->data + b->l - end);
3185
3186 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003187 if (len)
3188 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003189
willy tarreau5cbea6f2005-12-17 12:48:26 +01003190 /* we only move data after the displaced zone */
3191 if (b->r > pos) b->r += delta;
3192 if (b->w > pos) b->w += delta;
3193 if (b->h > pos) b->h += delta;
3194 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003195 b->l += delta;
3196
3197 return delta;
3198}
3199
3200
3201int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3202 char *old_dst = dst;
3203
3204 while (*str) {
3205 if (*str == '\\') {
3206 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003207 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003208 int len, num;
3209
3210 num = *str - '0';
3211 str++;
3212
willy tarreau8a86dbf2005-12-18 00:45:59 +01003213 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003214 len = matches[num].rm_eo - matches[num].rm_so;
3215 memcpy(dst, src + matches[num].rm_so, len);
3216 dst += len;
3217 }
3218
3219 }
3220 else if (*str == 'x') {
3221 unsigned char hex1, hex2;
3222 str++;
3223
willy tarreauc1f47532005-12-18 01:08:26 +01003224 hex1 = toupper(*str++) - '0';
3225 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003226
3227 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3228 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3229 *dst++ = (hex1<<4) + hex2;
3230 }
3231 else
3232 *dst++ = *str++;
3233 }
3234 else
3235 *dst++ = *str++;
3236 }
3237 *dst = 0;
3238 return dst - old_dst;
3239}
3240
willy tarreauc1f47532005-12-18 01:08:26 +01003241static int ishex(char s)
3242{
3243 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3244}
3245
3246/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3247char *check_replace_string(char *str)
3248{
3249 char *err = NULL;
3250 while (*str) {
3251 if (*str == '\\') {
3252 err = str; /* in case of a backslash, we return the pointer to it */
3253 str++;
3254 if (!*str)
3255 return err;
3256 else if (isdigit((int)*str))
3257 err = NULL;
3258 else if (*str == 'x') {
3259 str++;
3260 if (!ishex(*str))
3261 return err;
3262 str++;
3263 if (!ishex(*str))
3264 return err;
3265 err = NULL;
3266 }
3267 else {
3268 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3269 err = NULL;
3270 }
3271 }
3272 str++;
3273 }
3274 return err;
3275}
3276
3277
willy tarreau9fe663a2005-12-17 13:02:59 +01003278
willy tarreau0f7af912005-12-17 12:21:26 +01003279/*
3280 * manages the client FSM and its socket. BTW, it also tries to handle the
3281 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3282 * 0 else.
3283 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003284int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003285 int s = t->srv_state;
3286 int c = t->cli_state;
3287 struct buffer *req = t->req;
3288 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003289 int method_checked = 0;
3290 appsess *asession_temp = NULL;
3291 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003292
willy tarreau750a4722005-12-17 13:21:24 +01003293#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003294 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3295 cli_stnames[c], srv_stnames[s],
3296 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3297 t->crexpire.tv_sec, t->crexpire.tv_usec,
3298 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003299#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003300 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3301 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3302 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3303 //);
3304 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003305 /* now parse the partial (or complete) headers */
3306 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3307 char *ptr;
3308 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003309 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003310
willy tarreau5cbea6f2005-12-17 12:48:26 +01003311 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003312
willy tarreau0f7af912005-12-17 12:21:26 +01003313 /* look for the end of the current header */
3314 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3315 ptr++;
3316
willy tarreau5cbea6f2005-12-17 12:48:26 +01003317 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003318 int line, len;
3319 /* we can only get here after an end of headers */
3320 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003321
willy tarreaue39cd132005-12-17 13:00:18 +01003322 if (t->flags & SN_CLDENY) {
3323 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003324 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003325 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003326 if (!(t->flags & SN_ERR_MASK))
3327 t->flags |= SN_ERR_PRXCOND;
3328 if (!(t->flags & SN_FINST_MASK))
3329 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003330 return 1;
3331 }
3332
willy tarreau5cbea6f2005-12-17 12:48:26 +01003333 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003334 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3335 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003336 }
willy tarreau0f7af912005-12-17 12:21:26 +01003337
willy tarreau9fe663a2005-12-17 13:02:59 +01003338 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003339 if (t->cli_addr.ss_family == AF_INET) {
3340 unsigned char *pn;
3341 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3342 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3343 pn[0], pn[1], pn[2], pn[3]);
3344 buffer_replace2(req, req->h, req->h, trash, len);
3345 }
3346 else if (t->cli_addr.ss_family == AF_INET6) {
3347 char pn[INET6_ADDRSTRLEN];
3348 inet_ntop(AF_INET6,
3349 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3350 pn, sizeof(pn));
3351 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3352 buffer_replace2(req, req->h, req->h, trash, len);
3353 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003354 }
3355
willy tarreau25c4ea52005-12-18 00:49:49 +01003356 /* add a "connection: close" line if needed */
3357 if (t->proxy->options & PR_O_HTTP_CLOSE)
3358 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3359
willy tarreau982249e2005-12-18 00:57:06 +01003360 if (!memcmp(req->data, "POST ", 5)) {
3361 /* this is a POST request, which is not cacheable by default */
3362 t->flags |= SN_POST;
3363 }
willy tarreaucd878942005-12-17 13:27:43 +01003364
willy tarreau5cbea6f2005-12-17 12:48:26 +01003365 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003366 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003367
willy tarreau750a4722005-12-17 13:21:24 +01003368 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003369 /* FIXME: we'll set the client in a wait state while we try to
3370 * connect to the server. Is this really needed ? wouldn't it be
3371 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003372 //FD_CLR(t->cli_fd, StaticReadEvent);
3373 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003374
3375 /* FIXME: if we break here (as up to 1.1.23), having the client
3376 * shutdown its connection can lead to an abort further.
3377 * it's better to either return 1 or even jump directly to the
3378 * data state which will save one schedule.
3379 */
3380 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003381
3382 if (!t->proxy->clitimeout ||
3383 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3384 /* If the client has no timeout, or if the server is not ready yet,
3385 * and we know for sure that it can expire, then it's cleaner to
3386 * disable the timeout on the client side so that too low values
3387 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003388 *
3389 * FIXME-20050705: the server needs a way to re-enable this time-out
3390 * when it switches its state, otherwise a client can stay connected
3391 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003392 */
3393 tv_eternity(&t->crexpire);
3394
willy tarreau197e8ec2005-12-17 14:10:59 +01003395 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003396 }
willy tarreau0f7af912005-12-17 12:21:26 +01003397
Willy TARREAU13032e72006-03-12 17:31:45 +01003398 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3399 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003400 /* this is a partial header, let's wait for more to come */
3401 req->lr = ptr;
3402 break;
3403 }
willy tarreau0f7af912005-12-17 12:21:26 +01003404
willy tarreau5cbea6f2005-12-17 12:48:26 +01003405 /* now we know that *ptr is either \r or \n,
3406 * and that there are at least 1 char after it.
3407 */
3408 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3409 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3410 else
3411 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003412
willy tarreau5cbea6f2005-12-17 12:48:26 +01003413 /*
3414 * now we know that we have a full header ; we can do whatever
3415 * we want with these pointers :
3416 * req->h = beginning of header
3417 * ptr = end of header (first \r or \n)
3418 * req->lr = beginning of next line (next rep->h)
3419 * req->r = end of data (not used at this stage)
3420 */
willy tarreau0f7af912005-12-17 12:21:26 +01003421
willy tarreau12350152005-12-18 01:03:27 +01003422 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3423 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3424 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3425
3426 /* skip ; */
3427 request_line++;
3428
3429 /* look if we have a jsessionid */
3430
3431 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3432
3433 /* skip jsessionid= */
3434 request_line += t->proxy->appsession_name_len + 1;
3435
3436 /* First try if we allready have an appsession */
3437 asession_temp = &local_asession;
3438
3439 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3440 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3441 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3442 return 0;
3443 }
3444
3445 /* Copy the sessionid */
3446 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3447 asession_temp->sessid[t->proxy->appsession_len] = 0;
3448 asession_temp->serverid = NULL;
3449
3450 /* only do insert, if lookup fails */
3451 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3452 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3453 Alert("Not enough memory process_cli():asession:calloc().\n");
3454 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3455 return 0;
3456 }
3457 asession_temp->sessid = local_asession.sessid;
3458 asession_temp->serverid = local_asession.serverid;
3459 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003460 } /* end if (chtbl_lookup()) */
3461 else {
willy tarreau12350152005-12-18 01:03:27 +01003462 /*free wasted memory;*/
3463 pool_free_to(apools.sessid, local_asession.sessid);
3464 }
3465
3466 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3467 asession_temp->request_count++;
3468
3469#if defined(DEBUG_HASH)
3470 print_table(&(t->proxy->htbl_proxy));
3471#endif
3472
3473 if (asession_temp->serverid == NULL) {
3474 Alert("Found Application Session without matching server.\n");
3475 } else {
3476 struct server *srv = t->proxy->srv;
3477 while (srv) {
3478 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3479 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3480 /* we found the server and it's usable */
3481 t->flags &= ~SN_CK_MASK;
3482 t->flags |= SN_CK_VALID | SN_DIRECT;
3483 t->srv = srv;
3484 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003485 } else {
willy tarreau12350152005-12-18 01:03:27 +01003486 t->flags &= ~SN_CK_MASK;
3487 t->flags |= SN_CK_DOWN;
3488 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003489 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003490 srv = srv->next;
3491 }/* end while(srv) */
3492 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003493 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003494 else {
3495 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3496 }
willy tarreau598da412005-12-18 01:07:29 +01003497 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003498 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003499 else{
3500 //printf("No Methode-Header with Session-String\n");
3501 }
3502
willy tarreau8337c6b2005-12-17 13:41:01 +01003503 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003504 /* we have a complete HTTP request that we must log */
3505 int urilen;
3506
willy tarreaua1598082005-12-17 13:08:06 +01003507 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003508 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003509 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003510 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003511 if (!(t->flags & SN_ERR_MASK))
3512 t->flags |= SN_ERR_PRXCOND;
3513 if (!(t->flags & SN_FINST_MASK))
3514 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003515 return 1;
3516 }
3517
3518 urilen = ptr - req->h;
3519 if (urilen >= REQURI_LEN)
3520 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003521 memcpy(t->logs.uri, req->h, urilen);
3522 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003523
willy tarreaua1598082005-12-17 13:08:06 +01003524 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003525 sess_log(t);
3526 }
willy tarreau4302f492005-12-18 01:00:37 +01003527 else if (t->logs.logwait & LW_REQHDR) {
3528 struct cap_hdr *h;
3529 int len;
3530 for (h = t->proxy->req_cap; h; h = h->next) {
3531 if ((h->namelen + 2 <= ptr - req->h) &&
3532 (req->h[h->namelen] == ':') &&
3533 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3534
3535 if (t->req_cap[h->index] == NULL)
3536 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3537
3538 len = ptr - (req->h + h->namelen + 2);
3539 if (len > h->len)
3540 len = h->len;
3541
3542 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3543 t->req_cap[h->index][len]=0;
3544 }
3545 }
3546
3547 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003548
willy tarreau5cbea6f2005-12-17 12:48:26 +01003549 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003550
willy tarreau982249e2005-12-18 00:57:06 +01003551 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003552 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003553 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 +01003554 max = ptr - req->h;
3555 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003556 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003557 trash[len++] = '\n';
3558 write(1, trash, len);
3559 }
willy tarreau0f7af912005-12-17 12:21:26 +01003560
willy tarreau25c4ea52005-12-18 00:49:49 +01003561
3562 /* remove "connection: " if needed */
3563 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3564 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3565 delete_header = 1;
3566 }
3567
willy tarreau5cbea6f2005-12-17 12:48:26 +01003568 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003569 if (!delete_header && t->proxy->req_exp != NULL
3570 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003571 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003572 char term;
3573
3574 term = *ptr;
3575 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003576 exp = t->proxy->req_exp;
3577 do {
3578 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3579 switch (exp->action) {
3580 case ACT_ALLOW:
3581 if (!(t->flags & SN_CLDENY))
3582 t->flags |= SN_CLALLOW;
3583 break;
3584 case ACT_REPLACE:
3585 if (!(t->flags & SN_CLDENY)) {
3586 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3587 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3588 }
3589 break;
3590 case ACT_REMOVE:
3591 if (!(t->flags & SN_CLDENY))
3592 delete_header = 1;
3593 break;
3594 case ACT_DENY:
3595 if (!(t->flags & SN_CLALLOW))
3596 t->flags |= SN_CLDENY;
3597 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003598 case ACT_PASS: /* we simply don't deny this one */
3599 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003600 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003601 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003602 }
willy tarreaue39cd132005-12-17 13:00:18 +01003603 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003604 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003605 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003606
willy tarreau240afa62005-12-17 13:14:35 +01003607 /* Now look for cookies. Conforming to RFC2109, we have to support
3608 * attributes whose name begin with a '$', and associate them with
3609 * the right cookie, if we want to delete this cookie.
3610 * So there are 3 cases for each cookie read :
3611 * 1) it's a special attribute, beginning with a '$' : ignore it.
3612 * 2) it's a server id cookie that we *MAY* want to delete : save
3613 * some pointers on it (last semi-colon, beginning of cookie...)
3614 * 3) it's an application cookie : we *MAY* have to delete a previous
3615 * "special" cookie.
3616 * At the end of loop, if a "special" cookie remains, we may have to
3617 * remove it. If no application cookie persists in the header, we
3618 * *MUST* delete it
3619 */
willy tarreau12350152005-12-18 01:03:27 +01003620 if (!delete_header &&
3621 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003622 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003623 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003624 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003625 char *del_colon, *del_cookie, *colon;
3626 int app_cookies;
3627
willy tarreau5cbea6f2005-12-17 12:48:26 +01003628 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003629 colon = p1;
3630 /* del_cookie == NULL => nothing to be deleted */
3631 del_colon = del_cookie = NULL;
3632 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003633
3634 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003635 /* skip spaces and colons, but keep an eye on these ones */
3636 while (p1 < ptr) {
3637 if (*p1 == ';' || *p1 == ',')
3638 colon = p1;
3639 else if (!isspace((int)*p1))
3640 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003642 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003643
3644 if (p1 == ptr)
3645 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003646
3647 /* p1 is at the beginning of the cookie name */
3648 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003649 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003650 p2++;
3651
3652 if (p2 == ptr)
3653 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003654
3655 p3 = p2 + 1; /* skips the '=' sign */
3656 if (p3 == ptr)
3657 break;
3658
willy tarreau240afa62005-12-17 13:14:35 +01003659 p4 = p3;
3660 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003661 p4++;
3662
3663 /* here, we have the cookie name between p1 and p2,
3664 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003665 * we can process it :
3666 *
3667 * Cookie: NAME=VALUE;
3668 * | || || |
3669 * | || || +--> p4
3670 * | || |+-------> p3
3671 * | || +--------> p2
3672 * | |+------------> p1
3673 * | +-------------> colon
3674 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003675 */
3676
willy tarreau240afa62005-12-17 13:14:35 +01003677 if (*p1 == '$') {
3678 /* skip this one */
3679 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003680 else {
3681 /* first, let's see if we want to capture it */
3682 if (t->proxy->capture_name != NULL &&
3683 t->logs.cli_cookie == NULL &&
3684 (p4 - p1 >= t->proxy->capture_namelen) &&
3685 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3686 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003687
willy tarreau8337c6b2005-12-17 13:41:01 +01003688 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3689 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003690 } else {
3691 if (log_len > t->proxy->capture_len)
3692 log_len = t->proxy->capture_len;
3693 memcpy(t->logs.cli_cookie, p1, log_len);
3694 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003695 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003696 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003697
3698 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3699 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3700 /* Cool... it's the right one */
3701 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003702 char *delim;
3703
3704 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3705 * have the server ID betweek p3 and delim, and the original cookie between
3706 * delim+1 and p4. Otherwise, delim==p4 :
3707 *
3708 * Cookie: NAME=SRV~VALUE;
3709 * | || || | |
3710 * | || || | +--> p4
3711 * | || || +--------> delim
3712 * | || |+-----------> p3
3713 * | || +------------> p2
3714 * | |+----------------> p1
3715 * | +-----------------> colon
3716 * +------------------------> req->h
3717 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003718
willy tarreau0174f312005-12-18 01:02:42 +01003719 if (t->proxy->options & PR_O_COOK_PFX) {
3720 for (delim = p3; delim < p4; delim++)
3721 if (*delim == COOKIE_DELIM)
3722 break;
3723 }
3724 else
3725 delim = p4;
3726
3727
3728 /* Here, we'll look for the first running server which supports the cookie.
3729 * This allows to share a same cookie between several servers, for example
3730 * to dedicate backup servers to specific servers only.
3731 */
3732 while (srv) {
3733 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3734 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3735 /* we found the server and it's usable */
3736 t->flags &= ~SN_CK_MASK;
3737 t->flags |= SN_CK_VALID | SN_DIRECT;
3738 t->srv = srv;
3739 break;
willy tarreau12350152005-12-18 01:03:27 +01003740 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003741 /* we found a server, but it's down */
3742 t->flags &= ~SN_CK_MASK;
3743 t->flags |= SN_CK_DOWN;
3744 }
3745 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003746 srv = srv->next;
3747 }
3748
willy tarreau0174f312005-12-18 01:02:42 +01003749 if (!srv && !(t->flags & SN_CK_DOWN)) {
3750 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003751 t->flags &= ~SN_CK_MASK;
3752 t->flags |= SN_CK_INVALID;
3753 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003754
willy tarreau0174f312005-12-18 01:02:42 +01003755 /* depending on the cookie mode, we may have to either :
3756 * - delete the complete cookie if we're in insert+indirect mode, so that
3757 * the server never sees it ;
3758 * - remove the server id from the cookie value, and tag the cookie as an
3759 * application cookie so that it does not get accidentely removed later,
3760 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003761 */
willy tarreau0174f312005-12-18 01:02:42 +01003762 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3763 buffer_replace2(req, p3, delim + 1, NULL, 0);
3764 p4 -= (delim + 1 - p3);
3765 ptr -= (delim + 1 - p3);
3766 del_cookie = del_colon = NULL;
3767 app_cookies++; /* protect the header from deletion */
3768 }
3769 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003770 (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 +01003771 del_cookie = p1;
3772 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003773 }
willy tarreau12350152005-12-18 01:03:27 +01003774 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003775 /* now we know that we must keep this cookie since it's
3776 * not ours. But if we wanted to delete our cookie
3777 * earlier, we cannot remove the complete header, but we
3778 * can remove the previous block itself.
3779 */
3780 app_cookies++;
3781
3782 if (del_cookie != NULL) {
3783 buffer_replace2(req, del_cookie, p1, NULL, 0);
3784 p4 -= (p1 - del_cookie);
3785 ptr -= (p1 - del_cookie);
3786 del_cookie = del_colon = NULL;
3787 }
willy tarreau240afa62005-12-17 13:14:35 +01003788 }
willy tarreau12350152005-12-18 01:03:27 +01003789
3790 if ((t->proxy->appsession_name != NULL) &&
3791 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3792 /* first, let's see if the cookie is our appcookie*/
3793
3794 /* Cool... it's the right one */
3795
3796 asession_temp = &local_asession;
3797
3798 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3799 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3800 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3801 return 0;
3802 }
3803
3804 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3805 asession_temp->sessid[t->proxy->appsession_len] = 0;
3806 asession_temp->serverid = NULL;
3807
3808 /* only do insert, if lookup fails */
3809 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3810 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3811 Alert("Not enough memory process_cli():asession:calloc().\n");
3812 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3813 return 0;
3814 }
3815
3816 asession_temp->sessid = local_asession.sessid;
3817 asession_temp->serverid = local_asession.serverid;
3818 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3819 }
3820 else{
3821 /* free wasted memory */
3822 pool_free_to(apools.sessid, local_asession.sessid);
3823 }
3824
3825 if (asession_temp->serverid == NULL) {
3826 Alert("Found Application Session without matching server.\n");
3827 } else {
3828 struct server *srv = t->proxy->srv;
3829 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003830 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003831 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3832 /* we found the server and it's usable */
3833 t->flags &= ~SN_CK_MASK;
3834 t->flags |= SN_CK_VALID | SN_DIRECT;
3835 t->srv = srv;
3836 break;
3837 } else {
3838 t->flags &= ~SN_CK_MASK;
3839 t->flags |= SN_CK_DOWN;
3840 }
3841 }
3842 srv = srv->next;
3843 }/* end while(srv) */
3844 }/* end else if server == NULL */
3845
3846 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003847 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003848 }
willy tarreau240afa62005-12-17 13:14:35 +01003849
willy tarreau5cbea6f2005-12-17 12:48:26 +01003850 /* we'll have to look for another cookie ... */
3851 p1 = p4;
3852 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003853
3854 /* There's no more cookie on this line.
3855 * We may have marked the last one(s) for deletion.
3856 * We must do this now in two ways :
3857 * - if there is no app cookie, we simply delete the header ;
3858 * - if there are app cookies, we must delete the end of the
3859 * string properly, including the colon/semi-colon before
3860 * the cookie name.
3861 */
3862 if (del_cookie != NULL) {
3863 if (app_cookies) {
3864 buffer_replace2(req, del_colon, ptr, NULL, 0);
3865 /* WARNING! <ptr> becomes invalid for now. If some code
3866 * below needs to rely on it before the end of the global
3867 * header loop, we need to correct it with this code :
3868 * ptr = del_colon;
3869 */
3870 }
3871 else
3872 delete_header = 1;
3873 }
3874 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003875
3876 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003877 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003878 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003879 }
willy tarreau240afa62005-12-17 13:14:35 +01003880 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3881
willy tarreau5cbea6f2005-12-17 12:48:26 +01003882 req->h = req->lr;
3883 } /* while (req->lr < req->r) */
3884
3885 /* end of header processing (even if incomplete) */
3886
willy tarreauef900ab2005-12-17 12:52:52 +01003887 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3888 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3889 * full. We cannot loop here since event_cli_read will disable it only if
3890 * req->l == rlim-data
3891 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003892 FD_SET(t->cli_fd, StaticReadEvent);
3893 if (t->proxy->clitimeout)
3894 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3895 else
3896 tv_eternity(&t->crexpire);
3897 }
3898
willy tarreaue39cd132005-12-17 13:00:18 +01003899 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003900 * won't be able to free more later, so the session will never terminate.
3901 */
willy tarreaue39cd132005-12-17 13:00:18 +01003902 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003903 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003904 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003905 if (!(t->flags & SN_ERR_MASK))
3906 t->flags |= SN_ERR_PRXCOND;
3907 if (!(t->flags & SN_FINST_MASK))
3908 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003909 return 1;
3910 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003911 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003912 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003913 tv_eternity(&t->crexpire);
3914 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003915 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003916 if (!(t->flags & SN_ERR_MASK))
3917 t->flags |= SN_ERR_CLICL;
3918 if (!(t->flags & SN_FINST_MASK))
3919 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003920 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003921 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003922 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3923
3924 /* read timeout : give up with an error message.
3925 */
3926 t->logs.status = 408;
3927 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003928 if (!(t->flags & SN_ERR_MASK))
3929 t->flags |= SN_ERR_CLITO;
3930 if (!(t->flags & SN_FINST_MASK))
3931 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003932 return 1;
3933 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003934
3935 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003936 }
3937 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003938 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003939 /* FIXME: this error handling is partly buggy because we always report
3940 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3941 * or HEADER phase. BTW, it's not logical to expire the client while
3942 * we're waiting for the server to connect.
3943 */
willy tarreau0f7af912005-12-17 12:21:26 +01003944 /* read or write error */
3945 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003946 tv_eternity(&t->crexpire);
3947 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003948 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003949 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003950 if (!(t->flags & SN_ERR_MASK))
3951 t->flags |= SN_ERR_CLICL;
3952 if (!(t->flags & SN_FINST_MASK))
3953 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003954 return 1;
3955 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003956 /* last read, or end of server write */
3957 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003958 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003959 tv_eternity(&t->crexpire);
3960 shutdown(t->cli_fd, SHUT_RD);
3961 t->cli_state = CL_STSHUTR;
3962 return 1;
3963 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003964 /* last server read and buffer empty */
3965 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003966 FD_CLR(t->cli_fd, StaticWriteEvent);
3967 tv_eternity(&t->cwexpire);
3968 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003969 /* We must ensure that the read part is still alive when switching
3970 * to shutw */
3971 FD_SET(t->cli_fd, StaticReadEvent);
3972 if (t->proxy->clitimeout)
3973 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003974 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003975 //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 +01003976 return 1;
3977 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003978 /* read timeout */
3979 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3980 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003981 tv_eternity(&t->crexpire);
3982 shutdown(t->cli_fd, SHUT_RD);
3983 t->cli_state = CL_STSHUTR;
3984 if (!(t->flags & SN_ERR_MASK))
3985 t->flags |= SN_ERR_CLITO;
3986 if (!(t->flags & SN_FINST_MASK))
3987 t->flags |= SN_FINST_D;
3988 return 1;
3989 }
3990 /* write timeout */
3991 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3992 FD_CLR(t->cli_fd, StaticWriteEvent);
3993 tv_eternity(&t->cwexpire);
3994 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003995 /* We must ensure that the read part is still alive when switching
3996 * to shutw */
3997 FD_SET(t->cli_fd, StaticReadEvent);
3998 if (t->proxy->clitimeout)
3999 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4000
willy tarreau036e1ce2005-12-17 13:46:33 +01004001 t->cli_state = CL_STSHUTW;
4002 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004003 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004004 if (!(t->flags & SN_FINST_MASK))
4005 t->flags |= SN_FINST_D;
4006 return 1;
4007 }
willy tarreau0f7af912005-12-17 12:21:26 +01004008
willy tarreauc58fc692005-12-17 14:13:08 +01004009 if (req->l >= req->rlim - req->data) {
4010 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004011 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004012 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004013 FD_CLR(t->cli_fd, StaticReadEvent);
4014 tv_eternity(&t->crexpire);
4015 }
4016 }
4017 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004018 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004019 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4020 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004021 if (!t->proxy->clitimeout ||
4022 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4023 /* If the client has no timeout, or if the server not ready yet, and we
4024 * know for sure that it can expire, then it's cleaner to disable the
4025 * timeout on the client side so that too low values cannot make the
4026 * sessions abort too early.
4027 */
willy tarreau0f7af912005-12-17 12:21:26 +01004028 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004029 else
4030 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004031 }
4032 }
4033
4034 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004035 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004036 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4037 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4038 tv_eternity(&t->cwexpire);
4039 }
4040 }
4041 else { /* buffer not empty */
4042 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4043 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004044 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004045 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004046 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4047 t->crexpire = t->cwexpire;
4048 }
willy tarreau0f7af912005-12-17 12:21:26 +01004049 else
4050 tv_eternity(&t->cwexpire);
4051 }
4052 }
4053 return 0; /* other cases change nothing */
4054 }
4055 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004056 if (t->res_cw == RES_ERROR) {
4057 tv_eternity(&t->cwexpire);
4058 fd_delete(t->cli_fd);
4059 t->cli_state = CL_STCLOSE;
4060 if (!(t->flags & SN_ERR_MASK))
4061 t->flags |= SN_ERR_CLICL;
4062 if (!(t->flags & SN_FINST_MASK))
4063 t->flags |= SN_FINST_D;
4064 return 1;
4065 }
4066 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004067 tv_eternity(&t->cwexpire);
4068 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004069 t->cli_state = CL_STCLOSE;
4070 return 1;
4071 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004072 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4073 tv_eternity(&t->cwexpire);
4074 fd_delete(t->cli_fd);
4075 t->cli_state = CL_STCLOSE;
4076 if (!(t->flags & SN_ERR_MASK))
4077 t->flags |= SN_ERR_CLITO;
4078 if (!(t->flags & SN_FINST_MASK))
4079 t->flags |= SN_FINST_D;
4080 return 1;
4081 }
willy tarreau0f7af912005-12-17 12:21:26 +01004082 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004083 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004084 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4085 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4086 tv_eternity(&t->cwexpire);
4087 }
4088 }
4089 else { /* buffer not empty */
4090 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4091 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004092 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004093 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004094 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4095 t->crexpire = t->cwexpire;
4096 }
willy tarreau0f7af912005-12-17 12:21:26 +01004097 else
4098 tv_eternity(&t->cwexpire);
4099 }
4100 }
4101 return 0;
4102 }
4103 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004104 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004105 tv_eternity(&t->crexpire);
4106 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004107 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004108 if (!(t->flags & SN_ERR_MASK))
4109 t->flags |= SN_ERR_CLICL;
4110 if (!(t->flags & SN_FINST_MASK))
4111 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004112 return 1;
4113 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004114 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4115 tv_eternity(&t->crexpire);
4116 fd_delete(t->cli_fd);
4117 t->cli_state = CL_STCLOSE;
4118 return 1;
4119 }
4120 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4121 tv_eternity(&t->crexpire);
4122 fd_delete(t->cli_fd);
4123 t->cli_state = CL_STCLOSE;
4124 if (!(t->flags & SN_ERR_MASK))
4125 t->flags |= SN_ERR_CLITO;
4126 if (!(t->flags & SN_FINST_MASK))
4127 t->flags |= SN_FINST_D;
4128 return 1;
4129 }
willy tarreauef900ab2005-12-17 12:52:52 +01004130 else if (req->l >= req->rlim - req->data) {
4131 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004132
4133 /* FIXME-20050705: is it possible for a client to maintain a session
4134 * after the timeout by sending more data after it receives a close ?
4135 */
4136
willy tarreau0f7af912005-12-17 12:21:26 +01004137 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004138 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004139 FD_CLR(t->cli_fd, StaticReadEvent);
4140 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004141 //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 +01004142 }
4143 }
4144 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004145 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004146 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4147 FD_SET(t->cli_fd, StaticReadEvent);
4148 if (t->proxy->clitimeout)
4149 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4150 else
4151 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004152 //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 +01004153 }
4154 }
4155 return 0;
4156 }
4157 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004158 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004159 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004160 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 +01004161 write(1, trash, len);
4162 }
4163 return 0;
4164 }
4165 return 0;
4166}
4167
4168
4169/*
4170 * manages the server FSM and its socket. It returns 1 if a state has changed
4171 * (and a resync may be needed), 0 else.
4172 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004173int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004174 int s = t->srv_state;
4175 int c = t->cli_state;
4176 struct buffer *req = t->req;
4177 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004178 appsess *asession_temp = NULL;
4179 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004180 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004181
willy tarreau750a4722005-12-17 13:21:24 +01004182#ifdef DEBUG_FULL
4183 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4184#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004185 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4186 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4187 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4188 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004189 if (s == SV_STIDLE) {
4190 if (c == CL_STHEADERS)
4191 return 0; /* stay in idle, waiting for data to reach the client side */
4192 else if (c == CL_STCLOSE ||
4193 c == CL_STSHUTW ||
4194 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4195 tv_eternity(&t->cnexpire);
4196 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004197 if (!(t->flags & SN_ERR_MASK))
4198 t->flags |= SN_ERR_CLICL;
4199 if (!(t->flags & SN_FINST_MASK))
4200 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004201 return 1;
4202 }
4203 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004204 /* initiate a connection to the server */
4205 conn_err = connect_server(t);
4206 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004207 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4208 t->srv_state = SV_STCONN;
4209 }
4210 else { /* try again */
4211 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004212 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004213 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004214 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004215 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4216 t->flags &= ~SN_CK_MASK;
4217 t->flags |= SN_CK_DOWN;
4218 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004219 }
4220
willy tarreaub1285d52005-12-18 01:20:14 +01004221 conn_err = connect_server(t);
4222 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004223 t->srv_state = SV_STCONN;
4224 break;
4225 }
4226 }
4227 if (t->conn_retries < 0) {
4228 /* if conn_retries < 0 or other error, let's abort */
4229 tv_eternity(&t->cnexpire);
4230 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004231 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004232 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004233 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004234 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004235 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004236 if (!(t->flags & SN_FINST_MASK))
4237 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004238 }
4239 }
4240 return 1;
4241 }
4242 }
4243 else if (s == SV_STCONN) { /* connection in progress */
4244 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004245 //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 +01004246 return 0; /* nothing changed */
4247 }
4248 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4249 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4250 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004251 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004252 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004253 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004254 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004255 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004256 if (t->conn_retries >= 0) {
4257 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004258 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004259 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004260 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4261 t->flags &= ~SN_CK_MASK;
4262 t->flags |= SN_CK_DOWN;
4263 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004264 }
willy tarreaub1285d52005-12-18 01:20:14 +01004265 conn_err = connect_server(t);
4266 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004267 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004268 }
willy tarreaub1285d52005-12-18 01:20:14 +01004269 else if (t->res_sw == RES_SILENT)
4270 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4271 else
4272 conn_err = SN_ERR_SRVCL; // it was a connect error.
4273
willy tarreau0f7af912005-12-17 12:21:26 +01004274 /* if conn_retries < 0 or other error, let's abort */
4275 tv_eternity(&t->cnexpire);
4276 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004277 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004278 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004279 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004280 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004281 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004282 if (!(t->flags & SN_FINST_MASK))
4283 t->flags |= SN_FINST_C;
willy tarreau704f32b2006-04-07 17:37:55 +02004284 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004285 return 1;
4286 }
4287 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004288 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004289
willy tarreau0f7af912005-12-17 12:21:26 +01004290 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004291 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004292 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004293 tv_eternity(&t->swexpire);
4294 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004295 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004296 if (t->proxy->srvtimeout) {
4297 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4298 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4299 t->srexpire = t->swexpire;
4300 }
4301 else
4302 tv_eternity(&t->swexpire);
4303 }
willy tarreau0f7af912005-12-17 12:21:26 +01004304
4305 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4306 FD_SET(t->srv_fd, StaticReadEvent);
4307 if (t->proxy->srvtimeout)
4308 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4309 else
4310 tv_eternity(&t->srexpire);
4311
4312 t->srv_state = SV_STDATA;
willy tarreaub1c331f2006-04-07 18:23:29 +02004313 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004314 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004315
4316 /* if the user wants to log as soon as possible, without counting
4317 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004318 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004319 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4320 sess_log(t);
4321 }
willy tarreau0f7af912005-12-17 12:21:26 +01004322 }
willy tarreauef900ab2005-12-17 12:52:52 +01004323 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004324 t->srv_state = SV_STHEADERS;
willy tarreaub1c331f2006-04-07 18:23:29 +02004325 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004326 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4327 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004328 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004329 return 1;
4330 }
4331 }
4332 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004333 /* now parse the partial (or complete) headers */
4334 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4335 char *ptr;
4336 int delete_header;
4337
4338 ptr = rep->lr;
4339
4340 /* look for the end of the current header */
4341 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4342 ptr++;
4343
4344 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004345 int line, len;
4346
4347 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004348
4349 /* first, we'll block if security checks have caught nasty things */
4350 if (t->flags & SN_CACHEABLE) {
4351 if ((t->flags & SN_CACHE_COOK) &&
4352 (t->flags & SN_SCK_ANY) &&
4353 (t->proxy->options & PR_O_CHK_CACHE)) {
4354
4355 /* we're in presence of a cacheable response containing
4356 * a set-cookie header. We'll block it as requested by
4357 * the 'checkcache' option, and send an alert.
4358 */
4359 tv_eternity(&t->srexpire);
4360 tv_eternity(&t->swexpire);
4361 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004362 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004363 t->srv_state = SV_STCLOSE;
4364 t->logs.status = 502;
4365 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4366 if (!(t->flags & SN_ERR_MASK))
4367 t->flags |= SN_ERR_PRXCOND;
4368 if (!(t->flags & SN_FINST_MASK))
4369 t->flags |= SN_FINST_H;
4370
4371 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4372 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4373
willy tarreau704f32b2006-04-07 17:37:55 +02004374 /* TODO : check if there are pending connections on this server */
willy tarreau97f58572005-12-18 00:53:44 +01004375 return 1;
4376 }
4377 }
4378
willy tarreau982249e2005-12-18 00:57:06 +01004379 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4380 if (t->flags & SN_SVDENY) {
4381 tv_eternity(&t->srexpire);
4382 tv_eternity(&t->swexpire);
4383 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004384 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004385 t->srv_state = SV_STCLOSE;
4386 t->logs.status = 502;
4387 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4388 if (!(t->flags & SN_ERR_MASK))
4389 t->flags |= SN_ERR_PRXCOND;
4390 if (!(t->flags & SN_FINST_MASK))
4391 t->flags |= SN_FINST_H;
willy tarreau704f32b2006-04-07 17:37:55 +02004392 /* TODO : check if there are pending connections on this server */
willy tarreau982249e2005-12-18 00:57:06 +01004393 return 1;
4394 }
4395
willy tarreau5cbea6f2005-12-17 12:48:26 +01004396 /* we'll have something else to do here : add new headers ... */
4397
willy tarreaucd878942005-12-17 13:27:43 +01004398 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4399 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004400 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004401 * insert a set-cookie here, except if we want to insert only on POST
4402 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004403 */
willy tarreau750a4722005-12-17 13:21:24 +01004404 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004405 t->proxy->cookie_name,
4406 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004407
willy tarreau036e1ce2005-12-17 13:46:33 +01004408 t->flags |= SN_SCK_INSERTED;
4409
willy tarreau750a4722005-12-17 13:21:24 +01004410 /* Here, we will tell an eventual cache on the client side that we don't
4411 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4412 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4413 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4414 */
willy tarreau240afa62005-12-17 13:14:35 +01004415 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004416 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4417 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004418
4419 if (rep->data + rep->l < rep->h)
4420 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4421 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004422 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004423 }
4424
4425 /* headers to be added */
4426 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004427 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4428 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004429 }
4430
willy tarreau25c4ea52005-12-18 00:49:49 +01004431 /* add a "connection: close" line if needed */
4432 if (t->proxy->options & PR_O_HTTP_CLOSE)
4433 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4434
willy tarreau5cbea6f2005-12-17 12:48:26 +01004435 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004436 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004437 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004438
Willy TARREAU767ba712006-03-01 22:40:50 +01004439 /* client connection already closed or option 'httpclose' required :
4440 * we close the server's outgoing connection right now.
4441 */
4442 if ((req->l == 0) &&
4443 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4444 FD_CLR(t->srv_fd, StaticWriteEvent);
4445 tv_eternity(&t->swexpire);
4446
4447 /* We must ensure that the read part is still alive when switching
4448 * to shutw */
4449 FD_SET(t->srv_fd, StaticReadEvent);
4450 if (t->proxy->srvtimeout)
4451 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4452
4453 shutdown(t->srv_fd, SHUT_WR);
4454 t->srv_state = SV_STSHUTW;
4455 }
4456
willy tarreau25c4ea52005-12-18 00:49:49 +01004457 /* if the user wants to log as soon as possible, without counting
4458 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004459 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004460 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4461 t->logs.bytes = rep->h - rep->data;
4462 sess_log(t);
4463 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004464 break;
4465 }
4466
4467 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4468 if (ptr > rep->r - 2) {
4469 /* this is a partial header, let's wait for more to come */
4470 rep->lr = ptr;
4471 break;
4472 }
4473
4474 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4475 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4476
4477 /* now we know that *ptr is either \r or \n,
4478 * and that there are at least 1 char after it.
4479 */
4480 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4481 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4482 else
4483 rep->lr = ptr + 2; /* \r\n or \n\r */
4484
4485 /*
4486 * now we know that we have a full header ; we can do whatever
4487 * we want with these pointers :
4488 * rep->h = beginning of header
4489 * ptr = end of header (first \r or \n)
4490 * rep->lr = beginning of next line (next rep->h)
4491 * rep->r = end of data (not used at this stage)
4492 */
4493
willy tarreaua1598082005-12-17 13:08:06 +01004494
willy tarreau982249e2005-12-18 00:57:06 +01004495 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004496 t->logs.logwait &= ~LW_RESP;
4497 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004498 switch (t->logs.status) {
4499 case 200:
4500 case 203:
4501 case 206:
4502 case 300:
4503 case 301:
4504 case 410:
4505 /* RFC2616 @13.4:
4506 * "A response received with a status code of
4507 * 200, 203, 206, 300, 301 or 410 MAY be stored
4508 * by a cache (...) unless a cache-control
4509 * directive prohibits caching."
4510 *
4511 * RFC2616 @9.5: POST method :
4512 * "Responses to this method are not cacheable,
4513 * unless the response includes appropriate
4514 * Cache-Control or Expires header fields."
4515 */
4516 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4517 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4518 break;
4519 default:
4520 break;
4521 }
willy tarreau4302f492005-12-18 01:00:37 +01004522 }
4523 else if (t->logs.logwait & LW_RSPHDR) {
4524 struct cap_hdr *h;
4525 int len;
4526 for (h = t->proxy->rsp_cap; h; h = h->next) {
4527 if ((h->namelen + 2 <= ptr - rep->h) &&
4528 (rep->h[h->namelen] == ':') &&
4529 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4530
4531 if (t->rsp_cap[h->index] == NULL)
4532 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4533
4534 len = ptr - (rep->h + h->namelen + 2);
4535 if (len > h->len)
4536 len = h->len;
4537
4538 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4539 t->rsp_cap[h->index][len]=0;
4540 }
4541 }
4542
willy tarreaua1598082005-12-17 13:08:06 +01004543 }
4544
willy tarreau5cbea6f2005-12-17 12:48:26 +01004545 delete_header = 0;
4546
willy tarreau982249e2005-12-18 00:57:06 +01004547 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004548 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004549 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 +01004550 max = ptr - rep->h;
4551 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004552 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004553 trash[len++] = '\n';
4554 write(1, trash, len);
4555 }
4556
willy tarreau25c4ea52005-12-18 00:49:49 +01004557 /* remove "connection: " if needed */
4558 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4559 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4560 delete_header = 1;
4561 }
4562
willy tarreau5cbea6f2005-12-17 12:48:26 +01004563 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004564 if (!delete_header && t->proxy->rsp_exp != NULL
4565 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004566 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004567 char term;
4568
4569 term = *ptr;
4570 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004571 exp = t->proxy->rsp_exp;
4572 do {
4573 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4574 switch (exp->action) {
4575 case ACT_ALLOW:
4576 if (!(t->flags & SN_SVDENY))
4577 t->flags |= SN_SVALLOW;
4578 break;
4579 case ACT_REPLACE:
4580 if (!(t->flags & SN_SVDENY)) {
4581 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4582 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4583 }
4584 break;
4585 case ACT_REMOVE:
4586 if (!(t->flags & SN_SVDENY))
4587 delete_header = 1;
4588 break;
4589 case ACT_DENY:
4590 if (!(t->flags & SN_SVALLOW))
4591 t->flags |= SN_SVDENY;
4592 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004593 case ACT_PASS: /* we simply don't deny this one */
4594 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004595 }
4596 break;
4597 }
willy tarreaue39cd132005-12-17 13:00:18 +01004598 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004599 *ptr = term; /* restore the string terminator */
4600 }
4601
willy tarreau97f58572005-12-18 00:53:44 +01004602 /* check for cache-control: or pragma: headers */
4603 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4604 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4605 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4606 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4607 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004608 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004609 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4610 else {
4611 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004612 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004613 t->flags &= ~SN_CACHE_COOK;
4614 }
4615 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004616 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004617 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004618 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004619 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4620 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004621 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004622 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004623 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4624 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4625 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4626 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4627 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4628 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004629 }
4630 }
4631 }
4632
willy tarreau5cbea6f2005-12-17 12:48:26 +01004633 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004634 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004635 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004636 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004637 char *p1, *p2, *p3, *p4;
4638
willy tarreau97f58572005-12-18 00:53:44 +01004639 t->flags |= SN_SCK_ANY;
4640
willy tarreau5cbea6f2005-12-17 12:48:26 +01004641 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4642
4643 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004644 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004645 p1++;
4646
4647 if (p1 == ptr || *p1 == ';') /* end of cookie */
4648 break;
4649
4650 /* p1 is at the beginning of the cookie name */
4651 p2 = p1;
4652
4653 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4654 p2++;
4655
4656 if (p2 == ptr || *p2 == ';') /* next cookie */
4657 break;
4658
4659 p3 = p2 + 1; /* skips the '=' sign */
4660 if (p3 == ptr)
4661 break;
4662
4663 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004664 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004665 p4++;
4666
4667 /* here, we have the cookie name between p1 and p2,
4668 * and its value between p3 and p4.
4669 * we can process it.
4670 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004671
4672 /* first, let's see if we want to capture it */
4673 if (t->proxy->capture_name != NULL &&
4674 t->logs.srv_cookie == NULL &&
4675 (p4 - p1 >= t->proxy->capture_namelen) &&
4676 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4677 int log_len = p4 - p1;
4678
4679 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4680 Alert("HTTP logging : out of memory.\n");
4681 }
4682
4683 if (log_len > t->proxy->capture_len)
4684 log_len = t->proxy->capture_len;
4685 memcpy(t->logs.srv_cookie, p1, log_len);
4686 t->logs.srv_cookie[log_len] = 0;
4687 }
4688
4689 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4690 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004691 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004692 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004693
4694 /* If the cookie is in insert mode on a known server, we'll delete
4695 * this occurrence because we'll insert another one later.
4696 * We'll delete it too if the "indirect" option is set and we're in
4697 * a direct access. */
4698 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004699 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004700 /* this header must be deleted */
4701 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004702 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004703 }
4704 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4705 /* replace bytes p3->p4 with the cookie name associated
4706 * with this server since we know it.
4707 */
4708 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004709 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004710 }
willy tarreau0174f312005-12-18 01:02:42 +01004711 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4712 /* insert the cookie name associated with this server
4713 * before existing cookie, and insert a delimitor between them..
4714 */
4715 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4716 p3[t->srv->cklen] = COOKIE_DELIM;
4717 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4718 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004719 break;
4720 }
willy tarreau12350152005-12-18 01:03:27 +01004721
4722 /* first, let's see if the cookie is our appcookie*/
4723 if ((t->proxy->appsession_name != NULL) &&
4724 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4725
4726 /* Cool... it's the right one */
4727
willy tarreaub952e1d2005-12-18 01:31:20 +01004728 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004729 asession_temp = &local_asession;
4730
willy tarreaub952e1d2005-12-18 01:31:20 +01004731 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004732 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4733 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4734 }
4735 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4736 asession_temp->sessid[t->proxy->appsession_len] = 0;
4737 asession_temp->serverid = NULL;
4738
4739 /* only do insert, if lookup fails */
4740 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4741 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4742 Alert("Not enought Memory process_srv():asession:calloc().\n");
4743 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4744 return 0;
4745 }
4746 asession_temp->sessid = local_asession.sessid;
4747 asession_temp->serverid = local_asession.serverid;
4748 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004749 }/* end if (chtbl_lookup()) */
4750 else {
willy tarreau12350152005-12-18 01:03:27 +01004751 /* free wasted memory */
4752 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004753 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004754
willy tarreaub952e1d2005-12-18 01:31:20 +01004755 if (asession_temp->serverid == NULL) {
4756 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004757 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4758 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4759 }
4760 asession_temp->serverid[0] = '\0';
4761 }
4762
willy tarreaub952e1d2005-12-18 01:31:20 +01004763 if (asession_temp->serverid[0] == '\0')
4764 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004765
4766 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4767
4768#if defined(DEBUG_HASH)
4769 print_table(&(t->proxy->htbl_proxy));
4770#endif
4771 break;
4772 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004773 else {
4774 // fprintf(stderr,"Ignoring unknown cookie : ");
4775 // write(2, p1, p2-p1);
4776 // fprintf(stderr," = ");
4777 // write(2, p3, p4-p3);
4778 // fprintf(stderr,"\n");
4779 }
4780 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4781 } /* we're now at the end of the cookie value */
4782 } /* end of cookie processing */
4783
willy tarreau97f58572005-12-18 00:53:44 +01004784 /* check for any set-cookie in case we check for cacheability */
4785 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4786 (t->proxy->options & PR_O_CHK_CACHE) &&
4787 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4788 t->flags |= SN_SCK_ANY;
4789 }
4790
willy tarreau5cbea6f2005-12-17 12:48:26 +01004791 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004792 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004793 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004794
willy tarreau5cbea6f2005-12-17 12:48:26 +01004795 rep->h = rep->lr;
4796 } /* while (rep->lr < rep->r) */
4797
4798 /* end of header processing (even if incomplete) */
4799
willy tarreauef900ab2005-12-17 12:52:52 +01004800 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4801 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4802 * full. We cannot loop here since event_srv_read will disable it only if
4803 * rep->l == rlim-data
4804 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004805 FD_SET(t->srv_fd, StaticReadEvent);
4806 if (t->proxy->srvtimeout)
4807 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4808 else
4809 tv_eternity(&t->srexpire);
4810 }
willy tarreau0f7af912005-12-17 12:21:26 +01004811
willy tarreau8337c6b2005-12-17 13:41:01 +01004812 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004813 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004814 tv_eternity(&t->srexpire);
4815 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004816 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004817 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004818 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004819 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004820 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004821 if (!(t->flags & SN_ERR_MASK))
4822 t->flags |= SN_ERR_SRVCL;
4823 if (!(t->flags & SN_FINST_MASK))
4824 t->flags |= SN_FINST_H;
willy tarreau704f32b2006-04-07 17:37:55 +02004825 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004826 return 1;
4827 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004828 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004829 * since we are in header mode, if there's no space left for headers, we
4830 * won't be able to free more later, so the session will never terminate.
4831 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004832 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 +01004833 FD_CLR(t->srv_fd, StaticReadEvent);
4834 tv_eternity(&t->srexpire);
4835 shutdown(t->srv_fd, SHUT_RD);
4836 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004837 //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 +01004838 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004839 }
4840 /* read timeout : return a 504 to the client.
4841 */
4842 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4843 tv_eternity(&t->srexpire);
4844 tv_eternity(&t->swexpire);
4845 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004846 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01004847 t->srv_state = SV_STCLOSE;
4848 t->logs.status = 504;
4849 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004850 if (!(t->flags & SN_ERR_MASK))
4851 t->flags |= SN_ERR_SRVTO;
4852 if (!(t->flags & SN_FINST_MASK))
4853 t->flags |= SN_FINST_H;
willy tarreau704f32b2006-04-07 17:37:55 +02004854 /* TODO : check if there are pending connections on this server */
willy tarreau8337c6b2005-12-17 13:41:01 +01004855 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004856 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004857 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004858 /* FIXME!!! here, we don't want to switch to SHUTW if the
4859 * client shuts read too early, because we may still have
4860 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004861 * The side-effect is that if the client completely closes its
4862 * connection during SV_STHEADER, the connection to the server
4863 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004864 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004865 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004866 FD_CLR(t->srv_fd, StaticWriteEvent);
4867 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004868
4869 /* We must ensure that the read part is still alive when switching
4870 * to shutw */
4871 FD_SET(t->srv_fd, StaticReadEvent);
4872 if (t->proxy->srvtimeout)
4873 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4874
willy tarreau0f7af912005-12-17 12:21:26 +01004875 shutdown(t->srv_fd, SHUT_WR);
4876 t->srv_state = SV_STSHUTW;
4877 return 1;
4878 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004879 /* write timeout */
4880 /* FIXME!!! here, we don't want to switch to SHUTW if the
4881 * client shuts read too early, because we may still have
4882 * some work to do on the headers.
4883 */
4884 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4885 FD_CLR(t->srv_fd, StaticWriteEvent);
4886 tv_eternity(&t->swexpire);
4887 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004888 /* We must ensure that the read part is still alive when switching
4889 * to shutw */
4890 FD_SET(t->srv_fd, StaticReadEvent);
4891 if (t->proxy->srvtimeout)
4892 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4893
4894 /* We must ensure that the read part is still alive when switching
4895 * to shutw */
4896 FD_SET(t->srv_fd, StaticReadEvent);
4897 if (t->proxy->srvtimeout)
4898 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4899
willy tarreau036e1ce2005-12-17 13:46:33 +01004900 t->srv_state = SV_STSHUTW;
4901 if (!(t->flags & SN_ERR_MASK))
4902 t->flags |= SN_ERR_SRVTO;
4903 if (!(t->flags & SN_FINST_MASK))
4904 t->flags |= SN_FINST_H;
4905 return 1;
4906 }
willy tarreau0f7af912005-12-17 12:21:26 +01004907
4908 if (req->l == 0) {
4909 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4910 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4911 tv_eternity(&t->swexpire);
4912 }
4913 }
4914 else { /* client buffer not empty */
4915 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4916 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004917 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004918 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004919 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4920 t->srexpire = t->swexpire;
4921 }
willy tarreau0f7af912005-12-17 12:21:26 +01004922 else
4923 tv_eternity(&t->swexpire);
4924 }
4925 }
4926
willy tarreau5cbea6f2005-12-17 12:48:26 +01004927 /* be nice with the client side which would like to send a complete header
4928 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4929 * would read all remaining data at once ! The client should not write past rep->lr
4930 * when the server is in header state.
4931 */
4932 //return header_processed;
4933 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004934 }
4935 else if (s == SV_STDATA) {
4936 /* read or write error */
4937 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004938 tv_eternity(&t->srexpire);
4939 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004940 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02004941 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004942 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004943 if (!(t->flags & SN_ERR_MASK))
4944 t->flags |= SN_ERR_SRVCL;
4945 if (!(t->flags & SN_FINST_MASK))
4946 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02004947 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004948 return 1;
4949 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004950 /* last read, or end of client write */
4951 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004952 FD_CLR(t->srv_fd, StaticReadEvent);
4953 tv_eternity(&t->srexpire);
4954 shutdown(t->srv_fd, SHUT_RD);
4955 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004956 //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 +01004957 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004958 }
4959 /* end of client read and no more data to send */
4960 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4961 FD_CLR(t->srv_fd, StaticWriteEvent);
4962 tv_eternity(&t->swexpire);
4963 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004964 /* We must ensure that the read part is still alive when switching
4965 * to shutw */
4966 FD_SET(t->srv_fd, StaticReadEvent);
4967 if (t->proxy->srvtimeout)
4968 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4969
willy tarreaua41a8b42005-12-17 14:02:24 +01004970 t->srv_state = SV_STSHUTW;
4971 return 1;
4972 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004973 /* read timeout */
4974 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4975 FD_CLR(t->srv_fd, StaticReadEvent);
4976 tv_eternity(&t->srexpire);
4977 shutdown(t->srv_fd, SHUT_RD);
4978 t->srv_state = SV_STSHUTR;
4979 if (!(t->flags & SN_ERR_MASK))
4980 t->flags |= SN_ERR_SRVTO;
4981 if (!(t->flags & SN_FINST_MASK))
4982 t->flags |= SN_FINST_D;
4983 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004984 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004985 /* write timeout */
4986 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004987 FD_CLR(t->srv_fd, StaticWriteEvent);
4988 tv_eternity(&t->swexpire);
4989 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004990 /* We must ensure that the read part is still alive when switching
4991 * to shutw */
4992 FD_SET(t->srv_fd, StaticReadEvent);
4993 if (t->proxy->srvtimeout)
4994 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004995 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004996 if (!(t->flags & SN_ERR_MASK))
4997 t->flags |= SN_ERR_SRVTO;
4998 if (!(t->flags & SN_FINST_MASK))
4999 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005000 return 1;
5001 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005002
5003 /* recompute request time-outs */
5004 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005005 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5006 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5007 tv_eternity(&t->swexpire);
5008 }
5009 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005010 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005011 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5012 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005013 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005014 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005015 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5016 t->srexpire = t->swexpire;
5017 }
willy tarreau0f7af912005-12-17 12:21:26 +01005018 else
5019 tv_eternity(&t->swexpire);
5020 }
5021 }
5022
willy tarreaub1ff9db2005-12-17 13:51:03 +01005023 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005024 if (rep->l == BUFSIZE) { /* no room to read more data */
5025 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5026 FD_CLR(t->srv_fd, StaticReadEvent);
5027 tv_eternity(&t->srexpire);
5028 }
5029 }
5030 else {
5031 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5032 FD_SET(t->srv_fd, StaticReadEvent);
5033 if (t->proxy->srvtimeout)
5034 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5035 else
5036 tv_eternity(&t->srexpire);
5037 }
5038 }
5039
5040 return 0; /* other cases change nothing */
5041 }
5042 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005043 if (t->res_sw == RES_ERROR) {
5044 //FD_CLR(t->srv_fd, StaticWriteEvent);
5045 tv_eternity(&t->swexpire);
5046 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005047 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005048 //close(t->srv_fd);
5049 t->srv_state = SV_STCLOSE;
5050 if (!(t->flags & SN_ERR_MASK))
5051 t->flags |= SN_ERR_SRVCL;
5052 if (!(t->flags & SN_FINST_MASK))
5053 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005054 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005055 return 1;
5056 }
5057 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005058 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005059 tv_eternity(&t->swexpire);
5060 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005061 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005062 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005063 t->srv_state = SV_STCLOSE;
willy tarreau704f32b2006-04-07 17:37:55 +02005064 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005065 return 1;
5066 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005067 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5068 //FD_CLR(t->srv_fd, StaticWriteEvent);
5069 tv_eternity(&t->swexpire);
5070 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005071 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005072 //close(t->srv_fd);
5073 t->srv_state = SV_STCLOSE;
5074 if (!(t->flags & SN_ERR_MASK))
5075 t->flags |= SN_ERR_SRVTO;
5076 if (!(t->flags & SN_FINST_MASK))
5077 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005078 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005079 return 1;
5080 }
willy tarreau0f7af912005-12-17 12:21:26 +01005081 else if (req->l == 0) {
5082 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5083 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5084 tv_eternity(&t->swexpire);
5085 }
5086 }
5087 else { /* buffer not empty */
5088 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5089 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005090 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005091 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005092 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5093 t->srexpire = t->swexpire;
5094 }
willy tarreau0f7af912005-12-17 12:21:26 +01005095 else
5096 tv_eternity(&t->swexpire);
5097 }
5098 }
5099 return 0;
5100 }
5101 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005102 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005103 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005104 tv_eternity(&t->srexpire);
5105 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005106 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005107 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005108 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005109 if (!(t->flags & SN_ERR_MASK))
5110 t->flags |= SN_ERR_SRVCL;
5111 if (!(t->flags & SN_FINST_MASK))
5112 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005113 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005114 return 1;
5115 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005116 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5117 //FD_CLR(t->srv_fd, StaticReadEvent);
5118 tv_eternity(&t->srexpire);
5119 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005120 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005121 //close(t->srv_fd);
5122 t->srv_state = SV_STCLOSE;
willy tarreau704f32b2006-04-07 17:37:55 +02005123 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005124 return 1;
5125 }
5126 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5127 //FD_CLR(t->srv_fd, StaticReadEvent);
5128 tv_eternity(&t->srexpire);
5129 fd_delete(t->srv_fd);
willy tarreauc1364612006-04-07 16:28:28 +02005130 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005131 //close(t->srv_fd);
5132 t->srv_state = SV_STCLOSE;
5133 if (!(t->flags & SN_ERR_MASK))
5134 t->flags |= SN_ERR_SRVTO;
5135 if (!(t->flags & SN_FINST_MASK))
5136 t->flags |= SN_FINST_D;
willy tarreau704f32b2006-04-07 17:37:55 +02005137 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005138 return 1;
5139 }
willy tarreau0f7af912005-12-17 12:21:26 +01005140 else if (rep->l == BUFSIZE) { /* no room to read more data */
5141 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5142 FD_CLR(t->srv_fd, StaticReadEvent);
5143 tv_eternity(&t->srexpire);
5144 }
5145 }
5146 else {
5147 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5148 FD_SET(t->srv_fd, StaticReadEvent);
5149 if (t->proxy->srvtimeout)
5150 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5151 else
5152 tv_eternity(&t->srexpire);
5153 }
5154 }
5155 return 0;
5156 }
5157 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005158 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005159 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005160 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 +01005161 write(1, trash, len);
5162 }
5163 return 0;
5164 }
5165 return 0;
5166}
5167
5168
willy tarreau5cbea6f2005-12-17 12:48:26 +01005169/* Processes the client and server jobs of a session task, then
5170 * puts it back to the wait queue in a clean state, or
5171 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005172 * the time the task accepts to wait, or TIME_ETERNITY for
5173 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005174 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005175int process_session(struct task *t) {
5176 struct session *s = t->context;
5177 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005178
willy tarreau5cbea6f2005-12-17 12:48:26 +01005179 do {
5180 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005181 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005182 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005183 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005184 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005185 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005186 } while (fsm_resync);
5187
5188 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005189 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005190 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005191
willy tarreau5cbea6f2005-12-17 12:48:26 +01005192 tv_min(&min1, &s->crexpire, &s->cwexpire);
5193 tv_min(&min2, &s->srexpire, &s->swexpire);
5194 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005195 tv_min(&t->expire, &min1, &min2);
5196
5197 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005198 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005199
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005200#ifdef DEBUG_FULL
5201 /* DEBUG code : this should never ever happen, otherwise it indicates
5202 * that a task still has something to do and will provoke a quick loop.
5203 */
5204 if (tv_remain2(&now, &t->expire) <= 0)
5205 exit(100);
5206#endif
5207
willy tarreaub952e1d2005-12-18 01:31:20 +01005208 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005209 }
5210
willy tarreau5cbea6f2005-12-17 12:48:26 +01005211 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005212 actconn--;
5213
willy tarreau982249e2005-12-18 00:57:06 +01005214 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005215 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005216 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 +01005217 write(1, trash, len);
5218 }
5219
willy tarreau750a4722005-12-17 13:21:24 +01005220 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005221 if (s->rep != NULL)
5222 s->logs.bytes = s->rep->total;
5223
willy tarreau9fe663a2005-12-17 13:02:59 +01005224 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005225 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005226 sess_log(s);
5227
willy tarreau0f7af912005-12-17 12:21:26 +01005228 /* the task MUST not be in the run queue anymore */
5229 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005230 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005231 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005232 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005233}
5234
5235
5236
5237/*
5238 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005239 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005240 */
5241int process_chk(struct task *t) {
5242 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005243 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005244 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005245
willy tarreauef900ab2005-12-17 12:52:52 +01005246 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005247
willy tarreau25424f82006-03-19 19:37:48 +01005248 new_chk:
5249 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005250 if (fd < 0) { /* no check currently running */
5251 //fprintf(stderr, "process_chk: 2\n");
5252 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5253 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005254 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005255 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005256
5257 /* we don't send any health-checks when the proxy is stopped or when
5258 * the server should not be checked.
5259 */
5260 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005261 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5262 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005263 task_queue(t); /* restore t to its place in the task list */
5264 return tv_remain2(&now, &t->expire);
5265 }
5266
willy tarreau5cbea6f2005-12-17 12:48:26 +01005267 /* we'll initiate a new check */
5268 s->result = 0; /* no result yet */
5269 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005270 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005271 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5272 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5273 //fprintf(stderr, "process_chk: 3\n");
5274
willy tarreaua41a8b42005-12-17 14:02:24 +01005275 /* we'll connect to the check port on the server */
5276 sa = s->addr;
5277 sa.sin_port = htons(s->check_port);
5278
willy tarreau0174f312005-12-18 01:02:42 +01005279 /* allow specific binding :
5280 * - server-specific at first
5281 * - proxy-specific next
5282 */
5283 if (s->state & SRV_BIND_SRC) {
5284 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5285 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5286 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5287 s->proxy->id, s->id);
5288 s->result = -1;
5289 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005290 }
willy tarreau0174f312005-12-18 01:02:42 +01005291 else if (s->proxy->options & PR_O_BIND_SRC) {
5292 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5293 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5294 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5295 s->proxy->id);
5296 s->result = -1;
5297 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005298 }
willy tarreau0174f312005-12-18 01:02:42 +01005299
5300 if (!s->result) {
5301 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5302 /* OK, connection in progress or established */
5303
5304 //fprintf(stderr, "process_chk: 4\n");
5305
5306 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5307 fdtab[fd].owner = t;
5308 fdtab[fd].read = &event_srv_chk_r;
5309 fdtab[fd].write = &event_srv_chk_w;
5310 fdtab[fd].state = FD_STCONN; /* connection in progress */
5311 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005312#ifdef DEBUG_FULL
5313 assert (!FD_ISSET(fd, StaticReadEvent));
5314#endif
willy tarreau0174f312005-12-18 01:02:42 +01005315 fd_insert(fd);
5316 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5317 tv_delayfrom(&t->expire, &now, s->inter);
5318 task_queue(t); /* restore t to its place in the task list */
5319 return tv_remain(&now, &t->expire);
5320 }
5321 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5322 s->result = -1; /* a real error */
5323 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005324 }
5325 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005326 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005327 }
5328
5329 if (!s->result) { /* nothing done */
5330 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005331 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5332 tv_delayfrom(&t->expire, &t->expire, s->inter);
5333 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005334 }
5335
5336 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005337 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005338 s->health--; /* still good */
5339 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005340 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005341 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005342 recount_servers(s->proxy);
5343 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5344 s->state & SRV_BACKUP ? "Backup " : "",
5345 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5346 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5347 send_log(s->proxy, LOG_ALERT,
5348 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%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." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005352
willy tarreau62084d42006-03-24 18:57:41 +01005353 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005354 Alert("Proxy %s has no server available !\n", s->proxy->id);
5355 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5356 }
5357 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005358 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005359 }
5360
5361 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005362 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005363 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5364 tv_delayfrom(&t->expire, &t->expire, s->inter);
5365 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005366 }
5367 else {
5368 //fprintf(stderr, "process_chk: 8\n");
5369 /* there was a test running */
5370 if (s->result > 0) { /* good server detected */
5371 //fprintf(stderr, "process_chk: 9\n");
5372 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005373 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005374 s->state |= SRV_RUNNING;
5375
willy tarreau535ae7a2005-12-17 12:58:00 +01005376 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005377 recount_servers(s->proxy);
5378 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%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_NOTICE,
5383 "%sServer %s/%s is UP. %d active and %d backup servers online.%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." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005387 }
willy tarreauef900ab2005-12-17 12:52:52 +01005388
willy tarreaue47c8d72005-12-17 12:55:52 +01005389 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005390 }
willy tarreauef900ab2005-12-17 12:52:52 +01005391 s->curfd = -1; /* no check running anymore */
5392 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005393 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005394 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5395 tv_delayfrom(&t->expire, &t->expire, s->inter);
5396 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005397 }
5398 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5399 //fprintf(stderr, "process_chk: 10\n");
5400 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005401 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005402 s->health--; /* still good */
5403 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005404 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005405
willy tarreau62084d42006-03-24 18:57:41 +01005406 if (s->health == s->rise) {
5407 recount_servers(s->proxy);
5408 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5409 s->state & SRV_BACKUP ? "Backup " : "",
5410 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5411 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5412 send_log(s->proxy, LOG_ALERT,
5413 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5414 s->state & SRV_BACKUP ? "Backup " : "",
5415 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5416 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5417
5418 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5419 Alert("Proxy %s has no server available !\n", s->proxy->id);
5420 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5421 }
5422 }
willy tarreauef900ab2005-12-17 12:52:52 +01005423
willy tarreau5cbea6f2005-12-17 12:48:26 +01005424 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005425 }
5426 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005427 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005428 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005429 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5430 tv_delayfrom(&t->expire, &t->expire, s->inter);
5431 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005432 }
5433 /* if result is 0 and there's no timeout, we have to wait again */
5434 }
5435 //fprintf(stderr, "process_chk: 11\n");
5436 s->result = 0;
5437 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005438 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005439}
5440
5441
willy tarreau5cbea6f2005-12-17 12:48:26 +01005442
willy tarreau0f7af912005-12-17 12:21:26 +01005443#if STATTIME > 0
5444int stats(void);
5445#endif
5446
5447/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005448 * This does 4 things :
5449 * - wake up all expired tasks
5450 * - call all runnable tasks
5451 * - call maintain_proxies() to enable/disable the listeners
5452 * - return the delay till next event in ms, -1 = wait indefinitely
5453 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5454 *
willy tarreau0f7af912005-12-17 12:21:26 +01005455 */
5456
willy tarreau1c2ad212005-12-18 01:11:29 +01005457int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005458 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005459 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005460 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005461
willy tarreaub952e1d2005-12-18 01:31:20 +01005462 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005463
willy tarreau1c2ad212005-12-18 01:11:29 +01005464 /* look for expired tasks and add them to the run queue.
5465 */
5466 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5467 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5468 tnext = t->next;
5469 if (t->state & TASK_RUNNING)
5470 continue;
5471
willy tarreaub952e1d2005-12-18 01:31:20 +01005472 if (tv_iseternity(&t->expire))
5473 continue;
5474
willy tarreau1c2ad212005-12-18 01:11:29 +01005475 /* wakeup expired entries. It doesn't matter if they are
5476 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005477 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005478 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005479 task_wakeup(&rq, t);
5480 }
5481 else {
5482 /* first non-runnable task. Use its expiration date as an upper bound */
5483 int temp_time = tv_remain(&now, &t->expire);
5484 if (temp_time)
5485 next_time = temp_time;
5486 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005487 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005488 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005489
willy tarreau1c2ad212005-12-18 01:11:29 +01005490 /* process each task in the run queue now. Each task may be deleted
5491 * since we only use tnext.
5492 */
5493 tnext = rq;
5494 while ((t = tnext) != NULL) {
5495 int temp_time;
5496
5497 tnext = t->rqnext;
5498 task_sleep(&rq, t);
5499 temp_time = t->process(t);
5500 next_time = MINTIME(temp_time, next_time);
5501 }
5502
5503 /* maintain all proxies in a consistent state. This should quickly become a task */
5504 time2 = maintain_proxies();
5505 return MINTIME(time2, next_time);
5506}
5507
5508
5509#if defined(ENABLE_EPOLL)
5510
5511/*
5512 * Main epoll() loop.
5513 */
5514
5515/* does 3 actions :
5516 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5517 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5518 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5519 *
5520 * returns 0 if initialization failed, !0 otherwise.
5521 */
5522
5523int epoll_loop(int action) {
5524 int next_time;
5525 int status;
5526 int fd;
5527
5528 int fds, count;
5529 int pr, pw, sr, sw;
5530 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5531 struct epoll_event ev;
5532
5533 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005534 static struct epoll_event *epoll_events = NULL;
5535 static int epoll_fd;
5536
5537 if (action == POLL_LOOP_ACTION_INIT) {
5538 epoll_fd = epoll_create(global.maxsock + 1);
5539 if (epoll_fd < 0)
5540 return 0;
5541 else {
5542 epoll_events = (struct epoll_event*)
5543 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5544 PrevReadEvent = (fd_set *)
5545 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5546 PrevWriteEvent = (fd_set *)
5547 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005548 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005549 return 1;
5550 }
5551 else if (action == POLL_LOOP_ACTION_CLEAN) {
5552 if (PrevWriteEvent) free(PrevWriteEvent);
5553 if (PrevReadEvent) free(PrevReadEvent);
5554 if (epoll_events) free(epoll_events);
5555 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005556 epoll_fd = 0;
5557 return 1;
5558 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005559
willy tarreau1c2ad212005-12-18 01:11:29 +01005560 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005561
willy tarreau1c2ad212005-12-18 01:11:29 +01005562 tv_now(&now);
5563
5564 while (1) {
5565 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005566
5567 /* stop when there's no connection left and we don't allow them anymore */
5568 if (!actconn && listeners == 0)
5569 break;
5570
willy tarreau0f7af912005-12-17 12:21:26 +01005571#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005572 {
5573 int time2;
5574 time2 = stats();
5575 next_time = MINTIME(time2, next_time);
5576 }
willy tarreau0f7af912005-12-17 12:21:26 +01005577#endif
5578
willy tarreau1c2ad212005-12-18 01:11:29 +01005579 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5580
5581 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5582 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5583
5584 if ((ro^rn) | (wo^wn)) {
5585 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5586#define FDSETS_ARE_INT_ALIGNED
5587#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005588
willy tarreauad90a0c2005-12-18 01:09:15 +01005589#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5590#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005591 pr = (ro >> count) & 1;
5592 pw = (wo >> count) & 1;
5593 sr = (rn >> count) & 1;
5594 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005595#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005596 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5597 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5598 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5599 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005600#endif
5601#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005602 pr = FD_ISSET(fd, PrevReadEvent);
5603 pw = FD_ISSET(fd, PrevWriteEvent);
5604 sr = FD_ISSET(fd, StaticReadEvent);
5605 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005606#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005607 if (!((sr^pr) | (sw^pw)))
5608 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005609
willy tarreau1c2ad212005-12-18 01:11:29 +01005610 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5611 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005612
willy tarreaub952e1d2005-12-18 01:31:20 +01005613#ifdef EPOLL_CTL_MOD_WORKAROUND
5614 /* I encountered a rarely reproducible problem with
5615 * EPOLL_CTL_MOD where a modified FD (systematically
5616 * the one in epoll_events[0], fd#7) would sometimes
5617 * be set EPOLL_OUT while asked for a read ! This is
5618 * with the 2.4 epoll patch. The workaround is to
5619 * delete then recreate in case of modification.
5620 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5621 * nor RHEL kernels.
5622 */
5623
5624 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5625 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5626
5627 if ((sr | sw))
5628 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5629#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005630 if ((pr | pw)) {
5631 /* the file-descriptor already exists... */
5632 if ((sr | sw)) {
5633 /* ...and it will still exist */
5634 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5635 // perror("epoll_ctl(MOD)");
5636 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005637 }
5638 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005639 /* ...and it will be removed */
5640 if (fdtab[fd].state != FD_STCLOSE &&
5641 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5642 // perror("epoll_ctl(DEL)");
5643 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005644 }
5645 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005646 } else {
5647 /* the file-descriptor did not exist, let's add it */
5648 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5649 // perror("epoll_ctl(ADD)");
5650 // exit(1);
5651 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005652 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005653#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005654 }
5655 ((int*)PrevReadEvent)[fds] = rn;
5656 ((int*)PrevWriteEvent)[fds] = wn;
5657 }
5658 }
5659
5660 /* now let's wait for events */
5661 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5662 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005663
willy tarreau1c2ad212005-12-18 01:11:29 +01005664 for (count = 0; count < status; count++) {
5665 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005666
5667 if (FD_ISSET(fd, StaticReadEvent)) {
5668 if (fdtab[fd].state == FD_STCLOSE)
5669 continue;
5670 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5671 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005672 }
willy tarreau05be12b2006-03-19 19:35:00 +01005673
5674 if (FD_ISSET(fd, StaticWriteEvent)) {
5675 if (fdtab[fd].state == FD_STCLOSE)
5676 continue;
5677 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5678 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005679 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005680 }
5681 }
5682 return 1;
5683}
5684#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005685
willy tarreauad90a0c2005-12-18 01:09:15 +01005686
willy tarreau5cbea6f2005-12-17 12:48:26 +01005687
willy tarreau1c2ad212005-12-18 01:11:29 +01005688#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005689
willy tarreau1c2ad212005-12-18 01:11:29 +01005690/*
5691 * Main poll() loop.
5692 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005693
willy tarreau1c2ad212005-12-18 01:11:29 +01005694/* does 3 actions :
5695 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5696 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5697 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5698 *
5699 * returns 0 if initialization failed, !0 otherwise.
5700 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005701
willy tarreau1c2ad212005-12-18 01:11:29 +01005702int poll_loop(int action) {
5703 int next_time;
5704 int status;
5705 int fd, nbfd;
5706
5707 int fds, count;
5708 int sr, sw;
5709 unsigned rn, wn; /* read new, write new */
5710
5711 /* private data */
5712 static struct pollfd *poll_events = NULL;
5713
5714 if (action == POLL_LOOP_ACTION_INIT) {
5715 poll_events = (struct pollfd*)
5716 calloc(1, sizeof(struct pollfd) * global.maxsock);
5717 return 1;
5718 }
5719 else if (action == POLL_LOOP_ACTION_CLEAN) {
5720 if (poll_events)
5721 free(poll_events);
5722 return 1;
5723 }
5724
5725 /* OK, it's POLL_LOOP_ACTION_RUN */
5726
5727 tv_now(&now);
5728
5729 while (1) {
5730 next_time = process_runnable_tasks();
5731
5732 /* stop when there's no connection left and we don't allow them anymore */
5733 if (!actconn && listeners == 0)
5734 break;
5735
5736#if STATTIME > 0
5737 {
5738 int time2;
5739 time2 = stats();
5740 next_time = MINTIME(time2, next_time);
5741 }
5742#endif
5743
5744
5745 nbfd = 0;
5746 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5747
5748 rn = ((int*)StaticReadEvent)[fds];
5749 wn = ((int*)StaticWriteEvent)[fds];
5750
5751 if ((rn|wn)) {
5752 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5753#define FDSETS_ARE_INT_ALIGNED
5754#ifdef FDSETS_ARE_INT_ALIGNED
5755
5756#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5757#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5758 sr = (rn >> count) & 1;
5759 sw = (wn >> count) & 1;
5760#else
5761 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5762 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5763#endif
5764#else
5765 sr = FD_ISSET(fd, StaticReadEvent);
5766 sw = FD_ISSET(fd, StaticWriteEvent);
5767#endif
5768 if ((sr|sw)) {
5769 poll_events[nbfd].fd = fd;
5770 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5771 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005772 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005773 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005774 }
5775 }
5776
5777 /* now let's wait for events */
5778 status = poll(poll_events, nbfd, next_time);
5779 tv_now(&now);
5780
5781 for (count = 0; status > 0 && count < nbfd; count++) {
5782 fd = poll_events[count].fd;
5783
5784 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5785 continue;
5786
5787 /* ok, we found one active fd */
5788 status--;
5789
willy tarreau05be12b2006-03-19 19:35:00 +01005790 if (FD_ISSET(fd, StaticReadEvent)) {
5791 if (fdtab[fd].state == FD_STCLOSE)
5792 continue;
5793 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5794 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005795 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005796
willy tarreau05be12b2006-03-19 19:35:00 +01005797 if (FD_ISSET(fd, StaticWriteEvent)) {
5798 if (fdtab[fd].state == FD_STCLOSE)
5799 continue;
5800 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5801 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005802 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005803 }
5804 }
5805 return 1;
5806}
willy tarreauad90a0c2005-12-18 01:09:15 +01005807#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005808
willy tarreauad90a0c2005-12-18 01:09:15 +01005809
willy tarreauad90a0c2005-12-18 01:09:15 +01005810
willy tarreau1c2ad212005-12-18 01:11:29 +01005811/*
5812 * Main select() loop.
5813 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005814
willy tarreau1c2ad212005-12-18 01:11:29 +01005815/* does 3 actions :
5816 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5817 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5818 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5819 *
5820 * returns 0 if initialization failed, !0 otherwise.
5821 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005822
willy tarreauad90a0c2005-12-18 01:09:15 +01005823
willy tarreau1c2ad212005-12-18 01:11:29 +01005824int select_loop(int action) {
5825 int next_time;
5826 int status;
5827 int fd,i;
5828 struct timeval delta;
5829 int readnotnull, writenotnull;
5830 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005831
willy tarreau1c2ad212005-12-18 01:11:29 +01005832 if (action == POLL_LOOP_ACTION_INIT) {
5833 ReadEvent = (fd_set *)
5834 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5835 WriteEvent = (fd_set *)
5836 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5837 return 1;
5838 }
5839 else if (action == POLL_LOOP_ACTION_CLEAN) {
5840 if (WriteEvent) free(WriteEvent);
5841 if (ReadEvent) free(ReadEvent);
5842 return 1;
5843 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005844
willy tarreau1c2ad212005-12-18 01:11:29 +01005845 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005846
willy tarreau1c2ad212005-12-18 01:11:29 +01005847 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005848
willy tarreau1c2ad212005-12-18 01:11:29 +01005849 while (1) {
5850 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005851
willy tarreau1c2ad212005-12-18 01:11:29 +01005852 /* stop when there's no connection left and we don't allow them anymore */
5853 if (!actconn && listeners == 0)
5854 break;
5855
5856#if STATTIME > 0
5857 {
5858 int time2;
5859 time2 = stats();
5860 next_time = MINTIME(time2, next_time);
5861 }
5862#endif
5863
willy tarreau1c2ad212005-12-18 01:11:29 +01005864 if (next_time > 0) { /* FIXME */
5865 /* Convert to timeval */
5866 /* to avoid eventual select loops due to timer precision */
5867 next_time += SCHEDULER_RESOLUTION;
5868 delta.tv_sec = next_time / 1000;
5869 delta.tv_usec = (next_time % 1000) * 1000;
5870 }
5871 else if (next_time == 0) { /* allow select to return immediately when needed */
5872 delta.tv_sec = delta.tv_usec = 0;
5873 }
5874
5875
5876 /* let's restore fdset state */
5877
5878 readnotnull = 0; writenotnull = 0;
5879 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5880 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5881 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5882 }
5883
5884 // /* just a verification code, needs to be removed for performance */
5885 // for (i=0; i<maxfd; i++) {
5886 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5887 // abort();
5888 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5889 // abort();
5890 //
5891 // }
5892
5893 status = select(maxfd,
5894 readnotnull ? ReadEvent : NULL,
5895 writenotnull ? WriteEvent : NULL,
5896 NULL,
5897 (next_time >= 0) ? &delta : NULL);
5898
5899 /* this is an experiment on the separation of the select work */
5900 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5901 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5902
5903 tv_now(&now);
5904
5905 if (status > 0) { /* must proceed with events */
5906
5907 int fds;
5908 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005909
willy tarreau1c2ad212005-12-18 01:11:29 +01005910 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5911 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5912 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5913
5914 /* if we specify read first, the accepts and zero reads will be
5915 * seen first. Moreover, system buffers will be flushed faster.
5916 */
willy tarreau05be12b2006-03-19 19:35:00 +01005917 if (FD_ISSET(fd, ReadEvent)) {
5918 if (fdtab[fd].state == FD_STCLOSE)
5919 continue;
5920 fdtab[fd].read(fd);
5921 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005922
willy tarreau05be12b2006-03-19 19:35:00 +01005923 if (FD_ISSET(fd, WriteEvent)) {
5924 if (fdtab[fd].state == FD_STCLOSE)
5925 continue;
5926 fdtab[fd].write(fd);
5927 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005928 }
5929 }
5930 else {
5931 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005932 }
willy tarreau0f7af912005-12-17 12:21:26 +01005933 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005934 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005935}
5936
5937
5938#if STATTIME > 0
5939/*
5940 * Display proxy statistics regularly. It is designed to be called from the
5941 * select_loop().
5942 */
5943int stats(void) {
5944 static int lines;
5945 static struct timeval nextevt;
5946 static struct timeval lastevt;
5947 static struct timeval starttime = {0,0};
5948 unsigned long totaltime, deltatime;
5949 int ret;
5950
willy tarreau750a4722005-12-17 13:21:24 +01005951 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005952 deltatime = (tv_diff(&lastevt, &now)?:1);
5953 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005954
willy tarreau9fe663a2005-12-17 13:02:59 +01005955 if (global.mode & MODE_STATS) {
5956 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005957 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005958 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5959 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005960 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005961 actconn, totalconn,
5962 stats_tsk_new, stats_tsk_good,
5963 stats_tsk_left, stats_tsk_right,
5964 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5965 }
5966 }
5967
5968 tv_delayfrom(&nextevt, &now, STATTIME);
5969
5970 lastevt=now;
5971 }
5972 ret = tv_remain(&now, &nextevt);
5973 return ret;
5974}
5975#endif
5976
5977
5978/*
5979 * this function enables proxies when there are enough free sessions,
5980 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005981 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005982 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005983 */
5984static int maintain_proxies(void) {
5985 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005986 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005987 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005988
5989 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005990 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005991
5992 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005993 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005994 while (p) {
5995 if (p->nbconn < p->maxconn) {
5996 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005997 for (l = p->listen; l != NULL; l = l->next) {
5998 FD_SET(l->fd, StaticReadEvent);
5999 }
willy tarreau0f7af912005-12-17 12:21:26 +01006000 p->state = PR_STRUN;
6001 }
6002 }
6003 else {
6004 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006005 for (l = p->listen; l != NULL; l = l->next) {
6006 FD_CLR(l->fd, StaticReadEvent);
6007 }
willy tarreau0f7af912005-12-17 12:21:26 +01006008 p->state = PR_STIDLE;
6009 }
6010 }
6011 p = p->next;
6012 }
6013 }
6014 else { /* block all proxies */
6015 while (p) {
6016 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006017 for (l = p->listen; l != NULL; l = l->next) {
6018 FD_CLR(l->fd, StaticReadEvent);
6019 }
willy tarreau0f7af912005-12-17 12:21:26 +01006020 p->state = PR_STIDLE;
6021 }
6022 p = p->next;
6023 }
6024 }
6025
willy tarreau5cbea6f2005-12-17 12:48:26 +01006026 if (stopping) {
6027 p = proxy;
6028 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006029 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006030 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006031 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006032 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006033 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006034 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006035
willy tarreaua41a8b42005-12-17 14:02:24 +01006036 for (l = p->listen; l != NULL; l = l->next) {
6037 fd_delete(l->fd);
6038 listeners--;
6039 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006040 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006041 }
6042 else {
6043 tleft = MINTIME(t, tleft);
6044 }
6045 }
6046 p = p->next;
6047 }
6048 }
6049 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006050}
6051
6052/*
6053 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006054 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6055 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006056 */
6057static void soft_stop(void) {
6058 struct proxy *p;
6059
6060 stopping = 1;
6061 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006062 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006063 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006064 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006065 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006066 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006067 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006068 }
willy tarreau0f7af912005-12-17 12:21:26 +01006069 p = p->next;
6070 }
6071}
6072
willy tarreaudbd3bef2006-01-20 19:35:18 +01006073static void pause_proxy(struct proxy *p) {
6074 struct listener *l;
6075 for (l = p->listen; l != NULL; l = l->next) {
6076 shutdown(l->fd, SHUT_RD);
6077 FD_CLR(l->fd, StaticReadEvent);
6078 p->state = PR_STPAUSED;
6079 }
6080}
6081
6082/*
6083 * This function temporarily disables listening so that another new instance
6084 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006085 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006086 * the proxy, or a SIGTTIN can be sent to listen again.
6087 */
6088static void pause_proxies(void) {
6089 struct proxy *p;
6090
6091 p = proxy;
6092 tv_now(&now); /* else, the old time before select will be used */
6093 while (p) {
6094 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6095 Warning("Pausing proxy %s.\n", p->id);
6096 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6097 pause_proxy(p);
6098 }
6099 p = p->next;
6100 }
6101}
6102
6103
6104/*
6105 * This function reactivates listening. This can be used after a call to
6106 * sig_pause(), for example when a new instance has failed starting up.
6107 * It is designed to be called upon reception of a SIGTTIN.
6108 */
6109static void listen_proxies(void) {
6110 struct proxy *p;
6111 struct listener *l;
6112
6113 p = proxy;
6114 tv_now(&now); /* else, the old time before select will be used */
6115 while (p) {
6116 if (p->state == PR_STPAUSED) {
6117 Warning("Enabling proxy %s.\n", p->id);
6118 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6119
6120 for (l = p->listen; l != NULL; l = l->next) {
6121 if (listen(l->fd, p->maxconn) == 0) {
6122 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6123 FD_SET(l->fd, StaticReadEvent);
6124 p->state = PR_STRUN;
6125 }
6126 else
6127 p->state = PR_STIDLE;
6128 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006129 int port;
6130
6131 if (l->addr.ss_family == AF_INET6)
6132 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6133 else
6134 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6135
willy tarreaudbd3bef2006-01-20 19:35:18 +01006136 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006137 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006138 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006139 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006140 /* Another port might have been enabled. Let's stop everything. */
6141 pause_proxy(p);
6142 break;
6143 }
6144 }
6145 }
6146 p = p->next;
6147 }
6148}
6149
6150
willy tarreau0f7af912005-12-17 12:21:26 +01006151/*
6152 * upon SIGUSR1, let's have a soft stop.
6153 */
6154void sig_soft_stop(int sig) {
6155 soft_stop();
6156 signal(sig, SIG_IGN);
6157}
6158
willy tarreaudbd3bef2006-01-20 19:35:18 +01006159/*
6160 * upon SIGTTOU, we pause everything
6161 */
6162void sig_pause(int sig) {
6163 pause_proxies();
6164 signal(sig, sig_pause);
6165}
willy tarreau0f7af912005-12-17 12:21:26 +01006166
willy tarreau8337c6b2005-12-17 13:41:01 +01006167/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006168 * upon SIGTTIN, let's have a soft stop.
6169 */
6170void sig_listen(int sig) {
6171 listen_proxies();
6172 signal(sig, sig_listen);
6173}
6174
6175/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006176 * this function dumps every server's state when the process receives SIGHUP.
6177 */
6178void sig_dump_state(int sig) {
6179 struct proxy *p = proxy;
6180
6181 Warning("SIGHUP received, dumping servers states.\n");
6182 while (p) {
6183 struct server *s = p->srv;
6184
6185 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6186 while (s) {
6187 if (s->state & SRV_RUNNING) {
willy tarreaub1c331f2006-04-07 18:23:29 +02006188 snprintf(trash, sizeof(trash),
6189 "SIGHUP: Server %s/%s is UP. Conn: %d act, %d tot.",
6190 p->id, s->id, s->cur_sess, s->cum_sess);
6191 } else {
6192 snprintf(trash, sizeof(trash),
6193 "SIGHUP: Server %s/%s is DOWN. Conn: %d act, %d tot.",
6194 p->id, s->id, s->cur_sess, s->cum_sess);
willy tarreau8337c6b2005-12-17 13:41:01 +01006195 }
willy tarreaub1c331f2006-04-07 18:23:29 +02006196 Warning("%s\n", trash);
6197 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006198 s = s->next;
6199 }
willy tarreaudd07e972005-12-18 00:48:48 +01006200
willy tarreau62084d42006-03-24 18:57:41 +01006201 if (p->srv_act == 0) {
6202 if (p->srv_bck) {
willy tarreaub1c331f2006-04-07 18:23:29 +02006203 snprintf(trash, sizeof(trash),
6204 "SIGHUP: Proxy %s is running on backup servers ! Conn: %d act, %d tot.",
6205 p->id, p->nbconn, p->cum_conn);
6206 } else {
6207 snprintf(trash, sizeof(trash),
6208 "SIGHUP: Proxy %s has no server availble ! Conn: %d act, %d tot.",
6209 p->id, p->nbconn, p->cum_conn);
6210 }
6211 } else {
6212 snprintf(trash, sizeof(trash),
6213 "SIGHUP: Proxy %s has %d active servers and %d backup servers availble. Conn: %d act, %d tot.",
6214 p->id, p->srv_act, p->srv_bck, p->nbconn, p->cum_conn);
6215 }
6216 Warning("%s\n", trash);
6217 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006218
willy tarreau8337c6b2005-12-17 13:41:01 +01006219 p = p->next;
6220 }
6221 signal(sig, sig_dump_state);
6222}
6223
willy tarreau0f7af912005-12-17 12:21:26 +01006224void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006225 struct task *t, *tnext;
6226 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006227
willy tarreau5cbea6f2005-12-17 12:48:26 +01006228 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6229 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6230 tnext = t->next;
6231 s = t->context;
6232 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6233 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6234 "req=%d, rep=%d, clifd=%d\n",
6235 s, tv_remain(&now, &t->expire),
6236 s->cli_state,
6237 s->srv_state,
6238 FD_ISSET(s->cli_fd, StaticReadEvent),
6239 FD_ISSET(s->cli_fd, StaticWriteEvent),
6240 FD_ISSET(s->srv_fd, StaticReadEvent),
6241 FD_ISSET(s->srv_fd, StaticWriteEvent),
6242 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6243 );
willy tarreau0f7af912005-12-17 12:21:26 +01006244 }
willy tarreau12350152005-12-18 01:03:27 +01006245}
6246
willy tarreau64a3cc32005-12-18 01:13:11 +01006247#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006248static void fast_stop(void)
6249{
6250 struct proxy *p;
6251 p = proxy;
6252 while (p) {
6253 p->grace = 0;
6254 p = p->next;
6255 }
6256 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006257}
6258
willy tarreau12350152005-12-18 01:03:27 +01006259void sig_int(int sig) {
6260 /* This would normally be a hard stop,
6261 but we want to be sure about deallocation,
6262 and so on, so we do a soft stop with
6263 0 GRACE time
6264 */
6265 fast_stop();
6266 /* If we are killed twice, we decide to die*/
6267 signal(sig, SIG_DFL);
6268}
6269
6270void sig_term(int sig) {
6271 /* This would normally be a hard stop,
6272 but we want to be sure about deallocation,
6273 and so on, so we do a soft stop with
6274 0 GRACE time
6275 */
6276 fast_stop();
6277 /* If we are killed twice, we decide to die*/
6278 signal(sig, SIG_DFL);
6279}
willy tarreau64a3cc32005-12-18 01:13:11 +01006280#endif
willy tarreau12350152005-12-18 01:03:27 +01006281
willy tarreauc1f47532005-12-18 01:08:26 +01006282/* returns the pointer to an error in the replacement string, or NULL if OK */
6283char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006284 struct hdr_exp *exp;
6285
willy tarreauc1f47532005-12-18 01:08:26 +01006286 if (replace != NULL) {
6287 char *err;
6288 err = check_replace_string(replace);
6289 if (err)
6290 return err;
6291 }
6292
willy tarreaue39cd132005-12-17 13:00:18 +01006293 while (*head != NULL)
6294 head = &(*head)->next;
6295
6296 exp = calloc(1, sizeof(struct hdr_exp));
6297
6298 exp->preg = preg;
6299 exp->replace = replace;
6300 exp->action = action;
6301 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006302
6303 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006304}
6305
willy tarreau9fe663a2005-12-17 13:02:59 +01006306
willy tarreau0f7af912005-12-17 12:21:26 +01006307/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006308 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006309 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006310int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006311
willy tarreau9fe663a2005-12-17 13:02:59 +01006312 if (!strcmp(args[0], "global")) { /* new section */
6313 /* no option, nothing special to do */
6314 return 0;
6315 }
6316 else if (!strcmp(args[0], "daemon")) {
6317 global.mode |= MODE_DAEMON;
6318 }
6319 else if (!strcmp(args[0], "debug")) {
6320 global.mode |= MODE_DEBUG;
6321 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006322 else if (!strcmp(args[0], "noepoll")) {
6323 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6324 }
6325 else if (!strcmp(args[0], "nopoll")) {
6326 cfg_polling_mechanism &= ~POLL_USE_POLL;
6327 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006328 else if (!strcmp(args[0], "quiet")) {
6329 global.mode |= MODE_QUIET;
6330 }
6331 else if (!strcmp(args[0], "stats")) {
6332 global.mode |= MODE_STATS;
6333 }
6334 else if (!strcmp(args[0], "uid")) {
6335 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006336 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006337 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006338 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006339 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006340 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006341 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006342 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006343 global.uid = atol(args[1]);
6344 }
6345 else if (!strcmp(args[0], "gid")) {
6346 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006347 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006348 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006349 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006350 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006351 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006352 return -1;
6353 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006354 global.gid = atol(args[1]);
6355 }
6356 else if (!strcmp(args[0], "nbproc")) {
6357 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006358 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006359 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006360 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006361 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006362 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006363 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006364 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006365 global.nbproc = atol(args[1]);
6366 }
6367 else if (!strcmp(args[0], "maxconn")) {
6368 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006369 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006370 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006371 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006372 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006373 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006374 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006375 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006376 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006377#ifdef SYSTEM_MAXCONN
6378 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6379 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);
6380 global.maxconn = DEFAULT_MAXCONN;
6381 }
6382#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006383 }
willy tarreaub1285d52005-12-18 01:20:14 +01006384 else if (!strcmp(args[0], "ulimit-n")) {
6385 if (global.rlimit_nofile != 0) {
6386 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6387 return 0;
6388 }
6389 if (*(args[1]) == 0) {
6390 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6391 return -1;
6392 }
6393 global.rlimit_nofile = atol(args[1]);
6394 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006395 else if (!strcmp(args[0], "chroot")) {
6396 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006397 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006398 return 0;
6399 }
6400 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006401 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006402 return -1;
6403 }
6404 global.chroot = strdup(args[1]);
6405 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006406 else if (!strcmp(args[0], "pidfile")) {
6407 if (global.pidfile != NULL) {
6408 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6409 return 0;
6410 }
6411 if (*(args[1]) == 0) {
6412 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6413 return -1;
6414 }
6415 global.pidfile = strdup(args[1]);
6416 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006417 else if (!strcmp(args[0], "log")) { /* syslog server address */
6418 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006419 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006420
6421 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006422 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006423 return -1;
6424 }
6425
6426 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6427 if (!strcmp(log_facilities[facility], args[2]))
6428 break;
6429
6430 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006431 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006432 exit(1);
6433 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006434
6435 level = 7; /* max syslog level = debug */
6436 if (*(args[3])) {
6437 while (level >= 0 && strcmp(log_levels[level], args[3]))
6438 level--;
6439 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006440 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006441 exit(1);
6442 }
6443 }
6444
willy tarreau9fe663a2005-12-17 13:02:59 +01006445 sa = str2sa(args[1]);
6446 if (!sa->sin_port)
6447 sa->sin_port = htons(SYSLOG_PORT);
6448
6449 if (global.logfac1 == -1) {
6450 global.logsrv1 = *sa;
6451 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006452 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006453 }
6454 else if (global.logfac2 == -1) {
6455 global.logsrv2 = *sa;
6456 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006457 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006458 }
6459 else {
6460 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6461 return -1;
6462 }
6463
6464 }
6465 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006466 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006467 return -1;
6468 }
6469 return 0;
6470}
6471
6472
willy tarreaua41a8b42005-12-17 14:02:24 +01006473void init_default_instance() {
6474 memset(&defproxy, 0, sizeof(defproxy));
6475 defproxy.mode = PR_MODE_TCP;
6476 defproxy.state = PR_STNEW;
6477 defproxy.maxconn = cfg_maxpconn;
6478 defproxy.conn_retries = CONN_RETRIES;
6479 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6480}
6481
willy tarreau9fe663a2005-12-17 13:02:59 +01006482/*
6483 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6484 */
6485int cfg_parse_listen(char *file, int linenum, char **args) {
6486 static struct proxy *curproxy = NULL;
6487 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006488 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006489 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006490
6491 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006492 if (!*args[1]) {
6493 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6494 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006495 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006496 return -1;
6497 }
6498
6499 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006500 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006501 return -1;
6502 }
6503 curproxy->next = proxy;
6504 proxy = curproxy;
6505 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006506
6507 /* parse the listener address if any */
6508 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006509 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006510 if (!curproxy->listen)
6511 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006512 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006513 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006514
willy tarreau9fe663a2005-12-17 13:02:59 +01006515 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006516 curproxy->state = defproxy.state;
6517 curproxy->maxconn = defproxy.maxconn;
6518 curproxy->conn_retries = defproxy.conn_retries;
6519 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006520
6521 if (defproxy.check_req)
6522 curproxy->check_req = strdup(defproxy.check_req);
6523 curproxy->check_len = defproxy.check_len;
6524
6525 if (defproxy.cookie_name)
6526 curproxy->cookie_name = strdup(defproxy.cookie_name);
6527 curproxy->cookie_len = defproxy.cookie_len;
6528
6529 if (defproxy.capture_name)
6530 curproxy->capture_name = strdup(defproxy.capture_name);
6531 curproxy->capture_namelen = defproxy.capture_namelen;
6532 curproxy->capture_len = defproxy.capture_len;
6533
6534 if (defproxy.errmsg.msg400)
6535 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6536 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6537
6538 if (defproxy.errmsg.msg403)
6539 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6540 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6541
6542 if (defproxy.errmsg.msg408)
6543 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6544 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6545
6546 if (defproxy.errmsg.msg500)
6547 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6548 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6549
6550 if (defproxy.errmsg.msg502)
6551 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6552 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6553
6554 if (defproxy.errmsg.msg503)
6555 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6556 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6557
6558 if (defproxy.errmsg.msg504)
6559 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6560 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6561
willy tarreaua41a8b42005-12-17 14:02:24 +01006562 curproxy->clitimeout = defproxy.clitimeout;
6563 curproxy->contimeout = defproxy.contimeout;
6564 curproxy->srvtimeout = defproxy.srvtimeout;
6565 curproxy->mode = defproxy.mode;
6566 curproxy->logfac1 = defproxy.logfac1;
6567 curproxy->logsrv1 = defproxy.logsrv1;
6568 curproxy->loglev1 = defproxy.loglev1;
6569 curproxy->logfac2 = defproxy.logfac2;
6570 curproxy->logsrv2 = defproxy.logsrv2;
6571 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006572 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006573 curproxy->grace = defproxy.grace;
6574 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006575 curproxy->mon_net = defproxy.mon_net;
6576 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006577 return 0;
6578 }
6579 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006580 /* some variables may have already been initialized earlier */
6581 if (defproxy.check_req) free(defproxy.check_req);
6582 if (defproxy.cookie_name) free(defproxy.cookie_name);
6583 if (defproxy.capture_name) free(defproxy.capture_name);
6584 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6585 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6586 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6587 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6588 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6589 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6590 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6591
6592 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006593 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006594 return 0;
6595 }
6596 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006597 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006598 return -1;
6599 }
6600
willy tarreaua41a8b42005-12-17 14:02:24 +01006601 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6602 if (curproxy == &defproxy) {
6603 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6604 return -1;
6605 }
6606
6607 if (strchr(args[1], ':') == NULL) {
6608 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6609 file, linenum, args[0]);
6610 return -1;
6611 }
6612 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006613 if (!curproxy->listen)
6614 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006615 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006616 return 0;
6617 }
willy tarreaub1285d52005-12-18 01:20:14 +01006618 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6619 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6620 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6621 file, linenum, args[0]);
6622 return -1;
6623 }
6624 /* flush useless bits */
6625 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6626 return 0;
6627 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006628 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6630 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6631 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6632 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006633 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006634 return -1;
6635 }
6636 }
6637 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006638 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006639 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006640 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6641 curproxy->state = PR_STNEW;
6642 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006643 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6644 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006645// if (curproxy == &defproxy) {
6646// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6647// return -1;
6648// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006649
willy tarreau9fe663a2005-12-17 13:02:59 +01006650 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006651// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6652// file, linenum);
6653// return 0;
6654 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006655 }
6656
6657 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006658 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6659 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006660 return -1;
6661 }
6662 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006663 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006664
6665 cur_arg = 2;
6666 while (*(args[cur_arg])) {
6667 if (!strcmp(args[cur_arg], "rewrite")) {
6668 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006669 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006670 else if (!strcmp(args[cur_arg], "indirect")) {
6671 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006672 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006673 else if (!strcmp(args[cur_arg], "insert")) {
6674 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006675 }
willy tarreau240afa62005-12-17 13:14:35 +01006676 else if (!strcmp(args[cur_arg], "nocache")) {
6677 curproxy->options |= PR_O_COOK_NOC;
6678 }
willy tarreaucd878942005-12-17 13:27:43 +01006679 else if (!strcmp(args[cur_arg], "postonly")) {
6680 curproxy->options |= PR_O_COOK_POST;
6681 }
willy tarreau0174f312005-12-18 01:02:42 +01006682 else if (!strcmp(args[cur_arg], "prefix")) {
6683 curproxy->options |= PR_O_COOK_PFX;
6684 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006685 else {
willy tarreau0174f312005-12-18 01:02:42 +01006686 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006687 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006688 return -1;
6689 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006690 cur_arg++;
6691 }
willy tarreau0174f312005-12-18 01:02:42 +01006692 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6693 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6694 file, linenum);
6695 return -1;
6696 }
6697
6698 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6699 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006700 file, linenum);
6701 return -1;
6702 }
willy tarreau12350152005-12-18 01:03:27 +01006703 }/* end else if (!strcmp(args[0], "cookie")) */
6704 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6705// if (curproxy == &defproxy) {
6706// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6707// return -1;
6708// }
6709
6710 if (curproxy->appsession_name != NULL) {
6711// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6712// file, linenum);
6713// return 0;
6714 free(curproxy->appsession_name);
6715 }
6716
6717 if (*(args[5]) == 0) {
6718 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6719 file, linenum, args[0]);
6720 return -1;
6721 }
6722 have_appsession = 1;
6723 curproxy->appsession_name = strdup(args[1]);
6724 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6725 curproxy->appsession_len = atoi(args[3]);
6726 curproxy->appsession_timeout = atoi(args[5]);
6727 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6728 if (rc) {
6729 Alert("Error Init Appsession Hashtable.\n");
6730 return -1;
6731 }
6732 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006733 else if (!strcmp(args[0], "capture")) {
6734 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6735 // if (curproxy == &defproxy) {
6736 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6737 // return -1;
6738 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006739
willy tarreau4302f492005-12-18 01:00:37 +01006740 if (curproxy->capture_name != NULL) {
6741 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6742 // file, linenum, args[0]);
6743 // return 0;
6744 free(curproxy->capture_name);
6745 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006746
willy tarreau4302f492005-12-18 01:00:37 +01006747 if (*(args[4]) == 0) {
6748 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6749 file, linenum, args[0]);
6750 return -1;
6751 }
6752 curproxy->capture_name = strdup(args[2]);
6753 curproxy->capture_namelen = strlen(curproxy->capture_name);
6754 curproxy->capture_len = atol(args[4]);
6755 if (curproxy->capture_len >= CAPTURE_LEN) {
6756 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6757 file, linenum, CAPTURE_LEN - 1);
6758 curproxy->capture_len = CAPTURE_LEN - 1;
6759 }
6760 curproxy->to_log |= LW_COOKIE;
6761 }
6762 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6763 struct cap_hdr *hdr;
6764
6765 if (curproxy == &defproxy) {
6766 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6767 return -1;
6768 }
6769
6770 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6771 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6772 file, linenum, args[0], args[1]);
6773 return -1;
6774 }
6775
6776 hdr = calloc(sizeof(struct cap_hdr), 1);
6777 hdr->next = curproxy->req_cap;
6778 hdr->name = strdup(args[3]);
6779 hdr->namelen = strlen(args[3]);
6780 hdr->len = atol(args[5]);
6781 hdr->index = curproxy->nb_req_cap++;
6782 curproxy->req_cap = hdr;
6783 curproxy->to_log |= LW_REQHDR;
6784 }
6785 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6786 struct cap_hdr *hdr;
6787
6788 if (curproxy == &defproxy) {
6789 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6790 return -1;
6791 }
6792
6793 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6794 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6795 file, linenum, args[0], args[1]);
6796 return -1;
6797 }
6798 hdr = calloc(sizeof(struct cap_hdr), 1);
6799 hdr->next = curproxy->rsp_cap;
6800 hdr->name = strdup(args[3]);
6801 hdr->namelen = strlen(args[3]);
6802 hdr->len = atol(args[5]);
6803 hdr->index = curproxy->nb_rsp_cap++;
6804 curproxy->rsp_cap = hdr;
6805 curproxy->to_log |= LW_RSPHDR;
6806 }
6807 else {
6808 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006809 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006810 return -1;
6811 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006812 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006813 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006814 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006815 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006816 return 0;
6817 }
6818 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006819 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6820 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006821 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006822 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006823 curproxy->contimeout = atol(args[1]);
6824 }
6825 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006826 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006827 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6828 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006829 return 0;
6830 }
6831 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006832 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6833 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006834 return -1;
6835 }
6836 curproxy->clitimeout = atol(args[1]);
6837 }
6838 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006839 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006840 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006841 return 0;
6842 }
6843 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006844 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6845 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006846 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006847 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006848 curproxy->srvtimeout = atol(args[1]);
6849 }
6850 else if (!strcmp(args[0], "retries")) { /* connection retries */
6851 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006852 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6853 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006854 return -1;
6855 }
6856 curproxy->conn_retries = atol(args[1]);
6857 }
6858 else if (!strcmp(args[0], "option")) {
6859 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006860 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006861 return -1;
6862 }
6863 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006864 /* enable reconnections to dispatch */
6865 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006866#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006867 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006868 /* enable transparent proxy connections */
6869 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006870#endif
6871 else if (!strcmp(args[1], "keepalive"))
6872 /* enable keep-alive */
6873 curproxy->options |= PR_O_KEEPALIVE;
6874 else if (!strcmp(args[1], "forwardfor"))
6875 /* insert x-forwarded-for field */
6876 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006877 else if (!strcmp(args[1], "logasap"))
6878 /* log as soon as possible, without waiting for the session to complete */
6879 curproxy->options |= PR_O_LOGASAP;
6880 else if (!strcmp(args[1], "httpclose"))
6881 /* force connection: close in both directions in HTTP mode */
6882 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006883 else if (!strcmp(args[1], "forceclose"))
6884 /* force connection: close in both directions in HTTP mode and enforce end of session */
6885 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006886 else if (!strcmp(args[1], "checkcache"))
6887 /* require examination of cacheability of the 'set-cookie' field */
6888 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006889 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006890 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006891 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006892 else if (!strcmp(args[1], "tcplog"))
6893 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006894 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006895 else if (!strcmp(args[1], "dontlognull")) {
6896 /* don't log empty requests */
6897 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006898 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006899 else if (!strcmp(args[1], "tcpka")) {
6900 /* enable TCP keep-alives on client and server sessions */
6901 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6902 }
6903 else if (!strcmp(args[1], "clitcpka")) {
6904 /* enable TCP keep-alives on client sessions */
6905 curproxy->options |= PR_O_TCP_CLI_KA;
6906 }
6907 else if (!strcmp(args[1], "srvtcpka")) {
6908 /* enable TCP keep-alives on server sessions */
6909 curproxy->options |= PR_O_TCP_SRV_KA;
6910 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006911 else if (!strcmp(args[1], "allbackups")) {
6912 /* Use all backup servers simultaneously */
6913 curproxy->options |= PR_O_USE_ALL_BK;
6914 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006915 else if (!strcmp(args[1], "httpchk")) {
6916 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006917 if (curproxy->check_req != NULL) {
6918 free(curproxy->check_req);
6919 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006920 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006921 if (!*args[2]) { /* no argument */
6922 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6923 curproxy->check_len = strlen(DEF_CHECK_REQ);
6924 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006925 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6926 curproxy->check_req = (char *)malloc(reqlen);
6927 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6928 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006929 } else { /* more arguments : METHOD URI [HTTP_VER] */
6930 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6931 if (*args[4])
6932 reqlen += strlen(args[4]);
6933 else
6934 reqlen += strlen("HTTP/1.0");
6935
6936 curproxy->check_req = (char *)malloc(reqlen);
6937 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6938 "%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 +01006939 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006940 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006941 else if (!strcmp(args[1], "persist")) {
6942 /* persist on using the server specified by the cookie, even when it's down */
6943 curproxy->options |= PR_O_PERSIST;
6944 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006945 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006946 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006947 return -1;
6948 }
6949 return 0;
6950 }
6951 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6952 /* enable reconnections to dispatch */
6953 curproxy->options |= PR_O_REDISP;
6954 }
willy tarreaua1598082005-12-17 13:08:06 +01006955#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006956 else if (!strcmp(args[0], "transparent")) {
6957 /* enable transparent proxy connections */
6958 curproxy->options |= PR_O_TRANSP;
6959 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006960#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006961 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6962 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006963 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006964 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006965 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006966 curproxy->maxconn = atol(args[1]);
6967 }
6968 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6969 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006970 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006971 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 curproxy->grace = atol(args[1]);
6974 }
6975 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006976 if (curproxy == &defproxy) {
6977 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6978 return -1;
6979 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006980 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006981 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006982 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006983 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006984 curproxy->dispatch_addr = *str2sa(args[1]);
6985 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006986 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006987 if (*(args[1])) {
6988 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006989 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006990 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006991 else if (!strcmp(args[1], "source")) {
6992 curproxy->options |= PR_O_BALANCE_SH;
6993 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006994 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01006995 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006996 return -1;
6997 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006998 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006999 else /* if no option is set, use round-robin by default */
7000 curproxy->options |= PR_O_BALANCE_RR;
7001 }
7002 else if (!strcmp(args[0], "server")) { /* server address */
7003 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007004 char *rport;
7005 char *raddr;
7006 short realport;
7007 int do_check;
7008
7009 if (curproxy == &defproxy) {
7010 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7011 return -1;
7012 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007013
willy tarreaua41a8b42005-12-17 14:02:24 +01007014 if (!*args[2]) {
7015 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007016 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007017 return -1;
7018 }
7019 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7020 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7021 return -1;
7022 }
willy tarreau0174f312005-12-18 01:02:42 +01007023
7024 if (curproxy->srv == NULL)
7025 curproxy->srv = newsrv;
7026 else
7027 curproxy->cursrv->next = newsrv;
7028 curproxy->cursrv = newsrv;
7029
7030 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007031 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007032
7033 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007034 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007035 newsrv->id = strdup(args[1]);
7036
7037 /* several ways to check the port component :
7038 * - IP => port=+0, relative
7039 * - IP: => port=+0, relative
7040 * - IP:N => port=N, absolute
7041 * - IP:+N => port=+N, relative
7042 * - IP:-N => port=-N, relative
7043 */
7044 raddr = strdup(args[2]);
7045 rport = strchr(raddr, ':');
7046 if (rport) {
7047 *rport++ = 0;
7048 realport = atol(rport);
7049 if (!isdigit((int)*rport))
7050 newsrv->state |= SRV_MAPPORTS;
7051 } else {
7052 realport = 0;
7053 newsrv->state |= SRV_MAPPORTS;
7054 }
7055
7056 newsrv->addr = *str2sa(raddr);
7057 newsrv->addr.sin_port = htons(realport);
7058 free(raddr);
7059
willy tarreau9fe663a2005-12-17 13:02:59 +01007060 newsrv->curfd = -1; /* no health-check in progress */
7061 newsrv->inter = DEF_CHKINTR;
7062 newsrv->rise = DEF_RISETIME;
7063 newsrv->fall = DEF_FALLTIME;
7064 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7065 cur_arg = 3;
7066 while (*args[cur_arg]) {
7067 if (!strcmp(args[cur_arg], "cookie")) {
7068 newsrv->cookie = strdup(args[cur_arg + 1]);
7069 newsrv->cklen = strlen(args[cur_arg + 1]);
7070 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007071 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007072 else if (!strcmp(args[cur_arg], "rise")) {
7073 newsrv->rise = atol(args[cur_arg + 1]);
7074 newsrv->health = newsrv->rise;
7075 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007076 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007077 else if (!strcmp(args[cur_arg], "fall")) {
7078 newsrv->fall = atol(args[cur_arg + 1]);
7079 cur_arg += 2;
7080 }
7081 else if (!strcmp(args[cur_arg], "inter")) {
7082 newsrv->inter = atol(args[cur_arg + 1]);
7083 cur_arg += 2;
7084 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007085 else if (!strcmp(args[cur_arg], "port")) {
7086 newsrv->check_port = atol(args[cur_arg + 1]);
7087 cur_arg += 2;
7088 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007089 else if (!strcmp(args[cur_arg], "backup")) {
7090 newsrv->state |= SRV_BACKUP;
7091 cur_arg ++;
7092 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007093 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007094 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007095 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007096 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007097 }
willy tarreau0174f312005-12-18 01:02:42 +01007098 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7099 if (!*args[cur_arg + 1]) {
7100 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7101 file, linenum, "source");
7102 return -1;
7103 }
7104 newsrv->state |= SRV_BIND_SRC;
7105 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7106 cur_arg += 2;
7107 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007108 else {
willy tarreau0174f312005-12-18 01:02:42 +01007109 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 +01007110 file, linenum, newsrv->id);
7111 return -1;
7112 }
7113 }
7114
7115 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007116 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7117 newsrv->check_port = realport; /* by default */
7118 if (!newsrv->check_port) {
7119 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 +01007120 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007121 return -1;
7122 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007123 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007124 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007125
willy tarreau62084d42006-03-24 18:57:41 +01007126 if (newsrv->state & SRV_BACKUP)
7127 curproxy->srv_bck++;
7128 else
7129 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007130 }
7131 else if (!strcmp(args[0], "log")) { /* syslog server address */
7132 struct sockaddr_in *sa;
7133 int facility;
7134
7135 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7136 curproxy->logfac1 = global.logfac1;
7137 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007138 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007139 curproxy->logfac2 = global.logfac2;
7140 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007141 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007142 }
7143 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007144 int level;
7145
willy tarreau0f7af912005-12-17 12:21:26 +01007146 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7147 if (!strcmp(log_facilities[facility], args[2]))
7148 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007149
willy tarreau0f7af912005-12-17 12:21:26 +01007150 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007151 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007152 exit(1);
7153 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007154
willy tarreau8337c6b2005-12-17 13:41:01 +01007155 level = 7; /* max syslog level = debug */
7156 if (*(args[3])) {
7157 while (level >= 0 && strcmp(log_levels[level], args[3]))
7158 level--;
7159 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007160 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007161 exit(1);
7162 }
7163 }
7164
willy tarreau0f7af912005-12-17 12:21:26 +01007165 sa = str2sa(args[1]);
7166 if (!sa->sin_port)
7167 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007168
willy tarreau0f7af912005-12-17 12:21:26 +01007169 if (curproxy->logfac1 == -1) {
7170 curproxy->logsrv1 = *sa;
7171 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007172 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007173 }
7174 else if (curproxy->logfac2 == -1) {
7175 curproxy->logsrv2 = *sa;
7176 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007177 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007178 }
7179 else {
7180 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007181 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007182 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007183 }
7184 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007185 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007186 file, linenum);
7187 return -1;
7188 }
7189 }
willy tarreaua1598082005-12-17 13:08:06 +01007190 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007191 if (!*args[1]) {
7192 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007193 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007194 return -1;
7195 }
7196
7197 curproxy->source_addr = *str2sa(args[1]);
7198 curproxy->options |= PR_O_BIND_SRC;
7199 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007200 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7201 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007202 if (curproxy == &defproxy) {
7203 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7204 return -1;
7205 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007206
7207 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007208 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7209 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007210 return -1;
7211 }
7212
7213 preg = calloc(1, sizeof(regex_t));
7214 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007215 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007216 return -1;
7217 }
7218
willy tarreauc1f47532005-12-18 01:08:26 +01007219 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7220 if (err) {
7221 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7222 file, linenum, *err);
7223 return -1;
7224 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007225 }
7226 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7227 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007228 if (curproxy == &defproxy) {
7229 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7230 return -1;
7231 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007232
7233 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007234 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007235 return -1;
7236 }
7237
7238 preg = calloc(1, sizeof(regex_t));
7239 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007240 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007241 return -1;
7242 }
7243
7244 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7245 }
7246 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7247 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007248 if (curproxy == &defproxy) {
7249 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7250 return -1;
7251 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007252
7253 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007254 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007255 return -1;
7256 }
7257
7258 preg = calloc(1, sizeof(regex_t));
7259 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007260 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007261 return -1;
7262 }
7263
7264 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7265 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007266 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7267 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007268 if (curproxy == &defproxy) {
7269 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7270 return -1;
7271 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007272
7273 if (*(args[1]) == 0) {
7274 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7275 return -1;
7276 }
7277
7278 preg = calloc(1, sizeof(regex_t));
7279 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7280 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7281 return -1;
7282 }
7283
7284 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7285 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007286 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7287 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007288 if (curproxy == &defproxy) {
7289 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7290 return -1;
7291 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007292
7293 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007294 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007295 return -1;
7296 }
7297
7298 preg = calloc(1, sizeof(regex_t));
7299 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007300 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007301 return -1;
7302 }
7303
7304 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7305 }
7306 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7307 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007308 if (curproxy == &defproxy) {
7309 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7310 return -1;
7311 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007312
7313 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007314 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7315 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007316 return -1;
7317 }
7318
7319 preg = calloc(1, sizeof(regex_t));
7320 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007321 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007322 return -1;
7323 }
7324
willy tarreauc1f47532005-12-18 01:08:26 +01007325 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7326 if (err) {
7327 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7328 file, linenum, *err);
7329 return -1;
7330 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007331 }
7332 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7333 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007334 if (curproxy == &defproxy) {
7335 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7336 return -1;
7337 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007338
7339 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007340 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007341 return -1;
7342 }
7343
7344 preg = calloc(1, sizeof(regex_t));
7345 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007346 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007347 return -1;
7348 }
7349
7350 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7351 }
7352 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7353 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007354 if (curproxy == &defproxy) {
7355 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7356 return -1;
7357 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007358
7359 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007360 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007361 return -1;
7362 }
7363
7364 preg = calloc(1, sizeof(regex_t));
7365 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007366 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007367 return -1;
7368 }
7369
7370 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7371 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007372 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7373 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007374 if (curproxy == &defproxy) {
7375 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7376 return -1;
7377 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007378
7379 if (*(args[1]) == 0) {
7380 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7381 return -1;
7382 }
7383
7384 preg = calloc(1, sizeof(regex_t));
7385 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7386 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7387 return -1;
7388 }
7389
7390 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7391 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007392 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7393 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007394 if (curproxy == &defproxy) {
7395 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7396 return -1;
7397 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007398
7399 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007400 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007401 return -1;
7402 }
7403
7404 preg = calloc(1, sizeof(regex_t));
7405 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007406 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007407 return -1;
7408 }
7409
7410 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7411 }
7412 else if (!strcmp(args[0], "reqadd")) { /* add request header */
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 }
7417
willy tarreau9fe663a2005-12-17 13:02:59 +01007418 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007419 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007420 return 0;
7421 }
7422
7423 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007424 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007425 return -1;
7426 }
7427
willy tarreau4302f492005-12-18 01:00:37 +01007428 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7429 }
7430 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7431 regex_t *preg;
7432
7433 if (*(args[1]) == 0 || *(args[2]) == 0) {
7434 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7435 file, linenum, args[0]);
7436 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007437 }
willy tarreau4302f492005-12-18 01:00:37 +01007438
7439 preg = calloc(1, sizeof(regex_t));
7440 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7441 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7442 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007443 }
willy tarreau4302f492005-12-18 01:00:37 +01007444
willy tarreauc1f47532005-12-18 01:08:26 +01007445 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7446 if (err) {
7447 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7448 file, linenum, *err);
7449 return -1;
7450 }
willy tarreau4302f492005-12-18 01:00:37 +01007451 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007452 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7453 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007454 if (curproxy == &defproxy) {
7455 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7456 return -1;
7457 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007458
7459 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007460 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007461 return -1;
7462 }
willy tarreaue39cd132005-12-17 13:00:18 +01007463
willy tarreau9fe663a2005-12-17 13:02:59 +01007464 preg = calloc(1, sizeof(regex_t));
7465 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007466 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007467 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007468 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007469
willy tarreauc1f47532005-12-18 01:08:26 +01007470 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7471 if (err) {
7472 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7473 file, linenum, *err);
7474 return -1;
7475 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007476 }
willy tarreau982249e2005-12-18 00:57:06 +01007477 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7478 regex_t *preg;
7479 if (curproxy == &defproxy) {
7480 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7481 return -1;
7482 }
7483
7484 if (*(args[1]) == 0) {
7485 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7486 return -1;
7487 }
7488
7489 preg = calloc(1, sizeof(regex_t));
7490 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7491 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7492 return -1;
7493 }
7494
willy tarreauc1f47532005-12-18 01:08:26 +01007495 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7496 if (err) {
7497 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7498 file, linenum, *err);
7499 return -1;
7500 }
willy tarreau982249e2005-12-18 00:57:06 +01007501 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007502 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007503 regex_t *preg;
7504 if (curproxy == &defproxy) {
7505 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7506 return -1;
7507 }
willy tarreaue39cd132005-12-17 13:00:18 +01007508
willy tarreaua41a8b42005-12-17 14:02:24 +01007509 if (*(args[1]) == 0 || *(args[2]) == 0) {
7510 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7511 file, linenum, args[0]);
7512 return -1;
7513 }
willy tarreaue39cd132005-12-17 13:00:18 +01007514
willy tarreaua41a8b42005-12-17 14:02:24 +01007515 preg = calloc(1, sizeof(regex_t));
7516 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7517 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7518 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007519 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007520
willy tarreauc1f47532005-12-18 01:08:26 +01007521 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7522 if (err) {
7523 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7524 file, linenum, *err);
7525 return -1;
7526 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007527 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007528 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7529 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007530 if (curproxy == &defproxy) {
7531 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7532 return -1;
7533 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007534
7535 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007536 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007537 return -1;
7538 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007539
willy tarreau9fe663a2005-12-17 13:02:59 +01007540 preg = calloc(1, sizeof(regex_t));
7541 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007542 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007543 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007544 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007545
willy tarreauc1f47532005-12-18 01:08:26 +01007546 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7547 if (err) {
7548 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7549 file, linenum, *err);
7550 return -1;
7551 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007552 }
willy tarreau982249e2005-12-18 00:57:06 +01007553 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7554 regex_t *preg;
7555 if (curproxy == &defproxy) {
7556 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7557 return -1;
7558 }
7559
7560 if (*(args[1]) == 0) {
7561 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7562 return -1;
7563 }
7564
7565 preg = calloc(1, sizeof(regex_t));
7566 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7567 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7568 return -1;
7569 }
7570
willy tarreauc1f47532005-12-18 01:08:26 +01007571 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7572 if (err) {
7573 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7574 file, linenum, *err);
7575 return -1;
7576 }
willy tarreau982249e2005-12-18 00:57:06 +01007577 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007578 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007579 if (curproxy == &defproxy) {
7580 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7581 return -1;
7582 }
7583
willy tarreau9fe663a2005-12-17 13:02:59 +01007584 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007585 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007586 return 0;
7587 }
7588
7589 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007590 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007591 return -1;
7592 }
7593
7594 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7595 }
willy tarreauc1f47532005-12-18 01:08:26 +01007596 else if (!strcmp(args[0], "errorloc") ||
7597 !strcmp(args[0], "errorloc302") ||
7598 !strcmp(args[0], "errorloc303")) { /* error location */
7599 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007600 char *err;
7601
willy tarreaueedaa9f2005-12-17 14:08:03 +01007602 // if (curproxy == &defproxy) {
7603 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7604 // return -1;
7605 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007606
willy tarreau8337c6b2005-12-17 13:41:01 +01007607 if (*(args[2]) == 0) {
7608 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7609 return -1;
7610 }
7611
7612 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007613 if (!strcmp(args[0], "errorloc303")) {
7614 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7615 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7616 } else {
7617 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7618 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7619 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007620
7621 if (errnum == 400) {
7622 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007623 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007624 free(curproxy->errmsg.msg400);
7625 }
7626 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007627 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007628 }
7629 else if (errnum == 403) {
7630 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007631 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007632 free(curproxy->errmsg.msg403);
7633 }
7634 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007635 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007636 }
7637 else if (errnum == 408) {
7638 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007639 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007640 free(curproxy->errmsg.msg408);
7641 }
7642 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007643 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007644 }
7645 else if (errnum == 500) {
7646 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007647 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007648 free(curproxy->errmsg.msg500);
7649 }
7650 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007651 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007652 }
7653 else if (errnum == 502) {
7654 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007655 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007656 free(curproxy->errmsg.msg502);
7657 }
7658 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007659 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007660 }
7661 else if (errnum == 503) {
7662 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007663 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007664 free(curproxy->errmsg.msg503);
7665 }
7666 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007667 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007668 }
7669 else if (errnum == 504) {
7670 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007671 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007672 free(curproxy->errmsg.msg504);
7673 }
7674 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007675 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007676 }
7677 else {
7678 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7679 free(err);
7680 }
7681 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007682 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007683 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007684 return -1;
7685 }
7686 return 0;
7687}
willy tarreaue39cd132005-12-17 13:00:18 +01007688
willy tarreau5cbea6f2005-12-17 12:48:26 +01007689
willy tarreau9fe663a2005-12-17 13:02:59 +01007690/*
7691 * This function reads and parses the configuration file given in the argument.
7692 * returns 0 if OK, -1 if error.
7693 */
7694int readcfgfile(char *file) {
7695 char thisline[256];
7696 char *line;
7697 FILE *f;
7698 int linenum = 0;
7699 char *end;
7700 char *args[MAX_LINE_ARGS];
7701 int arg;
7702 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007703 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007704 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007705
willy tarreau9fe663a2005-12-17 13:02:59 +01007706 struct proxy *curproxy = NULL;
7707 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007708
willy tarreau9fe663a2005-12-17 13:02:59 +01007709 if ((f=fopen(file,"r")) == NULL)
7710 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007711
willy tarreaueedaa9f2005-12-17 14:08:03 +01007712 init_default_instance();
7713
willy tarreau9fe663a2005-12-17 13:02:59 +01007714 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7715 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007716
willy tarreau9fe663a2005-12-17 13:02:59 +01007717 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007718
willy tarreau9fe663a2005-12-17 13:02:59 +01007719 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007720 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007721 line++;
7722
7723 arg = 0;
7724 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007725
willy tarreau9fe663a2005-12-17 13:02:59 +01007726 while (*line && arg < MAX_LINE_ARGS) {
7727 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7728 * C equivalent value. Other combinations left unchanged (eg: \1).
7729 */
7730 if (*line == '\\') {
7731 int skip = 0;
7732 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7733 *line = line[1];
7734 skip = 1;
7735 }
7736 else if (line[1] == 'r') {
7737 *line = '\r';
7738 skip = 1;
7739 }
7740 else if (line[1] == 'n') {
7741 *line = '\n';
7742 skip = 1;
7743 }
7744 else if (line[1] == 't') {
7745 *line = '\t';
7746 skip = 1;
7747 }
willy tarreauc1f47532005-12-18 01:08:26 +01007748 else if (line[1] == 'x') {
7749 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7750 unsigned char hex1, hex2;
7751 hex1 = toupper(line[2]) - '0';
7752 hex2 = toupper(line[3]) - '0';
7753 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7754 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7755 *line = (hex1<<4) + hex2;
7756 skip = 3;
7757 }
7758 else {
7759 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7760 return -1;
7761 }
7762 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007763 if (skip) {
7764 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7765 end -= skip;
7766 }
7767 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007768 }
willy tarreaua1598082005-12-17 13:08:06 +01007769 else if (*line == '#' || *line == '\n' || *line == '\r') {
7770 /* end of string, end of loop */
7771 *line = 0;
7772 break;
7773 }
willy tarreauc29948c2005-12-17 13:10:27 +01007774 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007775 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007776 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007777 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007778 line++;
7779 args[++arg] = line;
7780 }
7781 else {
7782 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007783 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007784 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007785
willy tarreau9fe663a2005-12-17 13:02:59 +01007786 /* empty line */
7787 if (!**args)
7788 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007789
willy tarreau9fe663a2005-12-17 13:02:59 +01007790 /* zero out remaining args */
7791 while (++arg < MAX_LINE_ARGS) {
7792 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007793 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007794
willy tarreaua41a8b42005-12-17 14:02:24 +01007795 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007796 confsect = CFG_LISTEN;
7797 else if (!strcmp(args[0], "global")) /* global config */
7798 confsect = CFG_GLOBAL;
7799 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007800
willy tarreau9fe663a2005-12-17 13:02:59 +01007801 switch (confsect) {
7802 case CFG_LISTEN:
7803 if (cfg_parse_listen(file, linenum, args) < 0)
7804 return -1;
7805 break;
7806 case CFG_GLOBAL:
7807 if (cfg_parse_global(file, linenum, args) < 0)
7808 return -1;
7809 break;
7810 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007811 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007812 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007813 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007814
7815
willy tarreau0f7af912005-12-17 12:21:26 +01007816 }
7817 fclose(f);
7818
7819 /*
7820 * Now, check for the integrity of all that we have collected.
7821 */
7822
Willy TARREAU3759f982006-03-01 22:44:17 +01007823 /* will be needed further to delay some tasks */
7824 tv_now(&now);
7825
willy tarreau0f7af912005-12-17 12:21:26 +01007826 if ((curproxy = proxy) == NULL) {
7827 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7828 file);
7829 return -1;
7830 }
7831
7832 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007833 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007834 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007835 curproxy = curproxy->next;
7836 continue;
7837 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007838
7839 if (curproxy->listen == NULL) {
7840 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);
7841 cfgerr++;
7842 }
7843 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007844 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007845 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007846 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7847 file, curproxy->id);
7848 cfgerr++;
7849 }
7850 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7851 if (curproxy->options & PR_O_TRANSP) {
7852 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7853 file, curproxy->id);
7854 cfgerr++;
7855 }
7856 else if (curproxy->srv == NULL) {
7857 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7858 file, curproxy->id);
7859 cfgerr++;
7860 }
willy tarreaua1598082005-12-17 13:08:06 +01007861 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007862 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7863 file, curproxy->id);
7864 }
7865 }
7866 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007867 if (curproxy->cookie_name != NULL) {
7868 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7869 file, curproxy->id);
7870 }
7871 if ((newsrv = curproxy->srv) != NULL) {
7872 Warning("parsing %s : servers will be ignored for listener %s.\n",
7873 file, curproxy->id);
7874 }
willy tarreaue39cd132005-12-17 13:00:18 +01007875 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007876 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7877 file, curproxy->id);
7878 }
willy tarreaue39cd132005-12-17 13:00:18 +01007879 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007880 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7881 file, curproxy->id);
7882 }
7883 }
7884 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7885 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7886 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7887 file, curproxy->id);
7888 cfgerr++;
7889 }
7890 else {
7891 while (newsrv != NULL) {
7892 /* nothing to check for now */
7893 newsrv = newsrv->next;
7894 }
7895 }
7896 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007897
7898 if (curproxy->options & PR_O_LOGASAP)
7899 curproxy->to_log &= ~LW_BYTES;
7900
willy tarreau8337c6b2005-12-17 13:41:01 +01007901 if (curproxy->errmsg.msg400 == NULL) {
7902 curproxy->errmsg.msg400 = (char *)HTTP_400;
7903 curproxy->errmsg.len400 = strlen(HTTP_400);
7904 }
7905 if (curproxy->errmsg.msg403 == NULL) {
7906 curproxy->errmsg.msg403 = (char *)HTTP_403;
7907 curproxy->errmsg.len403 = strlen(HTTP_403);
7908 }
7909 if (curproxy->errmsg.msg408 == NULL) {
7910 curproxy->errmsg.msg408 = (char *)HTTP_408;
7911 curproxy->errmsg.len408 = strlen(HTTP_408);
7912 }
7913 if (curproxy->errmsg.msg500 == NULL) {
7914 curproxy->errmsg.msg500 = (char *)HTTP_500;
7915 curproxy->errmsg.len500 = strlen(HTTP_500);
7916 }
7917 if (curproxy->errmsg.msg502 == NULL) {
7918 curproxy->errmsg.msg502 = (char *)HTTP_502;
7919 curproxy->errmsg.len502 = strlen(HTTP_502);
7920 }
7921 if (curproxy->errmsg.msg503 == NULL) {
7922 curproxy->errmsg.msg503 = (char *)HTTP_503;
7923 curproxy->errmsg.len503 = strlen(HTTP_503);
7924 }
7925 if (curproxy->errmsg.msg504 == NULL) {
7926 curproxy->errmsg.msg504 = (char *)HTTP_504;
7927 curproxy->errmsg.len504 = strlen(HTTP_504);
7928 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007929
7930 /* now we'll start this proxy's health checks if any */
7931 /* 1- count the checkers to run simultaneously */
7932 nbchk = 0;
7933 mininter = 0;
7934 newsrv = curproxy->srv;
7935 while (newsrv != NULL) {
7936 if (newsrv->state & SRV_CHECKED) {
7937 if (!mininter || mininter > newsrv->inter)
7938 mininter = newsrv->inter;
7939 nbchk++;
7940 }
7941 newsrv = newsrv->next;
7942 }
7943
7944 /* 2- start them as far as possible from each others while respecting
7945 * their own intervals. For this, we will start them after their own
7946 * interval added to the min interval divided by the number of servers,
7947 * weighted by the server's position in the list.
7948 */
7949 if (nbchk > 0) {
7950 struct task *t;
7951 int srvpos;
7952
7953 newsrv = curproxy->srv;
7954 srvpos = 0;
7955 while (newsrv != NULL) {
7956 /* should this server be checked ? */
7957 if (newsrv->state & SRV_CHECKED) {
7958 if ((t = pool_alloc(task)) == NULL) {
7959 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7960 return -1;
7961 }
7962
7963 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7964 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7965 t->state = TASK_IDLE;
7966 t->process = process_chk;
7967 t->context = newsrv;
7968
7969 /* check this every ms */
7970 tv_delayfrom(&t->expire, &now,
7971 newsrv->inter + mininter * srvpos / nbchk);
7972 task_queue(t);
7973 //task_wakeup(&rq, t);
7974 srvpos++;
7975 }
7976 newsrv = newsrv->next;
7977 }
7978 }
7979
willy tarreau0f7af912005-12-17 12:21:26 +01007980 curproxy = curproxy->next;
7981 }
7982 if (cfgerr > 0) {
7983 Alert("Errors found in configuration file, aborting.\n");
7984 return -1;
7985 }
7986 else
7987 return 0;
7988}
7989
7990
7991/*
7992 * This function initializes all the necessary variables. It only returns
7993 * if everything is OK. If something fails, it exits.
7994 */
7995void init(int argc, char **argv) {
7996 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007997 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007998 char *old_argv = *argv;
7999 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008000 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008001
8002 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008003 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008004 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008005 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008006 exit(1);
8007 }
8008
willy tarreau746e26b2006-03-25 11:14:35 +01008009#ifdef HAPROXY_MEMMAX
8010 global.rlimit_memmax = HAPROXY_MEMMAX;
8011#endif
8012
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008013 /* initialize the libc's localtime structures once for all so that we
8014 * won't be missing memory if we want to send alerts under OOM conditions.
8015 */
8016 tv_now(&now);
8017 localtime(&now.tv_sec);
8018
willy tarreau4302f492005-12-18 01:00:37 +01008019 /* initialize the log header encoding map : '{|}"#' should be encoded with
8020 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8021 * URL encoding only requires '"', '#' to be encoded as well as non-
8022 * printable characters above.
8023 */
8024 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8025 memset(url_encode_map, 0, sizeof(url_encode_map));
8026 for (i = 0; i < 32; i++) {
8027 FD_SET(i, hdr_encode_map);
8028 FD_SET(i, url_encode_map);
8029 }
8030 for (i = 127; i < 256; i++) {
8031 FD_SET(i, hdr_encode_map);
8032 FD_SET(i, url_encode_map);
8033 }
8034
8035 tmp = "\"#{|}";
8036 while (*tmp) {
8037 FD_SET(*tmp, hdr_encode_map);
8038 tmp++;
8039 }
8040
8041 tmp = "\"#";
8042 while (*tmp) {
8043 FD_SET(*tmp, url_encode_map);
8044 tmp++;
8045 }
8046
willy tarreau64a3cc32005-12-18 01:13:11 +01008047 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8048#if defined(ENABLE_POLL)
8049 cfg_polling_mechanism |= POLL_USE_POLL;
8050#endif
8051#if defined(ENABLE_EPOLL)
8052 cfg_polling_mechanism |= POLL_USE_EPOLL;
8053#endif
8054
willy tarreau0f7af912005-12-17 12:21:26 +01008055 pid = getpid();
8056 progname = *argv;
8057 while ((tmp = strchr(progname, '/')) != NULL)
8058 progname = tmp + 1;
8059
8060 argc--; argv++;
8061 while (argc > 0) {
8062 char *flag;
8063
8064 if (**argv == '-') {
8065 flag = *argv+1;
8066
8067 /* 1 arg */
8068 if (*flag == 'v') {
8069 display_version();
8070 exit(0);
8071 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008072#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008073 else if (*flag == 'd' && flag[1] == 'e')
8074 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008075#endif
8076#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008077 else if (*flag == 'd' && flag[1] == 'p')
8078 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008079#endif
willy tarreau982249e2005-12-18 00:57:06 +01008080 else if (*flag == 'V')
8081 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008082 else if (*flag == 'd' && flag[1] == 'b')
8083 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008084 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008085 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008086 else if (*flag == 'c')
8087 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008088 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008089 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008090 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008091 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01008092#if STATTIME > 0
8093 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01008094 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01008095 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01008096 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01008097#endif
willy tarreau53e99702006-03-25 18:53:50 +01008098 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8099 /* list of pids to finish ('f') or terminate ('t') */
8100
8101 if (flag[1] == 'f')
8102 oldpids_sig = SIGUSR1; /* finish then exit */
8103 else
8104 oldpids_sig = SIGTERM; /* terminate immediately */
8105 argv++; argc--;
8106
8107 if (argc > 0) {
8108 oldpids = calloc(argc, sizeof(int));
8109 while (argc > 0) {
8110 oldpids[nb_oldpids] = atol(*argv);
8111 if (oldpids[nb_oldpids] <= 0)
8112 usage(old_argv);
8113 argc--; argv++;
8114 nb_oldpids++;
8115 }
8116 }
8117 }
willy tarreau0f7af912005-12-17 12:21:26 +01008118 else { /* >=2 args */
8119 argv++; argc--;
8120 if (argc == 0)
8121 usage(old_argv);
8122
8123 switch (*flag) {
8124 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008125 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008126 case 'N' : cfg_maxpconn = atol(*argv); break;
8127 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008128 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008129 default: usage(old_argv);
8130 }
8131 }
8132 }
8133 else
8134 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008135 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008136 }
8137
willy tarreaud0fb4652005-12-18 01:32:04 +01008138 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008139 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8140 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008141
willy tarreau0f7af912005-12-17 12:21:26 +01008142 if (!cfg_cfgfile)
8143 usage(old_argv);
8144
8145 gethostname(hostname, MAX_HOSTNAME_LEN);
8146
willy tarreau12350152005-12-18 01:03:27 +01008147 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008148 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008149 if (readcfgfile(cfg_cfgfile) < 0) {
8150 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8151 exit(1);
8152 }
willy tarreau12350152005-12-18 01:03:27 +01008153 if (have_appsession)
8154 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008155
willy tarreau982249e2005-12-18 00:57:06 +01008156 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008157 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8158 exit(0);
8159 }
8160
willy tarreau9fe663a2005-12-17 13:02:59 +01008161 if (cfg_maxconn > 0)
8162 global.maxconn = cfg_maxconn;
8163
willy tarreaufe2c5c12005-12-17 14:14:34 +01008164 if (cfg_pidfile) {
8165 if (global.pidfile)
8166 free(global.pidfile);
8167 global.pidfile = strdup(cfg_pidfile);
8168 }
8169
willy tarreau9fe663a2005-12-17 13:02:59 +01008170 if (global.maxconn == 0)
8171 global.maxconn = DEFAULT_MAXCONN;
8172
Willy TARREAU203b0b62006-03-12 18:00:28 +01008173 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008174
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008175 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008176 /* command line debug mode inhibits configuration mode */
8177 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8178 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008179 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8180 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008181
8182 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8183 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8184 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8185 }
8186
8187 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008188 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8189 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008190 global.nbproc = 1;
8191 }
8192
8193 if (global.nbproc < 1)
8194 global.nbproc = 1;
8195
willy tarreau0f7af912005-12-17 12:21:26 +01008196 StaticReadEvent = (fd_set *)calloc(1,
8197 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008198 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008199 StaticWriteEvent = (fd_set *)calloc(1,
8200 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008201 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008202
8203 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008204 sizeof(struct fdtab) * (global.maxsock));
8205 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008206 fdtab[i].state = FD_STCLOSE;
8207 }
8208}
8209
8210/*
willy tarreau41310e72006-03-25 18:17:56 +01008211 * this function starts all the proxies. Its return value is composed from
8212 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8213 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008214 */
willy tarreau41310e72006-03-25 18:17:56 +01008215int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008216 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008217 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008218 int err = ERR_NONE;
8219 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008220
8221 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008222 if (curproxy->state != PR_STNEW)
8223 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008224
willy tarreau41310e72006-03-25 18:17:56 +01008225 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008226 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008227 if (listener->fd != -1)
8228 continue; /* already initialized */
8229
8230 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8231 if (verbose)
8232 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8233 curproxy->id);
8234 err |= ERR_RETRYABLE;
8235 pxerr |= 1;
8236 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008237 }
willy tarreau0f7af912005-12-17 12:21:26 +01008238
willy tarreaua41a8b42005-12-17 14:02:24 +01008239 if (fd >= global.maxsock) {
8240 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8241 curproxy->id);
8242 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008243 err |= ERR_FATAL;
8244 pxerr |= 1;
8245 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008246 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008247
willy tarreaua41a8b42005-12-17 14:02:24 +01008248 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8249 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8250 (char *) &one, sizeof(one)) == -1)) {
8251 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8252 curproxy->id);
8253 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008254 err |= ERR_FATAL;
8255 pxerr |= 1;
8256 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008257 }
willy tarreau0f7af912005-12-17 12:21:26 +01008258
willy tarreaua41a8b42005-12-17 14:02:24 +01008259 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8260 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8261 curproxy->id);
8262 }
willy tarreau0f7af912005-12-17 12:21:26 +01008263
willy tarreaua41a8b42005-12-17 14:02:24 +01008264 if (bind(fd,
8265 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008266 listener->addr.ss_family == AF_INET6 ?
8267 sizeof(struct sockaddr_in6) :
8268 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008269 if (verbose)
8270 Alert("cannot bind socket for proxy %s. Aborting.\n",
8271 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008272 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008273 err |= ERR_RETRYABLE;
8274 pxerr |= 1;
8275 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008276 }
willy tarreau0f7af912005-12-17 12:21:26 +01008277
willy tarreaua41a8b42005-12-17 14:02:24 +01008278 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008279 if (verbose)
8280 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8281 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008282 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008283 err |= ERR_RETRYABLE;
8284 pxerr |= 1;
8285 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008286 }
willy tarreau0f7af912005-12-17 12:21:26 +01008287
willy tarreau41310e72006-03-25 18:17:56 +01008288 /* the socket is ready */
8289 listener->fd = fd;
8290
willy tarreaua41a8b42005-12-17 14:02:24 +01008291 /* the function for the accept() event */
8292 fdtab[fd].read = &event_accept;
8293 fdtab[fd].write = NULL; /* never called */
8294 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008295 fdtab[fd].state = FD_STLISTEN;
8296 FD_SET(fd, StaticReadEvent);
8297 fd_insert(fd);
8298 listeners++;
8299 }
willy tarreau41310e72006-03-25 18:17:56 +01008300
8301 if (!pxerr) {
8302 curproxy->state = PR_STRUN;
8303 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8304 }
willy tarreau0f7af912005-12-17 12:21:26 +01008305 }
willy tarreau41310e72006-03-25 18:17:56 +01008306
8307 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008308}
8309
willy tarreaub952e1d2005-12-18 01:31:20 +01008310int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008311
8312 appsess *temp1,*temp2;
8313 temp1 = (appsess *)key1;
8314 temp2 = (appsess *)key2;
8315
8316 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8317 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8318
8319 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8320}/* end match_str */
8321
willy tarreaub952e1d2005-12-18 01:31:20 +01008322void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008323 appsess *temp1;
8324
8325 //printf("destroy called\n");
8326 temp1 = (appsess *)data;
8327
8328 if (temp1->sessid)
8329 pool_free_to(apools.sessid, temp1->sessid);
8330
8331 if (temp1->serverid)
8332 pool_free_to(apools.serverid, temp1->serverid);
8333
8334 pool_free(appsess, temp1);
8335} /* end destroy */
8336
8337void appsession_cleanup( void )
8338{
8339 struct proxy *p = proxy;
8340
8341 while(p) {
8342 chtbl_destroy(&(p->htbl_proxy));
8343 p = p->next;
8344 }
8345}/* end appsession_cleanup() */
8346
8347void pool_destroy(void **pool)
8348{
8349 void *temp, *next;
8350 next = pool;
8351 while (next) {
8352 temp = next;
8353 next = *(void **)temp;
8354 free(temp);
8355 }
8356}/* end pool_destroy() */
8357
willy tarreaub952e1d2005-12-18 01:31:20 +01008358void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008359 struct proxy *p = proxy;
8360 struct cap_hdr *h,*h_next;
8361 struct server *s,*s_next;
8362 struct listener *l,*l_next;
8363
8364 while (p) {
8365 if (p->id)
8366 free(p->id);
8367
8368 if (p->check_req)
8369 free(p->check_req);
8370
8371 if (p->cookie_name)
8372 free(p->cookie_name);
8373
8374 if (p->capture_name)
8375 free(p->capture_name);
8376
8377 /* only strup if the user have set in config.
8378 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008379 if (p->errmsg.msg400) free(p->errmsg.msg400);
8380 if (p->errmsg.msg403) free(p->errmsg.msg403);
8381 if (p->errmsg.msg408) free(p->errmsg.msg408);
8382 if (p->errmsg.msg500) free(p->errmsg.msg500);
8383 if (p->errmsg.msg502) free(p->errmsg.msg502);
8384 if (p->errmsg.msg503) free(p->errmsg.msg503);
8385 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008386 */
8387 if (p->appsession_name)
8388 free(p->appsession_name);
8389
8390 h = p->req_cap;
8391 while (h) {
8392 h_next = h->next;
8393 if (h->name)
8394 free(h->name);
8395 pool_destroy(h->pool);
8396 free(h);
8397 h = h_next;
8398 }/* end while(h) */
8399
8400 h = p->rsp_cap;
8401 while (h) {
8402 h_next = h->next;
8403 if (h->name)
8404 free(h->name);
8405
8406 pool_destroy(h->pool);
8407 free(h);
8408 h = h_next;
8409 }/* end while(h) */
8410
8411 s = p->srv;
8412 while (s) {
8413 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008414 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008415 free(s->id);
8416
willy tarreaub952e1d2005-12-18 01:31:20 +01008417 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008418 free(s->cookie);
8419
8420 free(s);
8421 s = s_next;
8422 }/* end while(s) */
8423
8424 l = p->listen;
8425 while (l) {
8426 l_next = l->next;
8427 free(l);
8428 l = l_next;
8429 }/* end while(l) */
8430
8431 pool_destroy((void **) p->req_cap_pool);
8432 pool_destroy((void **) p->rsp_cap_pool);
8433 p = p->next;
8434 }/* end while(p) */
8435
8436 if (global.chroot) free(global.chroot);
8437 if (global.pidfile) free(global.pidfile);
8438
willy tarreau12350152005-12-18 01:03:27 +01008439 if (StaticReadEvent) free(StaticReadEvent);
8440 if (StaticWriteEvent) free(StaticWriteEvent);
8441 if (fdtab) free(fdtab);
8442
8443 pool_destroy(pool_session);
8444 pool_destroy(pool_buffer);
8445 pool_destroy(pool_fdtab);
8446 pool_destroy(pool_requri);
8447 pool_destroy(pool_task);
8448 pool_destroy(pool_capture);
8449 pool_destroy(pool_appsess);
8450
8451 if (have_appsession) {
8452 pool_destroy(apools.serverid);
8453 pool_destroy(apools.sessid);
8454 }
8455} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008456
willy tarreau41310e72006-03-25 18:17:56 +01008457/* sends the signal <sig> to all pids found in <oldpids> */
8458static void tell_old_pids(int sig) {
8459 int p;
8460 for (p = 0; p < nb_oldpids; p++)
8461 kill(oldpids[p], sig);
8462}
8463
willy tarreau0f7af912005-12-17 12:21:26 +01008464int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008465 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008466 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008467 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008468 init(argc, argv);
8469
willy tarreau0f7af912005-12-17 12:21:26 +01008470 signal(SIGQUIT, dump);
8471 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008472 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008473#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008474 signal(SIGINT, sig_int);
8475 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008476#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008477
8478 /* on very high loads, a sigpipe sometimes happen just between the
8479 * getsockopt() which tells "it's OK to write", and the following write :-(
8480 */
willy tarreau3242e862005-12-17 12:27:53 +01008481#ifndef MSG_NOSIGNAL
8482 signal(SIGPIPE, SIG_IGN);
8483#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008484
willy tarreau41310e72006-03-25 18:17:56 +01008485 /* We will loop at most 100 times with 10 ms delay each time.
8486 * That's at most 1 second. We only send a signal to old pids
8487 * if we cannot grab at least one port.
8488 */
8489 retry = MAX_START_RETRIES;
8490 err = ERR_NONE;
8491 while (retry >= 0) {
8492 struct timeval w;
8493 err = start_proxies(retry == 0 || nb_oldpids == 0);
8494 if (err != ERR_RETRYABLE)
8495 break;
8496 if (nb_oldpids == 0)
8497 break;
8498
8499 tell_old_pids(SIGTTOU);
8500 /* give some time to old processes to stop listening */
8501 w.tv_sec = 0;
8502 w.tv_usec = 10*1000;
8503 select(0, NULL, NULL, NULL, &w);
8504 retry--;
8505 }
8506
8507 /* Note: start_proxies() sends an alert when it fails. */
8508 if (err != ERR_NONE) {
8509 if (retry != MAX_START_RETRIES && nb_oldpids)
8510 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008511 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008512 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008513
8514 if (listeners == 0) {
8515 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008516 /* Note: we don't have to send anything to the old pids because we
8517 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008518 exit(1);
8519 }
8520
willy tarreaudbd3bef2006-01-20 19:35:18 +01008521 /* prepare pause/play signals */
8522 signal(SIGTTOU, sig_pause);
8523 signal(SIGTTIN, sig_listen);
8524
Willy TARREAUe3283d12006-03-01 22:15:29 +01008525 if (global.mode & MODE_DAEMON) {
8526 global.mode &= ~MODE_VERBOSE;
8527 global.mode |= MODE_QUIET;
8528 }
8529
willy tarreaud0fb4652005-12-18 01:32:04 +01008530 /* MODE_QUIET can inhibit alerts and warnings below this line */
8531
8532 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008533 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008534 /* detach from the tty */
8535 fclose(stdin); fclose(stdout); fclose(stderr);
8536 close(0); close(1); close(2);
8537 }
willy tarreau0f7af912005-12-17 12:21:26 +01008538
willy tarreaufe2c5c12005-12-17 14:14:34 +01008539 /* open log & pid files before the chroot */
8540 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8541 int pidfd;
8542 unlink(global.pidfile);
8543 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8544 if (pidfd < 0) {
8545 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008546 if (nb_oldpids)
8547 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008548 exit(1);
8549 }
8550 pidfile = fdopen(pidfd, "w");
8551 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008552
8553 /* chroot if needed */
8554 if (global.chroot != NULL) {
8555 if (chroot(global.chroot) == -1) {
8556 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008557 if (nb_oldpids)
8558 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008559 }
8560 chdir("/");
8561 }
8562
willy tarreaub1285d52005-12-18 01:20:14 +01008563 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008564 if (!global.rlimit_nofile)
8565 global.rlimit_nofile = global.maxsock;
8566
willy tarreaub1285d52005-12-18 01:20:14 +01008567 if (global.rlimit_nofile) {
8568 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8569 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8570 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8571 }
willy tarreau746e26b2006-03-25 11:14:35 +01008572 }
8573
8574 if (global.rlimit_memmax) {
8575 limit.rlim_cur = limit.rlim_max =
8576 global.rlimit_memmax * 1048576 / global.nbproc;
8577#ifdef RLIMIT_AS
8578 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8579 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8580 argv[0], global.rlimit_memmax);
8581 }
8582#else
8583 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8584 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8585 argv[0], global.rlimit_memmax);
8586 }
8587#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008588 }
8589
willy tarreau41310e72006-03-25 18:17:56 +01008590 if (nb_oldpids)
8591 tell_old_pids(oldpids_sig);
8592
8593 /* Note that any error at this stage will be fatal because we will not
8594 * be able to restart the old pids.
8595 */
8596
willy tarreau9fe663a2005-12-17 13:02:59 +01008597 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008598 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008599 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8600 exit(1);
8601 }
8602
willy tarreau036e1ce2005-12-17 13:46:33 +01008603 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008604 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8605 exit(1);
8606 }
8607
willy tarreaub1285d52005-12-18 01:20:14 +01008608 /* check ulimits */
8609 limit.rlim_cur = limit.rlim_max = 0;
8610 getrlimit(RLIMIT_NOFILE, &limit);
8611 if (limit.rlim_cur < global.maxsock) {
8612 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",
8613 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8614 }
8615
willy tarreau9fe663a2005-12-17 13:02:59 +01008616 if (global.mode & MODE_DAEMON) {
8617 int ret = 0;
8618 int proc;
8619
8620 /* the father launches the required number of processes */
8621 for (proc = 0; proc < global.nbproc; proc++) {
8622 ret = fork();
8623 if (ret < 0) {
8624 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008625 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008626 exit(1); /* there has been an error */
8627 }
8628 else if (ret == 0) /* child breaks here */
8629 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008630 if (pidfile != NULL) {
8631 fprintf(pidfile, "%d\n", ret);
8632 fflush(pidfile);
8633 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008634 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008635 /* close the pidfile both in children and father */
8636 if (pidfile != NULL)
8637 fclose(pidfile);
8638 free(global.pidfile);
8639
willy tarreau9fe663a2005-12-17 13:02:59 +01008640 if (proc == global.nbproc)
8641 exit(0); /* parent must leave */
8642
willy tarreau750a4722005-12-17 13:21:24 +01008643 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8644 * that we can detach from the TTY. We MUST NOT do it in other cases since
8645 * it would have already be done, and 0-2 would have been affected to listening
8646 * sockets
8647 */
8648 if (!(global.mode & MODE_QUIET)) {
8649 /* detach from the tty */
8650 fclose(stdin); fclose(stdout); fclose(stderr);
8651 close(0); close(1); close(2); /* close all fd's */
8652 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8653 }
willy tarreaua1598082005-12-17 13:08:06 +01008654 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008655 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008656 }
8657
willy tarreau1c2ad212005-12-18 01:11:29 +01008658#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008659 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008660 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8661 epoll_loop(POLL_LOOP_ACTION_RUN);
8662 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008663 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008664 }
8665 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008666 Warning("epoll() is not available. Using poll()/select() instead.\n");
8667 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008668 }
8669 }
8670#endif
8671
8672#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008673 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008674 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8675 poll_loop(POLL_LOOP_ACTION_RUN);
8676 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008677 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008678 }
8679 else {
8680 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008681 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008682 }
8683 }
8684#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008685 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008686 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8687 select_loop(POLL_LOOP_ACTION_RUN);
8688 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008689 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008690 }
8691 }
8692
willy tarreau0f7af912005-12-17 12:21:26 +01008693
willy tarreau12350152005-12-18 01:03:27 +01008694 /* Free all Hash Keys and all Hash elements */
8695 appsession_cleanup();
8696 /* Do some cleanup */
8697 deinit();
8698
willy tarreau0f7af912005-12-17 12:21:26 +01008699 exit(0);
8700}
willy tarreau12350152005-12-18 01:03:27 +01008701
8702#if defined(DEBUG_HASH)
8703static void print_table(const CHTbl *htbl) {
8704
8705 ListElmt *element;
8706 int i;
8707 appsess *asession;
8708
8709 /*****************************************************************************
8710 * *
8711 * Display the chained hash table. *
8712 * *
8713 *****************************************************************************/
8714
8715 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8716
8717 for (i = 0; i < TBLSIZ; i++) {
8718 fprintf(stdout, "Bucket[%03d]\n", i);
8719
8720 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8721 //fprintf(stdout, "%c", *(char *)list_data(element));
8722 asession = (appsess *)list_data(element);
8723 fprintf(stdout, "ELEM :%s:", asession->sessid);
8724 fprintf(stdout, " Server :%s: \n", asession->serverid);
8725 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8726 }
8727
8728 fprintf(stdout, "\n");
8729 }
8730 return;
8731} /* end print_table */
8732#endif
8733
8734static int appsession_init(void)
8735{
8736 static int initialized = 0;
8737 int idlen;
8738 struct server *s;
8739 struct proxy *p = proxy;
8740
8741 if (!initialized) {
8742 if (!appsession_task_init()) {
8743 apools.sessid = NULL;
8744 apools.serverid = NULL;
8745 apools.ser_waste = 0;
8746 apools.ser_use = 0;
8747 apools.ser_msize = sizeof(void *);
8748 apools.ses_waste = 0;
8749 apools.ses_use = 0;
8750 apools.ses_msize = sizeof(void *);
8751 while (p) {
8752 s = p->srv;
8753 if (apools.ses_msize < p->appsession_len)
8754 apools.ses_msize = p->appsession_len;
8755 while (s) {
8756 idlen = strlen(s->id);
8757 if (apools.ser_msize < idlen)
8758 apools.ser_msize = idlen;
8759 s = s->next;
8760 }
8761 p = p->next;
8762 }
8763 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8764 apools.ses_msize ++;
8765 }
8766 else {
8767 fprintf(stderr, "appsession_task_init failed\n");
8768 return -1;
8769 }
8770 initialized ++;
8771 }
8772 return 0;
8773}
8774
8775static int appsession_task_init(void)
8776{
8777 static int initialized = 0;
8778 struct task *t;
8779 if (!initialized) {
8780 if ((t = pool_alloc(task)) == NULL)
8781 return -1;
8782 t->next = t->prev = t->rqnext = NULL;
8783 t->wq = LIST_HEAD(wait_queue);
8784 t->state = TASK_IDLE;
8785 t->context = NULL;
8786 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8787 task_queue(t);
8788 t->process = appsession_refresh;
8789 initialized ++;
8790 }
8791 return 0;
8792}
8793
8794static int appsession_refresh(struct task *t) {
8795 struct proxy *p = proxy;
8796 CHTbl *htbl;
8797 ListElmt *element, *last;
8798 int i;
8799 appsess *asession;
8800 void *data;
8801
8802 while (p) {
8803 if (p->appsession_name != NULL) {
8804 htbl = &p->htbl_proxy;
8805 /* if we ever give up the use of TBLSIZ, we need to change this */
8806 for (i = 0; i < TBLSIZ; i++) {
8807 last = NULL;
8808 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8809 asession = (appsess *)list_data(element);
8810 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8811 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8812 int len;
8813 /*
8814 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8815 */
8816 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8817 asession->sessid, asession->serverid?asession->serverid:"(null)");
8818 write(1, trash, len);
8819 }
8820 /* delete the expired element from within the hash table */
8821 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8822 && (htbl->table[i].destroy != NULL)) {
8823 htbl->table[i].destroy(data);
8824 }
8825 if (last == NULL) {/* patient lost his head, get a new one */
8826 element = list_head(&htbl->table[i]);
8827 if (element == NULL) break; /* no heads left, go to next patient */
8828 }
8829 else
8830 element = last;
8831 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8832 else
8833 last = element;
8834 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8835 }
8836 }
8837 p = p->next;
8838 }
8839 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8840 return TBLCHKINT;
8841} /* end appsession_refresh */
8842