blob: 14f68a80b6f2d750f3ab262884c6c95ab13b9feb [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 tarreauc0d4bbd2006-04-15 21:47:50 +020091#define HAPROXY_VERSION "1.2.12"
willy tarreaubfad5742006-03-23 14:19:11 +010092#endif
93
94#ifndef HAPROXY_DATE
willy tarreauc0d4bbd2006-04-15 21:47:50 +020095#define HAPROXY_DATE "2006/04/15"
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 tarreaue3f023f2006-04-08 21:52:24 +0200514 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200515 unsigned int wscore; /* weight score, used during srv map computation */
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 tarreaucc1e2bd2006-04-10 20:32:43 +0200582 struct server *srv; /* known servers */
583 int srv_act, srv_bck; /* # of running servers */
584 int tot_wact, tot_wbck; /* total weights of active and backup servers */
585 struct server **srv_map; /* the server map used to apply weights */
586 int srv_map_sz; /* the size of the effective server map */
587 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100588 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100589 int cookie_len; /* strlen(cookie_name), computed only once */
590 char *appsession_name; /* name of the cookie to look for */
591 int appsession_name_len; /* strlen(appsession_name), computed only once */
592 int appsession_len; /* length of the appsession cookie value to be used */
593 int appsession_timeout;
594 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100595 char *capture_name; /* beginning of the name of the cookie to capture */
596 int capture_namelen; /* length of the cookie name to match */
597 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100598 int clitimeout; /* client I/O timeout (in milliseconds) */
599 int srvtimeout; /* server I/O timeout (in milliseconds) */
600 int contimeout; /* connect timeout (in milliseconds) */
601 char *id; /* proxy id */
602 int nbconn; /* # of active sessions */
603 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100604 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100605 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100606 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100607 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100608 struct proxy *next;
609 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100610 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100611 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100612 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100613 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100614 int nb_reqadd, nb_rspadd;
615 struct hdr_exp *req_exp; /* regular expressions for request headers */
616 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100617 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
618 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
619 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
620 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100621 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100622 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100623 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
624 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100625 struct {
626 char *msg400; /* message for error 400 */
627 int len400; /* message length for error 400 */
628 char *msg403; /* message for error 403 */
629 int len403; /* message length for error 403 */
630 char *msg408; /* message for error 408 */
631 int len408; /* message length for error 408 */
632 char *msg500; /* message for error 500 */
633 int len500; /* message length for error 500 */
634 char *msg502; /* message for error 502 */
635 int len502; /* message length for error 502 */
636 char *msg503; /* message for error 503 */
637 int len503; /* message length for error 503 */
638 char *msg504; /* message for error 504 */
639 int len504; /* message length for error 504 */
640 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100641};
642
643/* info about one given fd */
644struct fdtab {
645 int (*read)(int fd); /* read function */
646 int (*write)(int fd); /* write function */
647 struct task *owner; /* the session (or proxy) associated with this fd */
648 int state; /* the state of this fd */
649};
650
651/*********************************************************************/
652
willy tarreaub952e1d2005-12-18 01:31:20 +0100653int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100654int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100655char *cfg_cfgfile = NULL; /* configuration file */
656char *progname = NULL; /* program name */
657int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100658
659/* global options */
660static struct {
661 int uid;
662 int gid;
663 int nbproc;
664 int maxconn;
665 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100666 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100667 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100668 int mode;
669 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100670 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100671 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100672 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100673 struct sockaddr_in logsrv1, logsrv2;
674} global = {
675 logfac1 : -1,
676 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100677 loglev1 : 7, /* max syslog level : debug */
678 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100679 /* others NULL OK */
680};
681
willy tarreau0f7af912005-12-17 12:21:26 +0100682/*********************************************************************/
683
willy tarreau1c2ad212005-12-18 01:11:29 +0100684fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100685 *StaticWriteEvent;
686
willy tarreau64a3cc32005-12-18 01:13:11 +0100687int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100688
willy tarreau0f7af912005-12-17 12:21:26 +0100689void **pool_session = NULL,
690 **pool_buffer = NULL,
691 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100692 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100693 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100694 **pool_capture = NULL,
695 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100696
697struct proxy *proxy = NULL; /* list of all existing proxies */
698struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100699struct task *rq = NULL; /* global run queue */
700struct task wait_queue = { /* global wait queue */
701 prev:LIST_HEAD(wait_queue),
702 next:LIST_HEAD(wait_queue)
703};
willy tarreau0f7af912005-12-17 12:21:26 +0100704
willy tarreau0f7af912005-12-17 12:21:26 +0100705static int totalconn = 0; /* total # of terminated sessions */
706static int actconn = 0; /* # of active sessions */
707static int maxfd = 0; /* # of the highest fd + 1 */
708static int listeners = 0; /* # of listeners */
709static int stopping = 0; /* non zero means stopping in progress */
710static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100711static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100712
willy tarreau53e99702006-03-25 18:53:50 +0100713/* Here we store informations about the pids of the processes we may pause
714 * or kill. We will send them a signal every 10 ms until we can bind to all
715 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100716 */
willy tarreau53e99702006-03-25 18:53:50 +0100717#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100718static int nb_oldpids = 0;
719static int *oldpids = NULL;
720static int oldpids_sig; /* use USR1 or TERM */
721
willy tarreau08dedbe2005-12-18 01:13:48 +0100722#if defined(ENABLE_EPOLL)
723/* FIXME: this is dirty, but at the moment, there's no other solution to remove
724 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
725 * structure with pointers to functions such as init_fd() and close_fd(), plus
726 * a private structure with several pointers to places such as below.
727 */
728
729static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
730#endif
731
willy tarreau0f7af912005-12-17 12:21:26 +0100732static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100733/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100734static char trash[BUFSIZE];
735
willy tarreaudd07e972005-12-18 00:48:48 +0100736const int zero = 0;
737const int one = 1;
738
willy tarreau0f7af912005-12-17 12:21:26 +0100739/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100740 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100741 */
742
743#define MAX_SYSLOG_LEN 1024
744#define NB_LOG_FACILITIES 24
745const char *log_facilities[NB_LOG_FACILITIES] = {
746 "kern", "user", "mail", "daemon",
747 "auth", "syslog", "lpr", "news",
748 "uucp", "cron", "auth2", "ftp",
749 "ntp", "audit", "alert", "cron2",
750 "local0", "local1", "local2", "local3",
751 "local4", "local5", "local6", "local7"
752};
753
754
755#define NB_LOG_LEVELS 8
756const char *log_levels[NB_LOG_LEVELS] = {
757 "emerg", "alert", "crit", "err",
758 "warning", "notice", "info", "debug"
759};
760
761#define SYSLOG_PORT 514
762
763const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
764 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100765
willy tarreaub1285d52005-12-18 01:20:14 +0100766const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100767const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
768const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
769const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
770 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
771 unknown, Set-cookie Rewritten */
772
willy tarreau0f7af912005-12-17 12:21:26 +0100773#define MAX_HOSTNAME_LEN 32
774static char hostname[MAX_HOSTNAME_LEN] = "";
775
willy tarreau8337c6b2005-12-17 13:41:01 +0100776const char *HTTP_302 =
777 "HTTP/1.0 302 Found\r\n"
778 "Cache-Control: no-cache\r\n"
779 "Connection: close\r\n"
780 "Location: "; /* not terminated since it will be concatenated with the URL */
781
willy tarreauc1f47532005-12-18 01:08:26 +0100782/* same as 302 except that the browser MUST retry with the GET method */
783const char *HTTP_303 =
784 "HTTP/1.0 303 See Other\r\n"
785 "Cache-Control: no-cache\r\n"
786 "Connection: close\r\n"
787 "Location: "; /* not terminated since it will be concatenated with the URL */
788
willy tarreaua1598082005-12-17 13:08:06 +0100789const char *HTTP_400 =
790 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100791 "Cache-Control: no-cache\r\n"
792 "Connection: close\r\n"
793 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100794 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100795
willy tarreaua1598082005-12-17 13:08:06 +0100796const char *HTTP_403 =
797 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100798 "Cache-Control: no-cache\r\n"
799 "Connection: close\r\n"
800 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100801 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
802
willy tarreau8337c6b2005-12-17 13:41:01 +0100803const char *HTTP_408 =
804 "HTTP/1.0 408 Request Time-out\r\n"
805 "Cache-Control: no-cache\r\n"
806 "Connection: close\r\n"
807 "\r\n"
808 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
809
willy tarreau750a4722005-12-17 13:21:24 +0100810const char *HTTP_500 =
811 "HTTP/1.0 500 Server Error\r\n"
812 "Cache-Control: no-cache\r\n"
813 "Connection: close\r\n"
814 "\r\n"
815 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100816
817const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100818 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100819 "Cache-Control: no-cache\r\n"
820 "Connection: close\r\n"
821 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100822 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
823
824const char *HTTP_503 =
825 "HTTP/1.0 503 Service Unavailable\r\n"
826 "Cache-Control: no-cache\r\n"
827 "Connection: close\r\n"
828 "\r\n"
829 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
830
831const char *HTTP_504 =
832 "HTTP/1.0 504 Gateway Time-out\r\n"
833 "Cache-Control: no-cache\r\n"
834 "Connection: close\r\n"
835 "\r\n"
836 "<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 +0100837
willy tarreau0f7af912005-12-17 12:21:26 +0100838/*********************************************************************/
839/* statistics ******************************************************/
840/*********************************************************************/
841
willy tarreau750a4722005-12-17 13:21:24 +0100842#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100843static int stats_tsk_lsrch, stats_tsk_rsrch,
844 stats_tsk_good, stats_tsk_right, stats_tsk_left,
845 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100846#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100847
848
849/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100850/* debugging *******************************************************/
851/*********************************************************************/
852#ifdef DEBUG_FULL
853static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
854static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
855#endif
856
857/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100858/* function prototypes *********************************************/
859/*********************************************************************/
860
861int event_accept(int fd);
862int event_cli_read(int fd);
863int event_cli_write(int fd);
864int event_srv_read(int fd);
865int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100866int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100867
willy tarreau12350152005-12-18 01:03:27 +0100868static int appsession_task_init(void);
869static int appsession_init(void);
870static int appsession_refresh(struct task *t);
871
willy tarreau0f7af912005-12-17 12:21:26 +0100872/*********************************************************************/
873/* general purpose functions ***************************************/
874/*********************************************************************/
875
876void display_version() {
877 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100878 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100879}
880
881/*
882 * This function prints the command line usage and exits
883 */
884void usage(char *name) {
885 display_version();
886 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100887 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100888#if STATTIME > 0
889 "sl"
890#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100891 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
892 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100893 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100894 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100895 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100896#if STATTIME > 0
897 " -s enables statistics output\n"
898 " -l enables long statistics format\n"
899#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100900 " -D goes daemon ; implies -q\n"
901 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100902 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100903 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100904 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100905 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100906 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100907#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100908 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100909#endif
910#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100911 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100912#endif
willy tarreau53e99702006-03-25 18:53:50 +0100913 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100914 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100915 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100916 exit(1);
917}
918
919
920/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100921 * Displays the message on stderr with the date and pid. Overrides the quiet
922 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100923 */
924void Alert(char *fmt, ...) {
925 va_list argp;
926 struct timeval tv;
927 struct tm *tm;
928
willy tarreaud0fb4652005-12-18 01:32:04 +0100929 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100930 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100931
willy tarreau5cbea6f2005-12-17 12:48:26 +0100932 gettimeofday(&tv, NULL);
933 tm=localtime(&tv.tv_sec);
934 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100935 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100936 vfprintf(stderr, fmt, argp);
937 fflush(stderr);
938 va_end(argp);
939 }
willy tarreau0f7af912005-12-17 12:21:26 +0100940}
941
942
943/*
944 * Displays the message on stderr with the date and pid.
945 */
946void Warning(char *fmt, ...) {
947 va_list argp;
948 struct timeval tv;
949 struct tm *tm;
950
willy tarreau982249e2005-12-18 00:57:06 +0100951 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100952 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100953
willy tarreau5cbea6f2005-12-17 12:48:26 +0100954 gettimeofday(&tv, NULL);
955 tm=localtime(&tv.tv_sec);
956 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100957 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100958 vfprintf(stderr, fmt, argp);
959 fflush(stderr);
960 va_end(argp);
961 }
962}
963
964/*
965 * Displays the message on <out> only if quiet mode is not set.
966 */
967void qfprintf(FILE *out, char *fmt, ...) {
968 va_list argp;
969
willy tarreau982249e2005-12-18 00:57:06 +0100970 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100971 va_start(argp, fmt);
972 vfprintf(out, fmt, argp);
973 fflush(out);
974 va_end(argp);
975 }
willy tarreau0f7af912005-12-17 12:21:26 +0100976}
977
978
979/*
980 * converts <str> to a struct sockaddr_in* which is locally allocated.
981 * The format is "addr:port", where "addr" can be empty or "*" to indicate
982 * INADDR_ANY.
983 */
984struct sockaddr_in *str2sa(char *str) {
985 static struct sockaddr_in sa;
986 char *c;
987 int port;
988
willy tarreaua1598082005-12-17 13:08:06 +0100989 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100990 str=strdup(str);
991
992 if ((c=strrchr(str,':')) != NULL) {
993 *c++=0;
994 port=atol(c);
995 }
996 else
997 port=0;
998
999 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1000 sa.sin_addr.s_addr = INADDR_ANY;
1001 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001002 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001003 struct hostent *he;
1004
1005 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001006 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001007 }
1008 else
1009 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1010 }
1011 sa.sin_port=htons(port);
1012 sa.sin_family=AF_INET;
1013
1014 free(str);
1015 return &sa;
1016}
1017
willy tarreaub1285d52005-12-18 01:20:14 +01001018/*
1019 * converts <str> to a two struct in_addr* which are locally allocated.
1020 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1021 * is optionnal and either in the dotted or CIDR notation.
1022 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1023 */
1024int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1025 char *c;
1026 unsigned long len;
1027
1028 memset(mask, 0, sizeof(*mask));
1029 memset(addr, 0, sizeof(*addr));
1030 str=strdup(str);
1031
1032 if ((c = strrchr(str, '/')) != NULL) {
1033 *c++ = 0;
1034 /* c points to the mask */
1035 if (strchr(c, '.') != NULL) { /* dotted notation */
1036 if (!inet_pton(AF_INET, c, mask))
1037 return 0;
1038 }
1039 else { /* mask length */
1040 char *err;
1041 len = strtol(c, &err, 10);
1042 if (!*c || (err && *err) || (unsigned)len > 32)
1043 return 0;
1044 if (len)
1045 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1046 else
1047 mask->s_addr = 0;
1048 }
1049 }
1050 else {
1051 mask->s_addr = 0xFFFFFFFF;
1052 }
1053 if (!inet_pton(AF_INET, str, addr)) {
1054 struct hostent *he;
1055
1056 if ((he = gethostbyname(str)) == NULL) {
1057 return 0;
1058 }
1059 else
1060 *addr = *(struct in_addr *) *(he->h_addr_list);
1061 }
1062 free(str);
1063 return 1;
1064}
1065
willy tarreau9fe663a2005-12-17 13:02:59 +01001066
1067/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001068 * converts <str> to a list of listeners which are dynamically allocated.
1069 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1070 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1071 * - <port> is a numerical port from 1 to 65535 ;
1072 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1073 * This can be repeated as many times as necessary, separated by a coma.
1074 * The <tail> argument is a pointer to a current list which should be appended
1075 * to the tail of the new list. The pointer to the new list is returned.
1076 */
1077struct listener *str2listener(char *str, struct listener *tail) {
1078 struct listener *l;
1079 char *c, *next, *range, *dupstr;
1080 int port, end;
1081
1082 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001083
willy tarreaua41a8b42005-12-17 14:02:24 +01001084 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001085 struct sockaddr_storage ss;
1086
willy tarreaua41a8b42005-12-17 14:02:24 +01001087 str = next;
1088 /* 1) look for the end of the first address */
1089 if ((next = strrchr(str, ',')) != NULL) {
1090 *next++ = 0;
1091 }
1092
willy tarreau8a86dbf2005-12-18 00:45:59 +01001093 /* 2) look for the addr/port delimiter, it's the last colon. */
1094 if ((range = strrchr(str, ':')) == NULL) {
1095 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001096 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001097 }
1098
1099 *range++ = 0;
1100
1101 if (strrchr(str, ':') != NULL) {
1102 /* IPv6 address contains ':' */
1103 memset(&ss, 0, sizeof(ss));
1104 ss.ss_family = AF_INET6;
1105
1106 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1107 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001108 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001109 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001110 }
1111 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001112 memset(&ss, 0, sizeof(ss));
1113 ss.ss_family = AF_INET;
1114
1115 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1116 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1117 }
1118 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1119 struct hostent *he;
1120
1121 if ((he = gethostbyname(str)) == NULL) {
1122 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001123 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001124 }
1125 else
1126 ((struct sockaddr_in *)&ss)->sin_addr =
1127 *(struct in_addr *) *(he->h_addr_list);
1128 }
1129 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001130
1131 /* 3) look for the port-end delimiter */
1132 if ((c = strchr(range, '-')) != NULL) {
1133 *c++ = 0;
1134 end = atol(c);
1135 }
1136 else {
1137 end = atol(range);
1138 }
1139
willy tarreaud0fb4652005-12-18 01:32:04 +01001140 port = atol(range);
1141
1142 if (port < 1 || port > 65535) {
1143 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1144 goto fail;
1145 }
1146
1147 if (end < 1 || end > 65535) {
1148 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1149 goto fail;
1150 }
1151
1152 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001153 l = (struct listener *)calloc(1, sizeof(struct listener));
1154 l->next = tail;
1155 tail = l;
1156
willy tarreau41310e72006-03-25 18:17:56 +01001157 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001158 l->addr = ss;
1159 if (ss.ss_family == AF_INET6)
1160 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1161 else
1162 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1163
willy tarreaua41a8b42005-12-17 14:02:24 +01001164 } /* end for(port) */
1165 } /* end while(next) */
1166 free(dupstr);
1167 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001168 fail:
1169 free(dupstr);
1170 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001171}
1172
willy tarreau4302f492005-12-18 01:00:37 +01001173
1174#define FD_SETS_ARE_BITFIELDS
1175#ifdef FD_SETS_ARE_BITFIELDS
1176/*
1177 * This map is used with all the FD_* macros to check whether a particular bit
1178 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1179 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1180 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1181 * exclusively to the macros.
1182 */
1183fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1184fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1185
1186#else
1187#error "Check if your OS uses bitfields for fd_sets"
1188#endif
1189
1190/* will try to encode the string <string> replacing all characters tagged in
1191 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1192 * prefixed by <escape>, and will store the result between <start> (included
1193 *) and <stop> (excluded), and will always terminate the string with a '\0'
1194 * before <stop>. The position of the '\0' is returned if the conversion
1195 * completes. If bytes are missing between <start> and <stop>, then the
1196 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1197 * cannot even be stored so we return <start> without writing the 0.
1198 * The input string must also be zero-terminated.
1199 */
1200char hextab[16] = "0123456789ABCDEF";
1201char *encode_string(char *start, char *stop,
1202 const char escape, const fd_set *map,
1203 const char *string)
1204{
1205 if (start < stop) {
1206 stop--; /* reserve one byte for the final '\0' */
1207 while (start < stop && *string != 0) {
1208 if (!FD_ISSET((unsigned char)(*string), map))
1209 *start++ = *string;
1210 else {
1211 if (start + 3 >= stop)
1212 break;
1213 *start++ = escape;
1214 *start++ = hextab[(*string >> 4) & 15];
1215 *start++ = hextab[*string & 15];
1216 }
1217 string++;
1218 }
1219 *start = '\0';
1220 }
1221 return start;
1222}
willy tarreaua41a8b42005-12-17 14:02:24 +01001223
1224/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001225 * This function sends a syslog message to both log servers of a proxy,
1226 * or to global log servers if the proxy is NULL.
1227 * It also tries not to waste too much time computing the message header.
1228 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001229 */
1230void send_log(struct proxy *p, int level, char *message, ...) {
1231 static int logfd = -1; /* syslog UDP socket */
1232 static long tvsec = -1; /* to force the string to be initialized */
1233 struct timeval tv;
1234 va_list argp;
1235 static char logmsg[MAX_SYSLOG_LEN];
1236 static char *dataptr = NULL;
1237 int fac_level;
1238 int hdr_len, data_len;
1239 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001240 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001241 int nbloggers = 0;
1242 char *log_ptr;
1243
1244 if (logfd < 0) {
1245 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1246 return;
1247 }
1248
1249 if (level < 0 || progname == NULL || message == NULL)
1250 return;
1251
1252 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001253 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001254 /* this string is rebuild only once a second */
1255 struct tm *tm = localtime(&tv.tv_sec);
1256 tvsec = tv.tv_sec;
1257
willy tarreauc29948c2005-12-17 13:10:27 +01001258 hdr_len = snprintf(logmsg, sizeof(logmsg),
1259 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1260 monthname[tm->tm_mon],
1261 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1262 progname, pid);
1263 /* WARNING: depending upon implementations, snprintf may return
1264 * either -1 or the number of bytes that would be needed to store
1265 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001266 */
willy tarreauc29948c2005-12-17 13:10:27 +01001267 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1268 hdr_len = sizeof(logmsg);
1269
1270 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001271 }
1272
1273 va_start(argp, message);
1274 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001275 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1276 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001277 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001278 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001279
1280 if (p == NULL) {
1281 if (global.logfac1 >= 0) {
1282 sa[nbloggers] = &global.logsrv1;
1283 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001284 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001285 nbloggers++;
1286 }
1287 if (global.logfac2 >= 0) {
1288 sa[nbloggers] = &global.logsrv2;
1289 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001290 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001291 nbloggers++;
1292 }
1293 } else {
1294 if (p->logfac1 >= 0) {
1295 sa[nbloggers] = &p->logsrv1;
1296 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001297 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001298 nbloggers++;
1299 }
1300 if (p->logfac2 >= 0) {
1301 sa[nbloggers] = &p->logsrv2;
1302 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001303 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001304 nbloggers++;
1305 }
1306 }
1307
1308 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001309 /* we can filter the level of the messages that are sent to each logger */
1310 if (level > loglevel[nbloggers])
1311 continue;
1312
willy tarreauc29948c2005-12-17 13:10:27 +01001313 /* For each target, we may have a different facility.
1314 * We can also have a different log level for each message.
1315 * This induces variations in the message header length.
1316 * Since we don't want to recompute it each time, nor copy it every
1317 * time, we only change the facility in the pre-computed header,
1318 * and we change the pointer to the header accordingly.
1319 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001320 fac_level = (facilities[nbloggers] << 3) + level;
1321 log_ptr = logmsg + 3; /* last digit of the log level */
1322 do {
1323 *log_ptr = '0' + fac_level % 10;
1324 fac_level /= 10;
1325 log_ptr--;
1326 } while (fac_level && log_ptr > logmsg);
1327 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001328
willy tarreauc29948c2005-12-17 13:10:27 +01001329 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001330
1331#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001332 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001333 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1334#else
willy tarreauc29948c2005-12-17 13:10:27 +01001335 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001336 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1337#endif
1338 }
willy tarreau0f7af912005-12-17 12:21:26 +01001339}
1340
1341
1342/* sets <tv> to the current time */
1343static inline struct timeval *tv_now(struct timeval *tv) {
1344 if (tv)
1345 gettimeofday(tv, NULL);
1346 return tv;
1347}
1348
1349/*
1350 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1351 */
1352static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1353 if (!tv || !from)
1354 return NULL;
1355 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1356 tv->tv_sec = from->tv_sec + (ms/1000);
1357 while (tv->tv_usec >= 1000000) {
1358 tv->tv_usec -= 1000000;
1359 tv->tv_sec++;
1360 }
1361 return tv;
1362}
1363
1364/*
1365 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001366 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001367 */
1368static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001369 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001370 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001371 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001372 return 1;
1373 else if (tv1->tv_usec < tv2->tv_usec)
1374 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001375 else if (tv1->tv_usec > tv2->tv_usec)
1376 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001377 else
1378 return 0;
1379}
1380
1381/*
1382 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001383 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001384 */
1385unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1386 int cmp;
1387 unsigned long ret;
1388
1389
willy tarreauef900ab2005-12-17 12:52:52 +01001390 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001391 if (!cmp)
1392 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001393 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001394 struct timeval *tmp = tv1;
1395 tv1 = tv2;
1396 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001397 }
willy tarreauef900ab2005-12-17 12:52:52 +01001398 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001399 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001400 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001401 else
willy tarreauef900ab2005-12-17 12:52:52 +01001402 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001403 return (unsigned long) ret;
1404}
1405
1406/*
willy tarreau750a4722005-12-17 13:21:24 +01001407 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001408 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001409 */
1410static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1411 unsigned long ret;
1412
willy tarreau6e682ce2005-12-17 13:26:49 +01001413 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1414 if (tv2->tv_usec > tv1->tv_usec)
1415 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001416 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001417 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001418 return (unsigned long) ret;
1419}
1420
1421/*
willy tarreau0f7af912005-12-17 12:21:26 +01001422 * 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 +01001423 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001424 */
1425static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001426 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001427 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001428 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001429 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001430 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001431 else
1432 return 0;
1433 }
willy tarreau0f7af912005-12-17 12:21:26 +01001434 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001435 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001436 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001437 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001438 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001439 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001440 else
1441 return 0;
1442}
1443
1444/*
1445 * returns the remaining time between tv1=now and event=tv2
1446 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001447 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001448 */
1449static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1450 unsigned long ret;
1451
willy tarreau0f7af912005-12-17 12:21:26 +01001452 if (tv_cmp_ms(tv1, tv2) >= 0)
1453 return 0; /* event elapsed */
1454
willy tarreauef900ab2005-12-17 12:52:52 +01001455 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001456 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001457 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001458 else
willy tarreauef900ab2005-12-17 12:52:52 +01001459 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001460 return (unsigned long) ret;
1461}
1462
1463
1464/*
1465 * zeroes a struct timeval
1466 */
1467
1468static inline struct timeval *tv_eternity(struct timeval *tv) {
1469 tv->tv_sec = tv->tv_usec = 0;
1470 return tv;
1471}
1472
1473/*
1474 * returns 1 if tv is null, else 0
1475 */
1476static inline int tv_iseternity(struct timeval *tv) {
1477 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1478 return 1;
1479 else
1480 return 0;
1481}
1482
1483/*
1484 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1485 * considering that 0 is the eternity.
1486 */
1487static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1488 if (tv_iseternity(tv1))
1489 if (tv_iseternity(tv2))
1490 return 0; /* same */
1491 else
1492 return 1; /* tv1 later than tv2 */
1493 else if (tv_iseternity(tv2))
1494 return -1; /* tv2 later than tv1 */
1495
1496 if (tv1->tv_sec > tv2->tv_sec)
1497 return 1;
1498 else if (tv1->tv_sec < tv2->tv_sec)
1499 return -1;
1500 else if (tv1->tv_usec > tv2->tv_usec)
1501 return 1;
1502 else if (tv1->tv_usec < tv2->tv_usec)
1503 return -1;
1504 else
1505 return 0;
1506}
1507
1508/*
1509 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1510 * considering that 0 is the eternity.
1511 */
1512static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1513 if (tv_iseternity(tv1))
1514 if (tv_iseternity(tv2))
1515 return 0; /* same */
1516 else
1517 return 1; /* tv1 later than tv2 */
1518 else if (tv_iseternity(tv2))
1519 return -1; /* tv2 later than tv1 */
1520
willy tarreauefae1842005-12-17 12:51:03 +01001521 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001522 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001523 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001524 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001525 return -1;
1526 else
1527 return 0;
1528 }
1529 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001530 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001531 return 1;
1532 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001533 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001534 return -1;
1535 else
1536 return 0;
1537}
1538
1539/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001540 * returns the remaining time between tv1=now and event=tv2
1541 * if tv2 is passed, 0 is returned.
1542 * Returns TIME_ETERNITY if tv2 is eternity.
1543 */
1544static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1545 unsigned long ret;
1546
1547 if (tv_iseternity(tv2))
1548 return TIME_ETERNITY;
1549
1550 if (tv_cmp_ms(tv1, tv2) >= 0)
1551 return 0; /* event elapsed */
1552
1553 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1554 if (tv2->tv_usec > tv1->tv_usec)
1555 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1556 else
1557 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1558 return (unsigned long) ret;
1559}
1560
1561/*
willy tarreau0f7af912005-12-17 12:21:26 +01001562 * returns the first event between tv1 and tv2 into tvmin.
1563 * a zero tv is ignored. tvmin is returned.
1564 */
1565static inline struct timeval *tv_min(struct timeval *tvmin,
1566 struct timeval *tv1, struct timeval *tv2) {
1567
1568 if (tv_cmp2(tv1, tv2) <= 0)
1569 *tvmin = *tv1;
1570 else
1571 *tvmin = *tv2;
1572
1573 return tvmin;
1574}
1575
1576
1577
1578/***********************************************************/
1579/* fd management ***************************************/
1580/***********************************************************/
1581
1582
1583
willy tarreau5cbea6f2005-12-17 12:48:26 +01001584/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1585 * The file descriptor is also closed.
1586 */
willy tarreau0f7af912005-12-17 12:21:26 +01001587static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001588 FD_CLR(fd, StaticReadEvent);
1589 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001590#if defined(ENABLE_EPOLL)
1591 if (PrevReadEvent) {
1592 FD_CLR(fd, PrevReadEvent);
1593 FD_CLR(fd, PrevWriteEvent);
1594 }
1595#endif
1596
willy tarreau5cbea6f2005-12-17 12:48:26 +01001597 close(fd);
1598 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001599
1600 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1601 maxfd--;
1602}
1603
1604/* recomputes the maxfd limit from the fd */
1605static inline void fd_insert(int fd) {
1606 if (fd+1 > maxfd)
1607 maxfd = fd+1;
1608}
1609
1610/*************************************************************/
1611/* task management ***************************************/
1612/*************************************************************/
1613
willy tarreau5cbea6f2005-12-17 12:48:26 +01001614/* puts the task <t> in run queue <q>, and returns <t> */
1615static inline struct task *task_wakeup(struct task **q, struct task *t) {
1616 if (t->state == TASK_RUNNING)
1617 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001618 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001619 t->rqnext = *q;
1620 t->state = TASK_RUNNING;
1621 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001622 }
1623}
1624
willy tarreau5cbea6f2005-12-17 12:48:26 +01001625/* removes the task <t> from the queue <q>
1626 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001627 * set the run queue to point to the next one, and return it
1628 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001629static inline struct task *task_sleep(struct task **q, struct task *t) {
1630 if (t->state == TASK_RUNNING) {
1631 *q = t->rqnext;
1632 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001633 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001634 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001635}
1636
1637/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001638 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001639 * from the run queue. A pointer to the task itself is returned.
1640 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001641static inline struct task *task_delete(struct task *t) {
1642 t->prev->next = t->next;
1643 t->next->prev = t->prev;
1644 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001645}
1646
1647/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001648 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001649 */
1650static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001651 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001652}
1653
willy tarreau5cbea6f2005-12-17 12:48:26 +01001654/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001655 * may be only moved or left where it was, depending on its timing requirements.
1656 * <task> is returned.
1657 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001658struct task *task_queue(struct task *task) {
1659 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001660 struct task *start_from;
1661
1662 /* first, test if the task was already in a list */
1663 if (task->prev == NULL) {
1664 // start_from = list;
1665 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001666#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001667 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001668#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001669 /* insert the unlinked <task> into the list, searching back from the last entry */
1670 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1671 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001672#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001673 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001674#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001675 }
1676
1677 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1678 // start_from = start_from->next;
1679 // stats_tsk_nsrch++;
1680 // }
1681 }
1682 else if (task->prev == list ||
1683 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1684 start_from = task->next;
1685 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001686#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001687 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001688#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001689 return task; /* it's already in the right place */
1690 }
1691
willy tarreau750a4722005-12-17 13:21:24 +01001692#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001693 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001694#endif
1695
1696 /* if the task is not at the right place, there's little chance that
1697 * it has only shifted a bit, and it will nearly always be queued
1698 * at the end of the list because of constant timeouts
1699 * (observed in real case).
1700 */
1701#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1702 start_from = list->prev; /* assume we'll queue to the end of the list */
1703 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1704 start_from = start_from->prev;
1705#if STATTIME > 0
1706 stats_tsk_lsrch++;
1707#endif
1708 }
1709#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001710 /* insert the unlinked <task> into the list, searching after position <start_from> */
1711 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1712 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001713#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001714 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001715#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001716 }
willy tarreau750a4722005-12-17 13:21:24 +01001717#endif /* WE_REALLY_... */
1718
willy tarreau0f7af912005-12-17 12:21:26 +01001719 /* we need to unlink it now */
1720 task_delete(task);
1721 }
1722 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001723#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001724 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001725#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001726#ifdef LEFT_TO_TOP /* not very good */
1727 start_from = list;
1728 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1729 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001730#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001731 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001732#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001733 }
1734#else
1735 start_from = task->prev->prev; /* valid because of the previous test above */
1736 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1737 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001738#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001739 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001740#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001741 }
1742#endif
1743 /* we need to unlink it now */
1744 task_delete(task);
1745 }
1746 task->prev = start_from;
1747 task->next = start_from->next;
1748 task->next->prev = task;
1749 start_from->next = task;
1750 return task;
1751}
1752
1753
1754/*********************************************************************/
1755/* more specific functions ***************************************/
1756/*********************************************************************/
1757
1758/* some prototypes */
1759static int maintain_proxies(void);
1760
willy tarreaub952e1d2005-12-18 01:31:20 +01001761/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001762 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1763 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001764static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001765#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001766 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1767#else
willy tarreaua1598082005-12-17 13:08:06 +01001768#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001769 return getsockname(fd, (struct sockaddr *)sa, salen);
1770#else
1771 return -1;
1772#endif
1773#endif
1774}
1775
1776/*
1777 * frees the context associated to a session. It must have been removed first.
1778 */
1779static inline void session_free(struct session *s) {
1780 if (s->req)
1781 pool_free(buffer, s->req);
1782 if (s->rep)
1783 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001784
1785 if (s->rsp_cap != NULL) {
1786 struct cap_hdr *h;
1787 for (h = s->proxy->rsp_cap; h; h = h->next) {
1788 if (s->rsp_cap[h->index] != NULL)
1789 pool_free_to(h->pool, s->rsp_cap[h->index]);
1790 }
1791 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1792 }
1793 if (s->req_cap != NULL) {
1794 struct cap_hdr *h;
1795 for (h = s->proxy->req_cap; h; h = h->next) {
1796 if (s->req_cap[h->index] != NULL)
1797 pool_free_to(h->pool, s->req_cap[h->index]);
1798 }
1799 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1800 }
1801
willy tarreaua1598082005-12-17 13:08:06 +01001802 if (s->logs.uri)
1803 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001804 if (s->logs.cli_cookie)
1805 pool_free(capture, s->logs.cli_cookie);
1806 if (s->logs.srv_cookie)
1807 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001808
willy tarreau5cbea6f2005-12-17 12:48:26 +01001809 pool_free(session, s);
1810}
1811
willy tarreau0f7af912005-12-17 12:21:26 +01001812
1813/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001814 * This function recounts the number of usable active and backup servers for
1815 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001816 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001817 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001818static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001819 struct server *srv;
1820
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001821 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001822 for (srv = px->srv; srv != NULL; srv = srv->next) {
1823 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001824 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001825 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001826 px->tot_wbck += srv->eweight + 1;
1827 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001828 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001829 px->tot_wact += srv->eweight + 1;
1830 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01001831 }
1832 }
1833}
1834
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001835/* This function recomputes the server map for proxy px. It
1836 * relies on px->tot_wact and px->tot_wbck, so it must be
1837 * called after recount_servers(). It also expects px->srv_map
1838 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01001839 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001840static void recalc_server_map(struct proxy *px) {
1841 int o, tot, flag;
1842 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01001843
willy tarreau4c8c2b52006-03-24 19:36:41 +01001844 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001845 flag = SRV_RUNNING;
1846 tot = px->tot_wact;
1847 } else if (px->srv_bck) {
1848 flag = SRV_RUNNING | SRV_BACKUP;
1849 if (px->options & PR_O_USE_ALL_BK)
1850 tot = px->tot_wbck;
1851 else
1852 tot = 1; /* the first server is enough */
1853 } else {
1854 px->srv_map_sz = 0;
1855 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001856 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001857
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001858 /* this algorithm gives priority to the first server, which means that
1859 * it will respect the declaration order for equivalent weights, and
1860 * that whatever the weights, the first server called will always be
1861 * the first declard. This is an important asumption for the backup
1862 * case, where we want the first server only.
1863 */
1864 for (cur = px->srv; cur; cur = cur->next)
1865 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001866
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001867 for (o = 0; o < tot; o++) {
1868 int max = 0;
1869 best = NULL;
1870 for (cur = px->srv; cur; cur = cur->next) {
1871 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
1872 int v;
1873
1874 /* If we are forced to return only one server, we don't want to
1875 * go further, because we would return the wrong one due to
1876 * divide overflow.
1877 */
1878 if (tot == 1) {
1879 best = cur;
1880 break;
1881 }
1882
1883 cur->wscore += cur->eweight + 1;
1884 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
1885 if (best == NULL || v > max) {
1886 max = v;
1887 best = cur;
1888 }
1889 }
1890 }
1891 px->srv_map[o] = best;
1892 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001893 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001894 px->srv_map_sz = tot;
1895}
Willy TARREAU3481c462006-03-01 22:37:57 +01001896
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001897/*
1898 * This function tries to find a running server for the proxy <px> following
1899 * the round-robin method. Depending on the number of active/backup servers,
1900 * it will either look for active servers, or for backup servers.
1901 * If any server is found, it will be returned and px->srv_rr_idx will be updated
1902 * to point to the next server. If no valid server is found, NULL is returned.
1903 */
1904static inline struct server *get_server_rr(struct proxy *px) {
1905 if (px->srv_map_sz == 0)
1906 return NULL;
1907
1908 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
1909 px->srv_rr_idx = 0;
1910 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01001911}
1912
willy tarreau62084d42006-03-24 18:57:41 +01001913
1914/*
willy tarreau1a3442d2006-03-24 21:03:20 +01001915 * This function tries to find a running server for the proxy <px> following
1916 * the source hash method. Depending on the number of active/backup servers,
1917 * it will either look for active servers, or for backup servers.
1918 * If any server is found, it will be returned. If no valid server is found,
1919 * NULL is returned.
1920 */
1921static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001922 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01001923
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001924 if (px->srv_map_sz == 0)
1925 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01001926
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001927 l = h = 0;
1928 if (px->srv_act > 1) {
1929 while ((l + sizeof (int)) <= len) {
1930 h ^= ntohl(*(unsigned int *)(&addr[l]));
1931 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01001932 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001933 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01001934 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001935 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01001936}
1937
1938
1939/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001940 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001941 * is set, or to the dispatch server if (s->direct) is 0.
1942 * It can return one of :
1943 * - SN_ERR_NONE if everything's OK
1944 * - SN_ERR_SRVTO if there are no more servers
1945 * - SN_ERR_SRVCL if the connection was refused by the server
1946 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1947 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1948 * - SN_ERR_INTERNAL for any other purely internal errors
1949 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001950 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001951int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001952 int fd;
1953
willy tarreau12350152005-12-18 01:03:27 +01001954#ifdef DEBUG_FULL
1955 fprintf(stderr,"connect_server : s=%p\n",s);
1956#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001957
willy tarreaue39cd132005-12-17 13:00:18 +01001958 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001959 s->srv_addr = s->srv->addr;
1960 }
1961 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01001962 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01001963 if (!s->proxy->srv_act && !s->proxy->srv_bck)
1964 return SN_ERR_SRVTO;
1965
willy tarreau5cbea6f2005-12-17 12:48:26 +01001966 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001967 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001968
willy tarreau4c8c2b52006-03-24 19:36:41 +01001969 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01001970 s->srv_addr = srv->addr;
1971 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01001972 }
willy tarreau1a3442d2006-03-24 21:03:20 +01001973 else if (s->proxy->options & PR_O_BALANCE_SH) {
1974 struct server *srv;
1975 int len;
1976
1977 if (s->cli_addr.ss_family == AF_INET)
1978 len = 4;
1979 else if (s->cli_addr.ss_family == AF_INET6)
1980 len = 16;
1981 else /* unknown IP family */
1982 return SN_ERR_INTERNAL;
1983
1984 srv = get_server_sh(s->proxy,
1985 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1986 len);
1987 s->srv_addr = srv->addr;
1988 s->srv = srv;
1989 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001990 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001991 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001992 }
willy tarreaua1598082005-12-17 13:08:06 +01001993 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001994 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001995 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001996 }
1997 else if (s->proxy->options & PR_O_TRANSP) {
1998 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001999 socklen_t salen = sizeof(s->srv_addr);
2000
willy tarreau5cbea6f2005-12-17 12:48:26 +01002001 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2002 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002003 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002004 }
2005 }
willy tarreau0f7af912005-12-17 12:21:26 +01002006
willy tarreaua41a8b42005-12-17 14:02:24 +01002007 /* if this server remaps proxied ports, we'll use
2008 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01002009 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01002010 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002011 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002012
willy tarreaub952e1d2005-12-18 01:31:20 +01002013 if (!(s->proxy->options & PR_O_TRANSP) ||
2014 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002015 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2016 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2017 }
2018
willy tarreau0f7af912005-12-17 12:21:26 +01002019 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002020 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002021
2022 if (errno == ENFILE)
2023 send_log(s->proxy, LOG_EMERG,
2024 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2025 s->proxy->id, maxfd);
2026 else if (errno == EMFILE)
2027 send_log(s->proxy, LOG_EMERG,
2028 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2029 s->proxy->id, maxfd);
2030 else if (errno == ENOBUFS || errno == ENOMEM)
2031 send_log(s->proxy, LOG_EMERG,
2032 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2033 s->proxy->id, maxfd);
2034 /* this is a resource error */
2035 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002036 }
2037
willy tarreau9fe663a2005-12-17 13:02:59 +01002038 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002039 /* do not log anything there, it's a normal condition when this option
2040 * is used to serialize connections to a server !
2041 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002042 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2043 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002044 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002045 }
2046
willy tarreau0f7af912005-12-17 12:21:26 +01002047 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2048 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002049 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002050 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002051 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002052 }
2053
willy tarreaub952e1d2005-12-18 01:31:20 +01002054 if (s->proxy->options & PR_O_TCP_SRV_KA)
2055 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2056
willy tarreau0174f312005-12-18 01:02:42 +01002057 /* allow specific binding :
2058 * - server-specific at first
2059 * - proxy-specific next
2060 */
2061 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2062 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2063 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2064 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2065 s->proxy->id, s->srv->id);
2066 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002067 send_log(s->proxy, LOG_EMERG,
2068 "Cannot bind to source address before connect() for server %s/%s.\n",
2069 s->proxy->id, s->srv->id);
2070 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002071 }
2072 }
2073 else if (s->proxy->options & PR_O_BIND_SRC) {
2074 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2075 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2076 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->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 }
willy tarreaua1598082005-12-17 13:08:06 +01002083 }
2084
willy tarreaub1285d52005-12-18 01:20:14 +01002085 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2086 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2087
2088 if (errno == EAGAIN || errno == EADDRINUSE) {
2089 char *msg;
2090 if (errno == EAGAIN) /* no free ports left, try again later */
2091 msg = "no free ports";
2092 else
2093 msg = "local address already in use";
2094
2095 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002096 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002097 send_log(s->proxy, LOG_EMERG,
2098 "Connect() failed for server %s/%s: %s.\n",
2099 s->proxy->id, s->srv->id, msg);
2100 return SN_ERR_RESOURCE;
2101 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002102 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002103 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002104 return SN_ERR_SRVTO;
2105 } else {
2106 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002107 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002108 close(fd);
2109 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002110 }
2111 }
2112
willy tarreau5cbea6f2005-12-17 12:48:26 +01002113 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002114 fdtab[fd].read = &event_srv_read;
2115 fdtab[fd].write = &event_srv_write;
2116 fdtab[fd].state = FD_STCONN; /* connection in progress */
2117
2118 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002119#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2120 if (PrevReadEvent) {
2121 assert(!(FD_ISSET(fd, PrevReadEvent)));
2122 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2123 }
2124#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002125
2126 fd_insert(fd);
2127
2128 if (s->proxy->contimeout)
2129 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2130 else
2131 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002132 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002133}
2134
2135/*
2136 * this function is called on a read event from a client socket.
2137 * It returns 0.
2138 */
2139int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002140 struct task *t = fdtab[fd].owner;
2141 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002142 struct buffer *b = s->req;
2143 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002144
willy tarreau12350152005-12-18 01:03:27 +01002145#ifdef DEBUG_FULL
2146 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2147#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002148
willy tarreau0f7af912005-12-17 12:21:26 +01002149 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002150#ifdef FILL_BUFFERS
2151 while (1)
2152#else
2153 do
2154#endif
2155 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002156 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2157 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002158 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002159 }
2160 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002161 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002162 }
2163 else {
2164 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002165 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2166 * since it means that the rewrite protection has been removed. This
2167 * implies that the if statement can be removed.
2168 */
2169 if (max > b->rlim - b->data)
2170 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002171 }
2172
2173 if (max == 0) { /* not anymore room to store data */
2174 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002175 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002176 }
2177
willy tarreau3242e862005-12-17 12:27:53 +01002178#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002179 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002180 int skerr;
2181 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002182
willy tarreau5cbea6f2005-12-17 12:48:26 +01002183 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2184 if (skerr)
2185 ret = -1;
2186 else
2187 ret = recv(fd, b->r, max, 0);
2188 }
willy tarreau3242e862005-12-17 12:27:53 +01002189#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002190 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002191#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002192 if (ret > 0) {
2193 b->r += ret;
2194 b->l += ret;
2195 s->res_cr = RES_DATA;
2196
2197 if (b->r == b->data + BUFSIZE) {
2198 b->r = b->data; /* wrap around the buffer */
2199 }
willy tarreaua1598082005-12-17 13:08:06 +01002200
2201 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002202 /* we hope to read more data or to get a close on next round */
2203 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002204 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002205 else if (ret == 0) {
2206 s->res_cr = RES_NULL;
2207 break;
2208 }
2209 else if (errno == EAGAIN) {/* ignore EAGAIN */
2210 break;
2211 }
2212 else {
2213 s->res_cr = RES_ERROR;
2214 fdtab[fd].state = FD_STERROR;
2215 break;
2216 }
2217 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002218#ifndef FILL_BUFFERS
2219 while (0);
2220#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002221 }
2222 else {
2223 s->res_cr = RES_ERROR;
2224 fdtab[fd].state = FD_STERROR;
2225 }
2226
willy tarreau5cbea6f2005-12-17 12:48:26 +01002227 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002228 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002229 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2230 else
2231 tv_eternity(&s->crexpire);
2232
2233 task_wakeup(&rq, t);
2234 }
willy tarreau0f7af912005-12-17 12:21:26 +01002235
willy tarreau0f7af912005-12-17 12:21:26 +01002236 return 0;
2237}
2238
2239
2240/*
2241 * this function is called on a read event from a server socket.
2242 * It returns 0.
2243 */
2244int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002245 struct task *t = fdtab[fd].owner;
2246 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002247 struct buffer *b = s->rep;
2248 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002249
willy tarreau12350152005-12-18 01:03:27 +01002250#ifdef DEBUG_FULL
2251 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2252#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002253
willy tarreau0f7af912005-12-17 12:21:26 +01002254 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002255#ifdef FILL_BUFFERS
2256 while (1)
2257#else
2258 do
2259#endif
2260 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002261 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2262 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002263 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002264 }
2265 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002266 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002267 }
2268 else {
2269 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002270 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2271 * since it means that the rewrite protection has been removed. This
2272 * implies that the if statement can be removed.
2273 */
2274 if (max > b->rlim - b->data)
2275 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002276 }
2277
2278 if (max == 0) { /* not anymore room to store data */
2279 FD_CLR(fd, StaticReadEvent);
2280 break;
2281 }
2282
willy tarreau3242e862005-12-17 12:27:53 +01002283#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002284 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002285 int skerr;
2286 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002287
willy tarreau5cbea6f2005-12-17 12:48:26 +01002288 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2289 if (skerr)
2290 ret = -1;
2291 else
2292 ret = recv(fd, b->r, max, 0);
2293 }
willy tarreau3242e862005-12-17 12:27:53 +01002294#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002295 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002296#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002297 if (ret > 0) {
2298 b->r += ret;
2299 b->l += ret;
2300 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002301
willy tarreau5cbea6f2005-12-17 12:48:26 +01002302 if (b->r == b->data + BUFSIZE) {
2303 b->r = b->data; /* wrap around the buffer */
2304 }
willy tarreaua1598082005-12-17 13:08:06 +01002305
2306 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002307 /* we hope to read more data or to get a close on next round */
2308 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002309 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002310 else if (ret == 0) {
2311 s->res_sr = RES_NULL;
2312 break;
2313 }
2314 else if (errno == EAGAIN) {/* ignore EAGAIN */
2315 break;
2316 }
2317 else {
2318 s->res_sr = RES_ERROR;
2319 fdtab[fd].state = FD_STERROR;
2320 break;
2321 }
2322 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002323#ifndef FILL_BUFFERS
2324 while (0);
2325#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002326 }
2327 else {
2328 s->res_sr = RES_ERROR;
2329 fdtab[fd].state = FD_STERROR;
2330 }
2331
willy tarreau5cbea6f2005-12-17 12:48:26 +01002332 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002333 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002334 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2335 else
2336 tv_eternity(&s->srexpire);
2337
2338 task_wakeup(&rq, t);
2339 }
willy tarreau0f7af912005-12-17 12:21:26 +01002340
willy tarreau0f7af912005-12-17 12:21:26 +01002341 return 0;
2342}
2343
2344/*
2345 * this function is called on a write event from a client socket.
2346 * It returns 0.
2347 */
2348int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002349 struct task *t = fdtab[fd].owner;
2350 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002351 struct buffer *b = s->rep;
2352 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002353
willy tarreau12350152005-12-18 01:03:27 +01002354#ifdef DEBUG_FULL
2355 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2356#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002357
2358 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002359 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002360 // max = BUFSIZE; BUG !!!!
2361 max = 0;
2362 }
2363 else if (b->r > b->w) {
2364 max = b->r - b->w;
2365 }
2366 else
2367 max = b->data + BUFSIZE - b->w;
2368
willy tarreau0f7af912005-12-17 12:21:26 +01002369 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002370 if (max == 0) {
2371 s->res_cw = RES_NULL;
2372 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002373 tv_eternity(&s->cwexpire);
2374 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002375 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002376 }
2377
willy tarreau3242e862005-12-17 12:27:53 +01002378#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002379 {
2380 int skerr;
2381 socklen_t lskerr = sizeof(skerr);
2382
2383 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2384 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002385 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002386 else
willy tarreau3242e862005-12-17 12:27:53 +01002387 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002388 }
willy tarreau3242e862005-12-17 12:27:53 +01002389#else
willy tarreau0f7af912005-12-17 12:21:26 +01002390 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002391#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002392
2393 if (ret > 0) {
2394 b->l -= ret;
2395 b->w += ret;
2396
2397 s->res_cw = RES_DATA;
2398
2399 if (b->w == b->data + BUFSIZE) {
2400 b->w = b->data; /* wrap around the buffer */
2401 }
2402 }
2403 else if (ret == 0) {
2404 /* nothing written, just make as if we were never called */
2405// s->res_cw = RES_NULL;
2406 return 0;
2407 }
2408 else if (errno == EAGAIN) /* ignore EAGAIN */
2409 return 0;
2410 else {
2411 s->res_cw = RES_ERROR;
2412 fdtab[fd].state = FD_STERROR;
2413 }
2414 }
2415 else {
2416 s->res_cw = RES_ERROR;
2417 fdtab[fd].state = FD_STERROR;
2418 }
2419
willy tarreaub1ff9db2005-12-17 13:51:03 +01002420 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002421 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002422 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2423 s->crexpire = s->cwexpire;
2424 }
willy tarreau0f7af912005-12-17 12:21:26 +01002425 else
2426 tv_eternity(&s->cwexpire);
2427
willy tarreau5cbea6f2005-12-17 12:48:26 +01002428 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002429 return 0;
2430}
2431
2432
2433/*
2434 * this function is called on a write event from a server socket.
2435 * It returns 0.
2436 */
2437int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002438 struct task *t = fdtab[fd].owner;
2439 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002440 struct buffer *b = s->req;
2441 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002442
willy tarreau12350152005-12-18 01:03:27 +01002443#ifdef DEBUG_FULL
2444 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2445#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002446
2447 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002448 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002449 // max = BUFSIZE; BUG !!!!
2450 max = 0;
2451 }
2452 else if (b->r > b->w) {
2453 max = b->r - b->w;
2454 }
2455 else
2456 max = b->data + BUFSIZE - b->w;
2457
willy tarreau0f7af912005-12-17 12:21:26 +01002458 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002459 if (max == 0) {
2460 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002461 if (s->srv_state == SV_STCONN) {
2462 int skerr;
2463 socklen_t lskerr = sizeof(skerr);
2464 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2465 if (skerr) {
2466 s->res_sw = RES_ERROR;
2467 fdtab[fd].state = FD_STERROR;
2468 task_wakeup(&rq, t);
2469 tv_eternity(&s->swexpire);
2470 FD_CLR(fd, StaticWriteEvent);
2471 return 0;
2472 }
2473 }
2474
willy tarreau0f7af912005-12-17 12:21:26 +01002475 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002476 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002477 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002478 tv_eternity(&s->swexpire);
2479 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002480 return 0;
2481 }
2482
willy tarreau3242e862005-12-17 12:27:53 +01002483#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002484 {
2485 int skerr;
2486 socklen_t lskerr = sizeof(skerr);
2487 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2488 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002489 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002490 else
willy tarreau3242e862005-12-17 12:27:53 +01002491 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002492 }
willy tarreau3242e862005-12-17 12:27:53 +01002493#else
willy tarreau0f7af912005-12-17 12:21:26 +01002494 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002495#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002496 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002497 if (ret > 0) {
2498 b->l -= ret;
2499 b->w += ret;
2500
2501 s->res_sw = RES_DATA;
2502
2503 if (b->w == b->data + BUFSIZE) {
2504 b->w = b->data; /* wrap around the buffer */
2505 }
2506 }
2507 else if (ret == 0) {
2508 /* nothing written, just make as if we were never called */
2509 // s->res_sw = RES_NULL;
2510 return 0;
2511 }
2512 else if (errno == EAGAIN) /* ignore EAGAIN */
2513 return 0;
2514 else {
2515 s->res_sw = RES_ERROR;
2516 fdtab[fd].state = FD_STERROR;
2517 }
2518 }
2519 else {
2520 s->res_sw = RES_ERROR;
2521 fdtab[fd].state = FD_STERROR;
2522 }
2523
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002524 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2525 * otherwise it could loop indefinitely !
2526 */
2527 if (s->srv_state != SV_STCONN) {
2528 if (s->proxy->srvtimeout) {
2529 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2530 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2531 s->srexpire = s->swexpire;
2532 }
2533 else
2534 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002535 }
willy tarreau0f7af912005-12-17 12:21:26 +01002536
willy tarreau5cbea6f2005-12-17 12:48:26 +01002537 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002538 return 0;
2539}
2540
2541
2542/*
willy tarreaue39cd132005-12-17 13:00:18 +01002543 * returns a message to the client ; the connection is shut down for read,
2544 * and the request is cleared so that no server connection can be initiated.
2545 * The client must be in a valid state for this (HEADER, DATA ...).
2546 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002547 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002548 */
2549void client_retnclose(struct session *s, int len, const char *msg) {
2550 FD_CLR(s->cli_fd, StaticReadEvent);
2551 FD_SET(s->cli_fd, StaticWriteEvent);
2552 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002553 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002554 shutdown(s->cli_fd, SHUT_RD);
2555 s->cli_state = CL_STSHUTR;
2556 strcpy(s->rep->data, msg);
2557 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002558 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002559 s->rep->r += len;
2560 s->req->l = 0;
2561}
2562
2563
2564/*
2565 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002566 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002567 */
2568void client_return(struct session *s, int len, const char *msg) {
2569 strcpy(s->rep->data, msg);
2570 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002571 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002572 s->rep->r += len;
2573 s->req->l = 0;
2574}
2575
willy tarreau9fe663a2005-12-17 13:02:59 +01002576/*
2577 * send a log for the session when we have enough info about it
2578 */
2579void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002580 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002581 struct proxy *p = s->proxy;
2582 int log;
2583 char *uri;
2584 char *pxid;
2585 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002586 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002587
2588 /* This is a first attempt at a better logging system.
2589 * For now, we rely on send_log() to provide the date, although it obviously
2590 * is the date of the log and not of the request, and most fields are not
2591 * computed.
2592 */
2593
willy tarreaua1598082005-12-17 13:08:06 +01002594 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002595
willy tarreau8a86dbf2005-12-18 00:45:59 +01002596 if (s->cli_addr.ss_family == AF_INET)
2597 inet_ntop(AF_INET,
2598 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2599 pn, sizeof(pn));
2600 else
2601 inet_ntop(AF_INET6,
2602 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2603 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002604
willy tarreauc1cae632005-12-17 14:12:23 +01002605 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002606 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002607 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002608
willy tarreauc1cae632005-12-17 14:12:23 +01002609 tm = localtime(&s->logs.tv_accept.tv_sec);
2610 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002611 char tmpline[MAX_SYSLOG_LEN], *h;
2612 int hdr;
2613
2614 h = tmpline;
2615 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2616 *(h++) = ' ';
2617 *(h++) = '{';
2618 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2619 if (hdr)
2620 *(h++) = '|';
2621 if (s->req_cap[hdr] != NULL)
2622 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2623 }
2624 *(h++) = '}';
2625 }
2626
2627 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2628 *(h++) = ' ';
2629 *(h++) = '{';
2630 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2631 if (hdr)
2632 *(h++) = '|';
2633 if (s->rsp_cap[hdr] != NULL)
2634 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2635 }
2636 *(h++) = '}';
2637 }
2638
2639 if (h < tmpline + sizeof(tmpline) - 4) {
2640 *(h++) = ' ';
2641 *(h++) = '"';
2642 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2643 *(h++) = '"';
2644 }
2645 *h = '\0';
2646
willy tarreau0fe39652005-12-18 01:25:24 +01002647 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002648 pn,
2649 (s->cli_addr.ss_family == AF_INET) ?
2650 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2651 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002652 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2653 tm->tm_hour, tm->tm_min, tm->tm_sec,
2654 pxid, srv,
2655 s->logs.t_request,
2656 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2657 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002658 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2659 s->logs.status,
2660 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002661 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2662 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002663 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2664 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2665 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2666 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002667 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002668 }
2669 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002670 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002671 pn,
2672 (s->cli_addr.ss_family == AF_INET) ?
2673 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2674 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002675 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2676 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002677 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002678 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002679 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2680 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002681 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002682 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2683 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002684 }
2685
2686 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002687}
2688
willy tarreaue39cd132005-12-17 13:00:18 +01002689
2690/*
willy tarreau0f7af912005-12-17 12:21:26 +01002691 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002692 * to an accept. It tries to accept as many connections as possible.
2693 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002694 */
2695int event_accept(int fd) {
2696 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002697 struct session *s;
2698 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002699 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002700 int max_accept;
2701
2702 if (global.nbproc > 1)
2703 max_accept = 8; /* let other processes catch some connections too */
2704 else
2705 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002706
willy tarreauc2becdc2006-03-19 19:36:48 +01002707 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002708 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002709 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002710
willy tarreaub1285d52005-12-18 01:20:14 +01002711 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2712 switch (errno) {
2713 case EAGAIN:
2714 case EINTR:
2715 case ECONNABORTED:
2716 return 0; /* nothing more to accept */
2717 case ENFILE:
2718 send_log(p, LOG_EMERG,
2719 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2720 p->id, maxfd);
2721 return 0;
2722 case EMFILE:
2723 send_log(p, LOG_EMERG,
2724 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2725 p->id, maxfd);
2726 return 0;
2727 case ENOBUFS:
2728 case ENOMEM:
2729 send_log(p, LOG_EMERG,
2730 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2731 p->id, maxfd);
2732 return 0;
2733 default:
2734 return 0;
2735 }
2736 }
willy tarreau0f7af912005-12-17 12:21:26 +01002737
willy tarreau5cbea6f2005-12-17 12:48:26 +01002738 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2739 Alert("out of memory in event_accept().\n");
2740 FD_CLR(fd, StaticReadEvent);
2741 p->state = PR_STIDLE;
2742 close(cfd);
2743 return 0;
2744 }
willy tarreau0f7af912005-12-17 12:21:26 +01002745
willy tarreaub1285d52005-12-18 01:20:14 +01002746 /* if this session comes from a known monitoring system, we want to ignore
2747 * it as soon as possible, which means closing it immediately for TCP.
2748 */
2749 s->flags = 0;
2750 if (addr.ss_family == AF_INET &&
2751 p->mon_mask.s_addr &&
2752 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2753 if (p->mode == PR_MODE_TCP) {
2754 close(cfd);
2755 pool_free(session, s);
2756 continue;
2757 }
2758 s->flags |= SN_MONITOR;
2759 }
2760
willy tarreau5cbea6f2005-12-17 12:48:26 +01002761 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2762 Alert("out of memory in event_accept().\n");
2763 FD_CLR(fd, StaticReadEvent);
2764 p->state = PR_STIDLE;
2765 close(cfd);
2766 pool_free(session, s);
2767 return 0;
2768 }
willy tarreau0f7af912005-12-17 12:21:26 +01002769
willy tarreau5cbea6f2005-12-17 12:48:26 +01002770 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002771 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002772 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2773 close(cfd);
2774 pool_free(task, t);
2775 pool_free(session, s);
2776 return 0;
2777 }
willy tarreau0f7af912005-12-17 12:21:26 +01002778
willy tarreau5cbea6f2005-12-17 12:48:26 +01002779 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2780 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2781 (char *) &one, sizeof(one)) == -1)) {
2782 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2783 close(cfd);
2784 pool_free(task, t);
2785 pool_free(session, s);
2786 return 0;
2787 }
willy tarreau0f7af912005-12-17 12:21:26 +01002788
willy tarreaub952e1d2005-12-18 01:31:20 +01002789 if (p->options & PR_O_TCP_CLI_KA)
2790 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2791
willy tarreau9fe663a2005-12-17 13:02:59 +01002792 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2793 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2794 t->state = TASK_IDLE;
2795 t->process = process_session;
2796 t->context = s;
2797
2798 s->task = t;
2799 s->proxy = p;
2800 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2801 s->srv_state = SV_STIDLE;
2802 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002803
willy tarreau9fe663a2005-12-17 13:02:59 +01002804 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2805 s->cli_fd = cfd;
2806 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002807 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002808 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002809
willy tarreaub1285d52005-12-18 01:20:14 +01002810 if (s->flags & SN_MONITOR)
2811 s->logs.logwait = 0;
2812 else
2813 s->logs.logwait = p->to_log;
2814
willy tarreaua1598082005-12-17 13:08:06 +01002815 s->logs.tv_accept = now;
2816 s->logs.t_request = -1;
2817 s->logs.t_connect = -1;
2818 s->logs.t_data = -1;
2819 s->logs.t_close = 0;
2820 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002821 s->logs.cli_cookie = NULL;
2822 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002823 s->logs.status = -1;
2824 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002825
willy tarreau2f6ba652005-12-17 13:57:42 +01002826 s->uniq_id = totalconn;
2827
willy tarreau4302f492005-12-18 01:00:37 +01002828 if (p->nb_req_cap > 0) {
2829 if ((s->req_cap =
2830 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2831 == NULL) { /* no memory */
2832 close(cfd); /* nothing can be done for this fd without memory */
2833 pool_free(task, t);
2834 pool_free(session, s);
2835 return 0;
2836 }
2837 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2838 }
2839 else
2840 s->req_cap = NULL;
2841
2842 if (p->nb_rsp_cap > 0) {
2843 if ((s->rsp_cap =
2844 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2845 == NULL) { /* no memory */
2846 if (s->req_cap != NULL)
2847 pool_free_to(p->req_cap_pool, s->req_cap);
2848 close(cfd); /* nothing can be done for this fd without memory */
2849 pool_free(task, t);
2850 pool_free(session, s);
2851 return 0;
2852 }
2853 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2854 }
2855 else
2856 s->rsp_cap = NULL;
2857
willy tarreau5cbea6f2005-12-17 12:48:26 +01002858 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2859 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002860 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002861 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002862
willy tarreau8a86dbf2005-12-18 00:45:59 +01002863 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002864 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002865 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002866 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002867
willy tarreau9fe663a2005-12-17 13:02:59 +01002868 if (p->to_log) {
2869 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002870 if (s->logs.logwait & LW_CLIP)
2871 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002872 sess_log(s);
2873 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002874 else if (s->cli_addr.ss_family == AF_INET) {
2875 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2876 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2877 sn, sizeof(sn)) &&
2878 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2879 pn, sizeof(pn))) {
2880 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2881 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2882 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2883 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2884 }
2885 }
2886 else {
2887 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2888 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2889 sn, sizeof(sn)) &&
2890 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2891 pn, sizeof(pn))) {
2892 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2893 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2894 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2895 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2896 }
2897 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002898 }
willy tarreau0f7af912005-12-17 12:21:26 +01002899
willy tarreau982249e2005-12-18 00:57:06 +01002900 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002901 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002902 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002903 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002904 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002905 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002906 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002907 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002908
willy tarreau8a86dbf2005-12-18 00:45:59 +01002909 if (s->cli_addr.ss_family == AF_INET) {
2910 char pn[INET_ADDRSTRLEN];
2911 inet_ntop(AF_INET,
2912 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2913 pn, sizeof(pn));
2914
2915 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2916 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2917 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2918 }
2919 else {
2920 char pn[INET6_ADDRSTRLEN];
2921 inet_ntop(AF_INET6,
2922 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2923 pn, sizeof(pn));
2924
2925 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2926 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2927 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2928 }
2929
willy tarreauef900ab2005-12-17 12:52:52 +01002930 write(1, trash, len);
2931 }
willy tarreau0f7af912005-12-17 12:21:26 +01002932
willy tarreau5cbea6f2005-12-17 12:48:26 +01002933 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002934 if (s->rsp_cap != NULL)
2935 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2936 if (s->req_cap != NULL)
2937 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002938 close(cfd); /* nothing can be done for this fd without memory */
2939 pool_free(task, t);
2940 pool_free(session, s);
2941 return 0;
2942 }
willy tarreau4302f492005-12-18 01:00:37 +01002943
willy tarreau5cbea6f2005-12-17 12:48:26 +01002944 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002945 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002946 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2947 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002948 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002949 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002950
willy tarreau5cbea6f2005-12-17 12:48:26 +01002951 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2952 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002953 if (s->rsp_cap != NULL)
2954 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2955 if (s->req_cap != NULL)
2956 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002957 close(cfd); /* nothing can be done for this fd without memory */
2958 pool_free(task, t);
2959 pool_free(session, s);
2960 return 0;
2961 }
2962 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002963 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002964 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 +01002965
willy tarreau5cbea6f2005-12-17 12:48:26 +01002966 fdtab[cfd].read = &event_cli_read;
2967 fdtab[cfd].write = &event_cli_write;
2968 fdtab[cfd].owner = t;
2969 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002970
willy tarreaub1285d52005-12-18 01:20:14 +01002971 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2972 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2973 /* Either we got a request from a monitoring system on an HTTP instance,
2974 * or we're in health check mode with the 'httpchk' option enabled. In
2975 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2976 */
2977 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2978 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2979 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002980 }
2981 else {
2982 FD_SET(cfd, StaticReadEvent);
2983 }
2984
willy tarreaub952e1d2005-12-18 01:31:20 +01002985#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2986 if (PrevReadEvent) {
2987 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2988 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2989 }
2990#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002991 fd_insert(cfd);
2992
2993 tv_eternity(&s->cnexpire);
2994 tv_eternity(&s->srexpire);
2995 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002996 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002997 tv_eternity(&s->cwexpire);
2998
willy tarreaub1285d52005-12-18 01:20:14 +01002999 if (s->proxy->clitimeout) {
3000 if (FD_ISSET(cfd, StaticReadEvent))
3001 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3002 if (FD_ISSET(cfd, StaticWriteEvent))
3003 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3004 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003005
willy tarreaub1285d52005-12-18 01:20:14 +01003006 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003007
3008 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003009
3010 if (p->mode != PR_MODE_HEALTH)
3011 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003012
3013 p->nbconn++;
3014 actconn++;
3015 totalconn++;
3016
willy tarreaub952e1d2005-12-18 01:31:20 +01003017 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003018 } /* end of while (p->nbconn < p->maxconn) */
3019 return 0;
3020}
willy tarreau0f7af912005-12-17 12:21:26 +01003021
willy tarreau0f7af912005-12-17 12:21:26 +01003022
willy tarreau5cbea6f2005-12-17 12:48:26 +01003023/*
3024 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003025 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3026 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003027 * or -1 if an error occured.
3028 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003029int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003030 struct task *t = fdtab[fd].owner;
3031 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003032 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003033 socklen_t lskerr = sizeof(skerr);
3034
willy tarreau05be12b2006-03-19 19:35:00 +01003035 skerr = 1;
3036 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3037 || (skerr != 0)) {
3038 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003039 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003040 fdtab[fd].state = FD_STERROR;
3041 FD_CLR(fd, StaticWriteEvent);
3042 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003043 else if (s->result != -1) {
3044 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003045 if (s->proxy->options & PR_O_HTTP_CHK) {
3046 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003047 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003048 * so we'll send the request, and won't wake the checker up now.
3049 */
3050#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003051 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003052#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003053 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003054#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003055 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003056 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3057 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3058 return 0;
3059 }
willy tarreau05be12b2006-03-19 19:35:00 +01003060 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003061 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003062 FD_CLR(fd, StaticWriteEvent);
3063 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003064 }
3065 else {
3066 /* good TCP connection is enough */
3067 s->result = 1;
3068 }
3069 }
3070
3071 task_wakeup(&rq, t);
3072 return 0;
3073}
3074
willy tarreau0f7af912005-12-17 12:21:26 +01003075
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003076/*
3077 * This function is used only for server health-checks. It handles
3078 * the server's reply to an HTTP request. It returns 1 if the server replies
3079 * 2xx or 3xx (valid responses), or -1 in other cases.
3080 */
3081int event_srv_chk_r(int fd) {
3082 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003083 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003084 struct task *t = fdtab[fd].owner;
3085 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003086 int skerr;
3087 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003088
willy tarreaua4a583a2005-12-18 01:39:19 +01003089 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003090
willy tarreau05be12b2006-03-19 19:35:00 +01003091 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3092 if (!skerr) {
3093#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003094 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003095#else
willy tarreau05be12b2006-03-19 19:35:00 +01003096 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3097 * but the connection was closed on the remote end. Fortunately, recv still
3098 * works correctly and we don't need to do the getsockopt() on linux.
3099 */
3100 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003101#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003102
3103 if ((len >= sizeof("HTTP/1.0 000")) &&
3104 !memcmp(reply, "HTTP/1.", 7) &&
3105 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3106 result = 1;
3107 }
3108
3109 if (result == -1)
3110 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003111
3112 if (s->result != -1)
3113 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003114
3115 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003116 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003117 return 0;
3118}
3119
3120
3121/*
3122 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3123 * and moves <end> just after the end of <str>.
3124 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3125 * the shift value (positive or negative) is returned.
3126 * If there's no space left, the move is not done.
3127 *
3128 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003129int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003130 int delta;
3131 int len;
3132
3133 len = strlen(str);
3134 delta = len - (end - pos);
3135
3136 if (delta + b->r >= b->data + BUFSIZE)
3137 return 0; /* no space left */
3138
3139 /* first, protect the end of the buffer */
3140 memmove(end + delta, end, b->data + b->l - end);
3141
3142 /* now, copy str over pos */
3143 memcpy(pos, str,len);
3144
willy tarreau5cbea6f2005-12-17 12:48:26 +01003145 /* we only move data after the displaced zone */
3146 if (b->r > pos) b->r += delta;
3147 if (b->w > pos) b->w += delta;
3148 if (b->h > pos) b->h += delta;
3149 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003150 b->l += delta;
3151
3152 return delta;
3153}
3154
willy tarreau8337c6b2005-12-17 13:41:01 +01003155/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003156 * len is 0.
3157 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003158int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003159 int delta;
3160
3161 delta = len - (end - pos);
3162
3163 if (delta + b->r >= b->data + BUFSIZE)
3164 return 0; /* no space left */
3165
Willy TARREAUe78ae262006-01-08 01:24:12 +01003166 if (b->data + b->l < end)
3167 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3168 return 0;
3169
willy tarreau0f7af912005-12-17 12:21:26 +01003170 /* first, protect the end of the buffer */
3171 memmove(end + delta, end, b->data + b->l - end);
3172
3173 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003174 if (len)
3175 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003176
willy tarreau5cbea6f2005-12-17 12:48:26 +01003177 /* we only move data after the displaced zone */
3178 if (b->r > pos) b->r += delta;
3179 if (b->w > pos) b->w += delta;
3180 if (b->h > pos) b->h += delta;
3181 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003182 b->l += delta;
3183
3184 return delta;
3185}
3186
3187
3188int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3189 char *old_dst = dst;
3190
3191 while (*str) {
3192 if (*str == '\\') {
3193 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003194 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003195 int len, num;
3196
3197 num = *str - '0';
3198 str++;
3199
willy tarreau8a86dbf2005-12-18 00:45:59 +01003200 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003201 len = matches[num].rm_eo - matches[num].rm_so;
3202 memcpy(dst, src + matches[num].rm_so, len);
3203 dst += len;
3204 }
3205
3206 }
3207 else if (*str == 'x') {
3208 unsigned char hex1, hex2;
3209 str++;
3210
willy tarreauc1f47532005-12-18 01:08:26 +01003211 hex1 = toupper(*str++) - '0';
3212 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003213
3214 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3215 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3216 *dst++ = (hex1<<4) + hex2;
3217 }
3218 else
3219 *dst++ = *str++;
3220 }
3221 else
3222 *dst++ = *str++;
3223 }
3224 *dst = 0;
3225 return dst - old_dst;
3226}
3227
willy tarreauc1f47532005-12-18 01:08:26 +01003228static int ishex(char s)
3229{
3230 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3231}
3232
3233/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3234char *check_replace_string(char *str)
3235{
3236 char *err = NULL;
3237 while (*str) {
3238 if (*str == '\\') {
3239 err = str; /* in case of a backslash, we return the pointer to it */
3240 str++;
3241 if (!*str)
3242 return err;
3243 else if (isdigit((int)*str))
3244 err = NULL;
3245 else if (*str == 'x') {
3246 str++;
3247 if (!ishex(*str))
3248 return err;
3249 str++;
3250 if (!ishex(*str))
3251 return err;
3252 err = NULL;
3253 }
3254 else {
3255 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3256 err = NULL;
3257 }
3258 }
3259 str++;
3260 }
3261 return err;
3262}
3263
3264
willy tarreau9fe663a2005-12-17 13:02:59 +01003265
willy tarreau0f7af912005-12-17 12:21:26 +01003266/*
3267 * manages the client FSM and its socket. BTW, it also tries to handle the
3268 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3269 * 0 else.
3270 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003271int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003272 int s = t->srv_state;
3273 int c = t->cli_state;
3274 struct buffer *req = t->req;
3275 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003276 int method_checked = 0;
3277 appsess *asession_temp = NULL;
3278 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003279
willy tarreau750a4722005-12-17 13:21:24 +01003280#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003281 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3282 cli_stnames[c], srv_stnames[s],
3283 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3284 t->crexpire.tv_sec, t->crexpire.tv_usec,
3285 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003286#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003287 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3288 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3289 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3290 //);
3291 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003292 /* now parse the partial (or complete) headers */
3293 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3294 char *ptr;
3295 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003296 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003297
willy tarreau5cbea6f2005-12-17 12:48:26 +01003298 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003299
willy tarreau0f7af912005-12-17 12:21:26 +01003300 /* look for the end of the current header */
3301 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3302 ptr++;
3303
willy tarreau5cbea6f2005-12-17 12:48:26 +01003304 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003305 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003306
3307 /*
3308 * first, let's check that it's not a leading empty line, in
3309 * which case we'll ignore and remove it (according to RFC2616).
3310 */
3311 if (req->h == req->data) {
3312 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3313 if (ptr > req->r - 2) {
3314 /* this is a partial header, let's wait for more to come */
3315 req->lr = ptr;
3316 break;
3317 }
3318
3319 /* now we know that *ptr is either \r or \n,
3320 * and that there are at least 1 char after it.
3321 */
3322 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3323 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3324 else
3325 req->lr = ptr + 2; /* \r\n or \n\r */
3326 /* ignore empty leading lines */
3327 buffer_replace2(req, req->h, req->lr, NULL, 0);
3328 req->h = req->lr;
3329 continue;
3330 }
3331
willy tarreau5cbea6f2005-12-17 12:48:26 +01003332 /* we can only get here after an end of headers */
3333 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003334
willy tarreaue39cd132005-12-17 13:00:18 +01003335 if (t->flags & SN_CLDENY) {
3336 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003337 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003338 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003339 if (!(t->flags & SN_ERR_MASK))
3340 t->flags |= SN_ERR_PRXCOND;
3341 if (!(t->flags & SN_FINST_MASK))
3342 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003343 return 1;
3344 }
3345
willy tarreau5cbea6f2005-12-17 12:48:26 +01003346 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003347 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3348 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003349 }
willy tarreau0f7af912005-12-17 12:21:26 +01003350
willy tarreau9fe663a2005-12-17 13:02:59 +01003351 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003352 if (t->cli_addr.ss_family == AF_INET) {
3353 unsigned char *pn;
3354 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3355 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3356 pn[0], pn[1], pn[2], pn[3]);
3357 buffer_replace2(req, req->h, req->h, trash, len);
3358 }
3359 else if (t->cli_addr.ss_family == AF_INET6) {
3360 char pn[INET6_ADDRSTRLEN];
3361 inet_ntop(AF_INET6,
3362 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3363 pn, sizeof(pn));
3364 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3365 buffer_replace2(req, req->h, req->h, trash, len);
3366 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003367 }
3368
willy tarreau25c4ea52005-12-18 00:49:49 +01003369 /* add a "connection: close" line if needed */
3370 if (t->proxy->options & PR_O_HTTP_CLOSE)
3371 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3372
willy tarreau982249e2005-12-18 00:57:06 +01003373 if (!memcmp(req->data, "POST ", 5)) {
3374 /* this is a POST request, which is not cacheable by default */
3375 t->flags |= SN_POST;
3376 }
willy tarreaucd878942005-12-17 13:27:43 +01003377
willy tarreau5cbea6f2005-12-17 12:48:26 +01003378 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003379 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003380
willy tarreau750a4722005-12-17 13:21:24 +01003381 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003382 /* FIXME: we'll set the client in a wait state while we try to
3383 * connect to the server. Is this really needed ? wouldn't it be
3384 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003385 //FD_CLR(t->cli_fd, StaticReadEvent);
3386 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003387
3388 /* FIXME: if we break here (as up to 1.1.23), having the client
3389 * shutdown its connection can lead to an abort further.
3390 * it's better to either return 1 or even jump directly to the
3391 * data state which will save one schedule.
3392 */
3393 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003394
3395 if (!t->proxy->clitimeout ||
3396 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3397 /* If the client has no timeout, or if the server is not ready yet,
3398 * and we know for sure that it can expire, then it's cleaner to
3399 * disable the timeout on the client side so that too low values
3400 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003401 *
3402 * FIXME-20050705: the server needs a way to re-enable this time-out
3403 * when it switches its state, otherwise a client can stay connected
3404 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003405 */
3406 tv_eternity(&t->crexpire);
3407
willy tarreau197e8ec2005-12-17 14:10:59 +01003408 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003409 }
willy tarreau0f7af912005-12-17 12:21:26 +01003410
Willy TARREAU13032e72006-03-12 17:31:45 +01003411 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3412 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003413 /* this is a partial header, let's wait for more to come */
3414 req->lr = ptr;
3415 break;
3416 }
willy tarreau0f7af912005-12-17 12:21:26 +01003417
willy tarreau5cbea6f2005-12-17 12:48:26 +01003418 /* now we know that *ptr is either \r or \n,
3419 * and that there are at least 1 char after it.
3420 */
3421 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3422 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3423 else
3424 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003425
willy tarreau5cbea6f2005-12-17 12:48:26 +01003426 /*
3427 * now we know that we have a full header ; we can do whatever
3428 * we want with these pointers :
3429 * req->h = beginning of header
3430 * ptr = end of header (first \r or \n)
3431 * req->lr = beginning of next line (next rep->h)
3432 * req->r = end of data (not used at this stage)
3433 */
willy tarreau0f7af912005-12-17 12:21:26 +01003434
willy tarreau12350152005-12-18 01:03:27 +01003435 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3436 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3437 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3438
3439 /* skip ; */
3440 request_line++;
3441
3442 /* look if we have a jsessionid */
3443
3444 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3445
3446 /* skip jsessionid= */
3447 request_line += t->proxy->appsession_name_len + 1;
3448
3449 /* First try if we allready have an appsession */
3450 asession_temp = &local_asession;
3451
3452 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3453 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3454 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3455 return 0;
3456 }
3457
3458 /* Copy the sessionid */
3459 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3460 asession_temp->sessid[t->proxy->appsession_len] = 0;
3461 asession_temp->serverid = NULL;
3462
3463 /* only do insert, if lookup fails */
3464 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3465 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3466 Alert("Not enough memory process_cli():asession:calloc().\n");
3467 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3468 return 0;
3469 }
3470 asession_temp->sessid = local_asession.sessid;
3471 asession_temp->serverid = local_asession.serverid;
3472 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003473 } /* end if (chtbl_lookup()) */
3474 else {
willy tarreau12350152005-12-18 01:03:27 +01003475 /*free wasted memory;*/
3476 pool_free_to(apools.sessid, local_asession.sessid);
3477 }
3478
3479 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3480 asession_temp->request_count++;
3481
3482#if defined(DEBUG_HASH)
3483 print_table(&(t->proxy->htbl_proxy));
3484#endif
3485
3486 if (asession_temp->serverid == NULL) {
3487 Alert("Found Application Session without matching server.\n");
3488 } else {
3489 struct server *srv = t->proxy->srv;
3490 while (srv) {
3491 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3492 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3493 /* we found the server and it's usable */
3494 t->flags &= ~SN_CK_MASK;
3495 t->flags |= SN_CK_VALID | SN_DIRECT;
3496 t->srv = srv;
3497 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003498 } else {
willy tarreau12350152005-12-18 01:03:27 +01003499 t->flags &= ~SN_CK_MASK;
3500 t->flags |= SN_CK_DOWN;
3501 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003502 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003503 srv = srv->next;
3504 }/* end while(srv) */
3505 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003506 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003507 else {
3508 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3509 }
willy tarreau598da412005-12-18 01:07:29 +01003510 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003511 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003512 else{
3513 //printf("No Methode-Header with Session-String\n");
3514 }
3515
willy tarreau8337c6b2005-12-17 13:41:01 +01003516 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003517 /* we have a complete HTTP request that we must log */
3518 int urilen;
3519
willy tarreaua1598082005-12-17 13:08:06 +01003520 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003521 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003522 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003523 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003524 if (!(t->flags & SN_ERR_MASK))
3525 t->flags |= SN_ERR_PRXCOND;
3526 if (!(t->flags & SN_FINST_MASK))
3527 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003528 return 1;
3529 }
3530
3531 urilen = ptr - req->h;
3532 if (urilen >= REQURI_LEN)
3533 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003534 memcpy(t->logs.uri, req->h, urilen);
3535 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003536
willy tarreaua1598082005-12-17 13:08:06 +01003537 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003538 sess_log(t);
3539 }
willy tarreau4302f492005-12-18 01:00:37 +01003540 else if (t->logs.logwait & LW_REQHDR) {
3541 struct cap_hdr *h;
3542 int len;
3543 for (h = t->proxy->req_cap; h; h = h->next) {
3544 if ((h->namelen + 2 <= ptr - req->h) &&
3545 (req->h[h->namelen] == ':') &&
3546 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3547
3548 if (t->req_cap[h->index] == NULL)
3549 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3550
3551 len = ptr - (req->h + h->namelen + 2);
3552 if (len > h->len)
3553 len = h->len;
3554
3555 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3556 t->req_cap[h->index][len]=0;
3557 }
3558 }
3559
3560 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003561
willy tarreau5cbea6f2005-12-17 12:48:26 +01003562 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003563
willy tarreau982249e2005-12-18 00:57:06 +01003564 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003565 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003566 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 +01003567 max = ptr - req->h;
3568 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003569 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003570 trash[len++] = '\n';
3571 write(1, trash, len);
3572 }
willy tarreau0f7af912005-12-17 12:21:26 +01003573
willy tarreau25c4ea52005-12-18 00:49:49 +01003574
3575 /* remove "connection: " if needed */
3576 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3577 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3578 delete_header = 1;
3579 }
3580
willy tarreau5cbea6f2005-12-17 12:48:26 +01003581 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003582 if (!delete_header && t->proxy->req_exp != NULL
3583 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003584 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003585 char term;
3586
3587 term = *ptr;
3588 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003589 exp = t->proxy->req_exp;
3590 do {
3591 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3592 switch (exp->action) {
3593 case ACT_ALLOW:
3594 if (!(t->flags & SN_CLDENY))
3595 t->flags |= SN_CLALLOW;
3596 break;
3597 case ACT_REPLACE:
3598 if (!(t->flags & SN_CLDENY)) {
3599 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3600 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3601 }
3602 break;
3603 case ACT_REMOVE:
3604 if (!(t->flags & SN_CLDENY))
3605 delete_header = 1;
3606 break;
3607 case ACT_DENY:
3608 if (!(t->flags & SN_CLALLOW))
3609 t->flags |= SN_CLDENY;
3610 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003611 case ACT_PASS: /* we simply don't deny this one */
3612 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003613 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003614 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003615 }
willy tarreaue39cd132005-12-17 13:00:18 +01003616 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003617 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003618 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003619
willy tarreau240afa62005-12-17 13:14:35 +01003620 /* Now look for cookies. Conforming to RFC2109, we have to support
3621 * attributes whose name begin with a '$', and associate them with
3622 * the right cookie, if we want to delete this cookie.
3623 * So there are 3 cases for each cookie read :
3624 * 1) it's a special attribute, beginning with a '$' : ignore it.
3625 * 2) it's a server id cookie that we *MAY* want to delete : save
3626 * some pointers on it (last semi-colon, beginning of cookie...)
3627 * 3) it's an application cookie : we *MAY* have to delete a previous
3628 * "special" cookie.
3629 * At the end of loop, if a "special" cookie remains, we may have to
3630 * remove it. If no application cookie persists in the header, we
3631 * *MUST* delete it
3632 */
willy tarreau12350152005-12-18 01:03:27 +01003633 if (!delete_header &&
3634 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003635 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003636 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003637 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003638 char *del_colon, *del_cookie, *colon;
3639 int app_cookies;
3640
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003642 colon = p1;
3643 /* del_cookie == NULL => nothing to be deleted */
3644 del_colon = del_cookie = NULL;
3645 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003646
3647 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003648 /* skip spaces and colons, but keep an eye on these ones */
3649 while (p1 < ptr) {
3650 if (*p1 == ';' || *p1 == ',')
3651 colon = p1;
3652 else if (!isspace((int)*p1))
3653 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003654 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003655 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003656
3657 if (p1 == ptr)
3658 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003659
3660 /* p1 is at the beginning of the cookie name */
3661 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003662 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003663 p2++;
3664
3665 if (p2 == ptr)
3666 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003667
3668 p3 = p2 + 1; /* skips the '=' sign */
3669 if (p3 == ptr)
3670 break;
3671
willy tarreau240afa62005-12-17 13:14:35 +01003672 p4 = p3;
3673 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003674 p4++;
3675
3676 /* here, we have the cookie name between p1 and p2,
3677 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003678 * we can process it :
3679 *
3680 * Cookie: NAME=VALUE;
3681 * | || || |
3682 * | || || +--> p4
3683 * | || |+-------> p3
3684 * | || +--------> p2
3685 * | |+------------> p1
3686 * | +-------------> colon
3687 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003688 */
3689
willy tarreau240afa62005-12-17 13:14:35 +01003690 if (*p1 == '$') {
3691 /* skip this one */
3692 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003693 else {
3694 /* first, let's see if we want to capture it */
3695 if (t->proxy->capture_name != NULL &&
3696 t->logs.cli_cookie == NULL &&
3697 (p4 - p1 >= t->proxy->capture_namelen) &&
3698 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3699 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003700
willy tarreau8337c6b2005-12-17 13:41:01 +01003701 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3702 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003703 } else {
3704 if (log_len > t->proxy->capture_len)
3705 log_len = t->proxy->capture_len;
3706 memcpy(t->logs.cli_cookie, p1, log_len);
3707 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003708 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003709 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003710
3711 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3712 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3713 /* Cool... it's the right one */
3714 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003715 char *delim;
3716
3717 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3718 * have the server ID betweek p3 and delim, and the original cookie between
3719 * delim+1 and p4. Otherwise, delim==p4 :
3720 *
3721 * Cookie: NAME=SRV~VALUE;
3722 * | || || | |
3723 * | || || | +--> p4
3724 * | || || +--------> delim
3725 * | || |+-----------> p3
3726 * | || +------------> p2
3727 * | |+----------------> p1
3728 * | +-----------------> colon
3729 * +------------------------> req->h
3730 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003731
willy tarreau0174f312005-12-18 01:02:42 +01003732 if (t->proxy->options & PR_O_COOK_PFX) {
3733 for (delim = p3; delim < p4; delim++)
3734 if (*delim == COOKIE_DELIM)
3735 break;
3736 }
3737 else
3738 delim = p4;
3739
3740
3741 /* Here, we'll look for the first running server which supports the cookie.
3742 * This allows to share a same cookie between several servers, for example
3743 * to dedicate backup servers to specific servers only.
3744 */
3745 while (srv) {
3746 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3747 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3748 /* we found the server and it's usable */
3749 t->flags &= ~SN_CK_MASK;
3750 t->flags |= SN_CK_VALID | SN_DIRECT;
3751 t->srv = srv;
3752 break;
willy tarreau12350152005-12-18 01:03:27 +01003753 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003754 /* we found a server, but it's down */
3755 t->flags &= ~SN_CK_MASK;
3756 t->flags |= SN_CK_DOWN;
3757 }
3758 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003759 srv = srv->next;
3760 }
3761
willy tarreau0174f312005-12-18 01:02:42 +01003762 if (!srv && !(t->flags & SN_CK_DOWN)) {
3763 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003764 t->flags &= ~SN_CK_MASK;
3765 t->flags |= SN_CK_INVALID;
3766 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003767
willy tarreau0174f312005-12-18 01:02:42 +01003768 /* depending on the cookie mode, we may have to either :
3769 * - delete the complete cookie if we're in insert+indirect mode, so that
3770 * the server never sees it ;
3771 * - remove the server id from the cookie value, and tag the cookie as an
3772 * application cookie so that it does not get accidentely removed later,
3773 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003774 */
willy tarreau0174f312005-12-18 01:02:42 +01003775 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3776 buffer_replace2(req, p3, delim + 1, NULL, 0);
3777 p4 -= (delim + 1 - p3);
3778 ptr -= (delim + 1 - p3);
3779 del_cookie = del_colon = NULL;
3780 app_cookies++; /* protect the header from deletion */
3781 }
3782 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003783 (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 +01003784 del_cookie = p1;
3785 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003786 }
willy tarreau12350152005-12-18 01:03:27 +01003787 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003788 /* now we know that we must keep this cookie since it's
3789 * not ours. But if we wanted to delete our cookie
3790 * earlier, we cannot remove the complete header, but we
3791 * can remove the previous block itself.
3792 */
3793 app_cookies++;
3794
3795 if (del_cookie != NULL) {
3796 buffer_replace2(req, del_cookie, p1, NULL, 0);
3797 p4 -= (p1 - del_cookie);
3798 ptr -= (p1 - del_cookie);
3799 del_cookie = del_colon = NULL;
3800 }
willy tarreau240afa62005-12-17 13:14:35 +01003801 }
willy tarreau12350152005-12-18 01:03:27 +01003802
3803 if ((t->proxy->appsession_name != NULL) &&
3804 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3805 /* first, let's see if the cookie is our appcookie*/
3806
3807 /* Cool... it's the right one */
3808
3809 asession_temp = &local_asession;
3810
3811 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3812 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3813 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3814 return 0;
3815 }
3816
3817 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3818 asession_temp->sessid[t->proxy->appsession_len] = 0;
3819 asession_temp->serverid = NULL;
3820
3821 /* only do insert, if lookup fails */
3822 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3823 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3824 Alert("Not enough memory process_cli():asession:calloc().\n");
3825 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3826 return 0;
3827 }
3828
3829 asession_temp->sessid = local_asession.sessid;
3830 asession_temp->serverid = local_asession.serverid;
3831 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3832 }
3833 else{
3834 /* free wasted memory */
3835 pool_free_to(apools.sessid, local_asession.sessid);
3836 }
3837
3838 if (asession_temp->serverid == NULL) {
3839 Alert("Found Application Session without matching server.\n");
3840 } else {
3841 struct server *srv = t->proxy->srv;
3842 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003843 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003844 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3845 /* we found the server and it's usable */
3846 t->flags &= ~SN_CK_MASK;
3847 t->flags |= SN_CK_VALID | SN_DIRECT;
3848 t->srv = srv;
3849 break;
3850 } else {
3851 t->flags &= ~SN_CK_MASK;
3852 t->flags |= SN_CK_DOWN;
3853 }
3854 }
3855 srv = srv->next;
3856 }/* end while(srv) */
3857 }/* end else if server == NULL */
3858
3859 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003860 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003861 }
willy tarreau240afa62005-12-17 13:14:35 +01003862
willy tarreau5cbea6f2005-12-17 12:48:26 +01003863 /* we'll have to look for another cookie ... */
3864 p1 = p4;
3865 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003866
3867 /* There's no more cookie on this line.
3868 * We may have marked the last one(s) for deletion.
3869 * We must do this now in two ways :
3870 * - if there is no app cookie, we simply delete the header ;
3871 * - if there are app cookies, we must delete the end of the
3872 * string properly, including the colon/semi-colon before
3873 * the cookie name.
3874 */
3875 if (del_cookie != NULL) {
3876 if (app_cookies) {
3877 buffer_replace2(req, del_colon, ptr, NULL, 0);
3878 /* WARNING! <ptr> becomes invalid for now. If some code
3879 * below needs to rely on it before the end of the global
3880 * header loop, we need to correct it with this code :
3881 * ptr = del_colon;
3882 */
3883 }
3884 else
3885 delete_header = 1;
3886 }
3887 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003888
3889 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003890 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003891 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003892 }
willy tarreau240afa62005-12-17 13:14:35 +01003893 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3894
willy tarreau5cbea6f2005-12-17 12:48:26 +01003895 req->h = req->lr;
3896 } /* while (req->lr < req->r) */
3897
3898 /* end of header processing (even if incomplete) */
3899
willy tarreauef900ab2005-12-17 12:52:52 +01003900 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3901 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3902 * full. We cannot loop here since event_cli_read will disable it only if
3903 * req->l == rlim-data
3904 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003905 FD_SET(t->cli_fd, StaticReadEvent);
3906 if (t->proxy->clitimeout)
3907 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3908 else
3909 tv_eternity(&t->crexpire);
3910 }
3911
willy tarreaue39cd132005-12-17 13:00:18 +01003912 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003913 * won't be able to free more later, so the session will never terminate.
3914 */
willy tarreaue39cd132005-12-17 13:00:18 +01003915 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003916 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003917 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003918 if (!(t->flags & SN_ERR_MASK))
3919 t->flags |= SN_ERR_PRXCOND;
3920 if (!(t->flags & SN_FINST_MASK))
3921 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003922 return 1;
3923 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003924 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003925 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003926 tv_eternity(&t->crexpire);
3927 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003928 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003929 if (!(t->flags & SN_ERR_MASK))
3930 t->flags |= SN_ERR_CLICL;
3931 if (!(t->flags & SN_FINST_MASK))
3932 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003933 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003934 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003935 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3936
3937 /* read timeout : give up with an error message.
3938 */
3939 t->logs.status = 408;
3940 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003941 if (!(t->flags & SN_ERR_MASK))
3942 t->flags |= SN_ERR_CLITO;
3943 if (!(t->flags & SN_FINST_MASK))
3944 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003945 return 1;
3946 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003947
3948 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003949 }
3950 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003951 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003952 /* FIXME: this error handling is partly buggy because we always report
3953 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3954 * or HEADER phase. BTW, it's not logical to expire the client while
3955 * we're waiting for the server to connect.
3956 */
willy tarreau0f7af912005-12-17 12:21:26 +01003957 /* read or write error */
3958 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003959 tv_eternity(&t->crexpire);
3960 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003961 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003962 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003963 if (!(t->flags & SN_ERR_MASK))
3964 t->flags |= SN_ERR_CLICL;
3965 if (!(t->flags & SN_FINST_MASK))
3966 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003967 return 1;
3968 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003969 /* last read, or end of server write */
3970 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003971 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003972 tv_eternity(&t->crexpire);
3973 shutdown(t->cli_fd, SHUT_RD);
3974 t->cli_state = CL_STSHUTR;
3975 return 1;
3976 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003977 /* last server read and buffer empty */
3978 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003979 FD_CLR(t->cli_fd, StaticWriteEvent);
3980 tv_eternity(&t->cwexpire);
3981 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003982 /* We must ensure that the read part is still alive when switching
3983 * to shutw */
3984 FD_SET(t->cli_fd, StaticReadEvent);
3985 if (t->proxy->clitimeout)
3986 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003987 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003988 //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 +01003989 return 1;
3990 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003991 /* read timeout */
3992 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3993 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003994 tv_eternity(&t->crexpire);
3995 shutdown(t->cli_fd, SHUT_RD);
3996 t->cli_state = CL_STSHUTR;
3997 if (!(t->flags & SN_ERR_MASK))
3998 t->flags |= SN_ERR_CLITO;
3999 if (!(t->flags & SN_FINST_MASK))
4000 t->flags |= SN_FINST_D;
4001 return 1;
4002 }
4003 /* write timeout */
4004 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4005 FD_CLR(t->cli_fd, StaticWriteEvent);
4006 tv_eternity(&t->cwexpire);
4007 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004008 /* We must ensure that the read part is still alive when switching
4009 * to shutw */
4010 FD_SET(t->cli_fd, StaticReadEvent);
4011 if (t->proxy->clitimeout)
4012 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4013
willy tarreau036e1ce2005-12-17 13:46:33 +01004014 t->cli_state = CL_STSHUTW;
4015 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004016 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004017 if (!(t->flags & SN_FINST_MASK))
4018 t->flags |= SN_FINST_D;
4019 return 1;
4020 }
willy tarreau0f7af912005-12-17 12:21:26 +01004021
willy tarreauc58fc692005-12-17 14:13:08 +01004022 if (req->l >= req->rlim - req->data) {
4023 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004024 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004025 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004026 FD_CLR(t->cli_fd, StaticReadEvent);
4027 tv_eternity(&t->crexpire);
4028 }
4029 }
4030 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004031 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004032 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4033 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004034 if (!t->proxy->clitimeout ||
4035 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4036 /* If the client has no timeout, or if the server not ready yet, and we
4037 * know for sure that it can expire, then it's cleaner to disable the
4038 * timeout on the client side so that too low values cannot make the
4039 * sessions abort too early.
4040 */
willy tarreau0f7af912005-12-17 12:21:26 +01004041 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004042 else
4043 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004044 }
4045 }
4046
4047 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004048 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004049 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4050 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4051 tv_eternity(&t->cwexpire);
4052 }
4053 }
4054 else { /* buffer not empty */
4055 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4056 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004057 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004058 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004059 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4060 t->crexpire = t->cwexpire;
4061 }
willy tarreau0f7af912005-12-17 12:21:26 +01004062 else
4063 tv_eternity(&t->cwexpire);
4064 }
4065 }
4066 return 0; /* other cases change nothing */
4067 }
4068 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004069 if (t->res_cw == RES_ERROR) {
4070 tv_eternity(&t->cwexpire);
4071 fd_delete(t->cli_fd);
4072 t->cli_state = CL_STCLOSE;
4073 if (!(t->flags & SN_ERR_MASK))
4074 t->flags |= SN_ERR_CLICL;
4075 if (!(t->flags & SN_FINST_MASK))
4076 t->flags |= SN_FINST_D;
4077 return 1;
4078 }
4079 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004080 tv_eternity(&t->cwexpire);
4081 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004082 t->cli_state = CL_STCLOSE;
4083 return 1;
4084 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004085 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4086 tv_eternity(&t->cwexpire);
4087 fd_delete(t->cli_fd);
4088 t->cli_state = CL_STCLOSE;
4089 if (!(t->flags & SN_ERR_MASK))
4090 t->flags |= SN_ERR_CLITO;
4091 if (!(t->flags & SN_FINST_MASK))
4092 t->flags |= SN_FINST_D;
4093 return 1;
4094 }
willy tarreau0f7af912005-12-17 12:21:26 +01004095 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004096 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004097 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4098 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4099 tv_eternity(&t->cwexpire);
4100 }
4101 }
4102 else { /* buffer not empty */
4103 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4104 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004105 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004106 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004107 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4108 t->crexpire = t->cwexpire;
4109 }
willy tarreau0f7af912005-12-17 12:21:26 +01004110 else
4111 tv_eternity(&t->cwexpire);
4112 }
4113 }
4114 return 0;
4115 }
4116 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004117 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004118 tv_eternity(&t->crexpire);
4119 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004120 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004121 if (!(t->flags & SN_ERR_MASK))
4122 t->flags |= SN_ERR_CLICL;
4123 if (!(t->flags & SN_FINST_MASK))
4124 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004125 return 1;
4126 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004127 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4128 tv_eternity(&t->crexpire);
4129 fd_delete(t->cli_fd);
4130 t->cli_state = CL_STCLOSE;
4131 return 1;
4132 }
4133 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4134 tv_eternity(&t->crexpire);
4135 fd_delete(t->cli_fd);
4136 t->cli_state = CL_STCLOSE;
4137 if (!(t->flags & SN_ERR_MASK))
4138 t->flags |= SN_ERR_CLITO;
4139 if (!(t->flags & SN_FINST_MASK))
4140 t->flags |= SN_FINST_D;
4141 return 1;
4142 }
willy tarreauef900ab2005-12-17 12:52:52 +01004143 else if (req->l >= req->rlim - req->data) {
4144 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004145
4146 /* FIXME-20050705: is it possible for a client to maintain a session
4147 * after the timeout by sending more data after it receives a close ?
4148 */
4149
willy tarreau0f7af912005-12-17 12:21:26 +01004150 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004151 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004152 FD_CLR(t->cli_fd, StaticReadEvent);
4153 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004154 //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 +01004155 }
4156 }
4157 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004158 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004159 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4160 FD_SET(t->cli_fd, StaticReadEvent);
4161 if (t->proxy->clitimeout)
4162 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4163 else
4164 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004165 //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 +01004166 }
4167 }
4168 return 0;
4169 }
4170 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004171 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004172 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004173 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 +01004174 write(1, trash, len);
4175 }
4176 return 0;
4177 }
4178 return 0;
4179}
4180
4181
4182/*
4183 * manages the server FSM and its socket. It returns 1 if a state has changed
4184 * (and a resync may be needed), 0 else.
4185 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004186int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004187 int s = t->srv_state;
4188 int c = t->cli_state;
4189 struct buffer *req = t->req;
4190 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004191 appsess *asession_temp = NULL;
4192 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004193 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004194
willy tarreau750a4722005-12-17 13:21:24 +01004195#ifdef DEBUG_FULL
4196 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4197#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004198 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4199 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4200 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4201 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004202 if (s == SV_STIDLE) {
4203 if (c == CL_STHEADERS)
4204 return 0; /* stay in idle, waiting for data to reach the client side */
4205 else if (c == CL_STCLOSE ||
4206 c == CL_STSHUTW ||
4207 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4208 tv_eternity(&t->cnexpire);
4209 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004210 if (!(t->flags & SN_ERR_MASK))
4211 t->flags |= SN_ERR_CLICL;
4212 if (!(t->flags & SN_FINST_MASK))
4213 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004214 return 1;
4215 }
4216 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004217 /* initiate a connection to the server */
4218 conn_err = connect_server(t);
4219 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004220 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4221 t->srv_state = SV_STCONN;
4222 }
4223 else { /* try again */
4224 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004225 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004226 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004227 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004228 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4229 t->flags &= ~SN_CK_MASK;
4230 t->flags |= SN_CK_DOWN;
4231 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004232 }
4233
willy tarreaub1285d52005-12-18 01:20:14 +01004234 conn_err = connect_server(t);
4235 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004236 t->srv_state = SV_STCONN;
4237 break;
4238 }
4239 }
4240 if (t->conn_retries < 0) {
4241 /* if conn_retries < 0 or other error, let's abort */
4242 tv_eternity(&t->cnexpire);
4243 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004244 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004245 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004246 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004247 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004248 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004249 if (!(t->flags & SN_FINST_MASK))
4250 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004251 }
4252 }
4253 return 1;
4254 }
4255 }
4256 else if (s == SV_STCONN) { /* connection in progress */
4257 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004258 //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 +01004259 return 0; /* nothing changed */
4260 }
4261 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4262 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4263 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004264 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004265 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004266 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004267 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004268 if (t->conn_retries >= 0) {
4269 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004270 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004271 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004272 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4273 t->flags &= ~SN_CK_MASK;
4274 t->flags |= SN_CK_DOWN;
4275 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004276 }
willy tarreaub1285d52005-12-18 01:20:14 +01004277 conn_err = connect_server(t);
4278 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004279 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004280 }
willy tarreaub1285d52005-12-18 01:20:14 +01004281 else if (t->res_sw == RES_SILENT)
4282 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4283 else
4284 conn_err = SN_ERR_SRVCL; // it was a connect error.
4285
willy tarreau0f7af912005-12-17 12:21:26 +01004286 /* if conn_retries < 0 or other error, let's abort */
4287 tv_eternity(&t->cnexpire);
4288 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004289 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004290 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004291 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004292 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004293 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004294 if (!(t->flags & SN_FINST_MASK))
4295 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004296 return 1;
4297 }
4298 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004299 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004300
willy tarreau0f7af912005-12-17 12:21:26 +01004301 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004302 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004303 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004304 tv_eternity(&t->swexpire);
4305 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004306 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004307 if (t->proxy->srvtimeout) {
4308 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4309 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4310 t->srexpire = t->swexpire;
4311 }
4312 else
4313 tv_eternity(&t->swexpire);
4314 }
willy tarreau0f7af912005-12-17 12:21:26 +01004315
4316 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4317 FD_SET(t->srv_fd, StaticReadEvent);
4318 if (t->proxy->srvtimeout)
4319 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4320 else
4321 tv_eternity(&t->srexpire);
4322
4323 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004324 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004325
4326 /* if the user wants to log as soon as possible, without counting
4327 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004328 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004329 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4330 sess_log(t);
4331 }
willy tarreau0f7af912005-12-17 12:21:26 +01004332 }
willy tarreauef900ab2005-12-17 12:52:52 +01004333 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004334 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004335 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4336 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004337 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004338 return 1;
4339 }
4340 }
4341 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004342 /* now parse the partial (or complete) headers */
4343 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4344 char *ptr;
4345 int delete_header;
4346
4347 ptr = rep->lr;
4348
4349 /* look for the end of the current header */
4350 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4351 ptr++;
4352
4353 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004354 int line, len;
4355
4356 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004357
4358 /* first, we'll block if security checks have caught nasty things */
4359 if (t->flags & SN_CACHEABLE) {
4360 if ((t->flags & SN_CACHE_COOK) &&
4361 (t->flags & SN_SCK_ANY) &&
4362 (t->proxy->options & PR_O_CHK_CACHE)) {
4363
4364 /* we're in presence of a cacheable response containing
4365 * a set-cookie header. We'll block it as requested by
4366 * the 'checkcache' option, and send an alert.
4367 */
4368 tv_eternity(&t->srexpire);
4369 tv_eternity(&t->swexpire);
4370 fd_delete(t->srv_fd);
4371 t->srv_state = SV_STCLOSE;
4372 t->logs.status = 502;
4373 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4374 if (!(t->flags & SN_ERR_MASK))
4375 t->flags |= SN_ERR_PRXCOND;
4376 if (!(t->flags & SN_FINST_MASK))
4377 t->flags |= SN_FINST_H;
4378
4379 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4380 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4381
4382 return 1;
4383 }
4384 }
4385
willy tarreau982249e2005-12-18 00:57:06 +01004386 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4387 if (t->flags & SN_SVDENY) {
4388 tv_eternity(&t->srexpire);
4389 tv_eternity(&t->swexpire);
4390 fd_delete(t->srv_fd);
4391 t->srv_state = SV_STCLOSE;
4392 t->logs.status = 502;
4393 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4394 if (!(t->flags & SN_ERR_MASK))
4395 t->flags |= SN_ERR_PRXCOND;
4396 if (!(t->flags & SN_FINST_MASK))
4397 t->flags |= SN_FINST_H;
4398 return 1;
4399 }
4400
willy tarreau5cbea6f2005-12-17 12:48:26 +01004401 /* we'll have something else to do here : add new headers ... */
4402
willy tarreaucd878942005-12-17 13:27:43 +01004403 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4404 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004405 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004406 * insert a set-cookie here, except if we want to insert only on POST
4407 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004408 */
willy tarreau750a4722005-12-17 13:21:24 +01004409 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004410 t->proxy->cookie_name,
4411 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004412
willy tarreau036e1ce2005-12-17 13:46:33 +01004413 t->flags |= SN_SCK_INSERTED;
4414
willy tarreau750a4722005-12-17 13:21:24 +01004415 /* Here, we will tell an eventual cache on the client side that we don't
4416 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4417 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4418 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4419 */
willy tarreau240afa62005-12-17 13:14:35 +01004420 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004421 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4422 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004423
4424 if (rep->data + rep->l < rep->h)
4425 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4426 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004427 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004428 }
4429
4430 /* headers to be added */
4431 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004432 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4433 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004434 }
4435
willy tarreau25c4ea52005-12-18 00:49:49 +01004436 /* add a "connection: close" line if needed */
4437 if (t->proxy->options & PR_O_HTTP_CLOSE)
4438 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4439
willy tarreau5cbea6f2005-12-17 12:48:26 +01004440 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004441 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004442 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004443
Willy TARREAU767ba712006-03-01 22:40:50 +01004444 /* client connection already closed or option 'httpclose' required :
4445 * we close the server's outgoing connection right now.
4446 */
4447 if ((req->l == 0) &&
4448 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4449 FD_CLR(t->srv_fd, StaticWriteEvent);
4450 tv_eternity(&t->swexpire);
4451
4452 /* We must ensure that the read part is still alive when switching
4453 * to shutw */
4454 FD_SET(t->srv_fd, StaticReadEvent);
4455 if (t->proxy->srvtimeout)
4456 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4457
4458 shutdown(t->srv_fd, SHUT_WR);
4459 t->srv_state = SV_STSHUTW;
4460 }
4461
willy tarreau25c4ea52005-12-18 00:49:49 +01004462 /* if the user wants to log as soon as possible, without counting
4463 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004464 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004465 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4466 t->logs.bytes = rep->h - rep->data;
4467 sess_log(t);
4468 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004469 break;
4470 }
4471
4472 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4473 if (ptr > rep->r - 2) {
4474 /* this is a partial header, let's wait for more to come */
4475 rep->lr = ptr;
4476 break;
4477 }
4478
4479 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4480 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4481
4482 /* now we know that *ptr is either \r or \n,
4483 * and that there are at least 1 char after it.
4484 */
4485 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4486 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4487 else
4488 rep->lr = ptr + 2; /* \r\n or \n\r */
4489
4490 /*
4491 * now we know that we have a full header ; we can do whatever
4492 * we want with these pointers :
4493 * rep->h = beginning of header
4494 * ptr = end of header (first \r or \n)
4495 * rep->lr = beginning of next line (next rep->h)
4496 * rep->r = end of data (not used at this stage)
4497 */
4498
willy tarreaua1598082005-12-17 13:08:06 +01004499
willy tarreau982249e2005-12-18 00:57:06 +01004500 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004501 t->logs.logwait &= ~LW_RESP;
4502 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004503 switch (t->logs.status) {
4504 case 200:
4505 case 203:
4506 case 206:
4507 case 300:
4508 case 301:
4509 case 410:
4510 /* RFC2616 @13.4:
4511 * "A response received with a status code of
4512 * 200, 203, 206, 300, 301 or 410 MAY be stored
4513 * by a cache (...) unless a cache-control
4514 * directive prohibits caching."
4515 *
4516 * RFC2616 @9.5: POST method :
4517 * "Responses to this method are not cacheable,
4518 * unless the response includes appropriate
4519 * Cache-Control or Expires header fields."
4520 */
4521 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4522 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4523 break;
4524 default:
4525 break;
4526 }
willy tarreau4302f492005-12-18 01:00:37 +01004527 }
4528 else if (t->logs.logwait & LW_RSPHDR) {
4529 struct cap_hdr *h;
4530 int len;
4531 for (h = t->proxy->rsp_cap; h; h = h->next) {
4532 if ((h->namelen + 2 <= ptr - rep->h) &&
4533 (rep->h[h->namelen] == ':') &&
4534 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4535
4536 if (t->rsp_cap[h->index] == NULL)
4537 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4538
4539 len = ptr - (rep->h + h->namelen + 2);
4540 if (len > h->len)
4541 len = h->len;
4542
4543 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4544 t->rsp_cap[h->index][len]=0;
4545 }
4546 }
4547
willy tarreaua1598082005-12-17 13:08:06 +01004548 }
4549
willy tarreau5cbea6f2005-12-17 12:48:26 +01004550 delete_header = 0;
4551
willy tarreau982249e2005-12-18 00:57:06 +01004552 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004553 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004554 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 +01004555 max = ptr - rep->h;
4556 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004557 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004558 trash[len++] = '\n';
4559 write(1, trash, len);
4560 }
4561
willy tarreau25c4ea52005-12-18 00:49:49 +01004562 /* remove "connection: " if needed */
4563 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4564 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4565 delete_header = 1;
4566 }
4567
willy tarreau5cbea6f2005-12-17 12:48:26 +01004568 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004569 if (!delete_header && t->proxy->rsp_exp != NULL
4570 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004571 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004572 char term;
4573
4574 term = *ptr;
4575 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004576 exp = t->proxy->rsp_exp;
4577 do {
4578 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4579 switch (exp->action) {
4580 case ACT_ALLOW:
4581 if (!(t->flags & SN_SVDENY))
4582 t->flags |= SN_SVALLOW;
4583 break;
4584 case ACT_REPLACE:
4585 if (!(t->flags & SN_SVDENY)) {
4586 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4587 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4588 }
4589 break;
4590 case ACT_REMOVE:
4591 if (!(t->flags & SN_SVDENY))
4592 delete_header = 1;
4593 break;
4594 case ACT_DENY:
4595 if (!(t->flags & SN_SVALLOW))
4596 t->flags |= SN_SVDENY;
4597 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004598 case ACT_PASS: /* we simply don't deny this one */
4599 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004600 }
4601 break;
4602 }
willy tarreaue39cd132005-12-17 13:00:18 +01004603 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004604 *ptr = term; /* restore the string terminator */
4605 }
4606
willy tarreau97f58572005-12-18 00:53:44 +01004607 /* check for cache-control: or pragma: headers */
4608 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4609 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4610 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4611 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4612 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004613 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004614 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4615 else {
4616 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004617 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004618 t->flags &= ~SN_CACHE_COOK;
4619 }
4620 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004621 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004622 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004623 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004624 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4625 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004626 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004627 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004628 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4629 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4630 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4631 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4632 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4633 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004634 }
4635 }
4636 }
4637
willy tarreau5cbea6f2005-12-17 12:48:26 +01004638 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004639 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004640 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004641 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004642 char *p1, *p2, *p3, *p4;
4643
willy tarreau97f58572005-12-18 00:53:44 +01004644 t->flags |= SN_SCK_ANY;
4645
willy tarreau5cbea6f2005-12-17 12:48:26 +01004646 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4647
4648 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004649 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004650 p1++;
4651
4652 if (p1 == ptr || *p1 == ';') /* end of cookie */
4653 break;
4654
4655 /* p1 is at the beginning of the cookie name */
4656 p2 = p1;
4657
4658 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4659 p2++;
4660
4661 if (p2 == ptr || *p2 == ';') /* next cookie */
4662 break;
4663
4664 p3 = p2 + 1; /* skips the '=' sign */
4665 if (p3 == ptr)
4666 break;
4667
4668 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004669 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004670 p4++;
4671
4672 /* here, we have the cookie name between p1 and p2,
4673 * and its value between p3 and p4.
4674 * we can process it.
4675 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004676
4677 /* first, let's see if we want to capture it */
4678 if (t->proxy->capture_name != NULL &&
4679 t->logs.srv_cookie == NULL &&
4680 (p4 - p1 >= t->proxy->capture_namelen) &&
4681 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4682 int log_len = p4 - p1;
4683
4684 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4685 Alert("HTTP logging : out of memory.\n");
4686 }
4687
4688 if (log_len > t->proxy->capture_len)
4689 log_len = t->proxy->capture_len;
4690 memcpy(t->logs.srv_cookie, p1, log_len);
4691 t->logs.srv_cookie[log_len] = 0;
4692 }
4693
4694 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4695 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004696 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004697 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004698
4699 /* If the cookie is in insert mode on a known server, we'll delete
4700 * this occurrence because we'll insert another one later.
4701 * We'll delete it too if the "indirect" option is set and we're in
4702 * a direct access. */
4703 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004704 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004705 /* this header must be deleted */
4706 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004707 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004708 }
4709 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4710 /* replace bytes p3->p4 with the cookie name associated
4711 * with this server since we know it.
4712 */
4713 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004714 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004715 }
willy tarreau0174f312005-12-18 01:02:42 +01004716 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4717 /* insert the cookie name associated with this server
4718 * before existing cookie, and insert a delimitor between them..
4719 */
4720 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4721 p3[t->srv->cklen] = COOKIE_DELIM;
4722 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4723 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004724 break;
4725 }
willy tarreau12350152005-12-18 01:03:27 +01004726
4727 /* first, let's see if the cookie is our appcookie*/
4728 if ((t->proxy->appsession_name != NULL) &&
4729 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4730
4731 /* Cool... it's the right one */
4732
willy tarreaub952e1d2005-12-18 01:31:20 +01004733 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004734 asession_temp = &local_asession;
4735
willy tarreaub952e1d2005-12-18 01:31:20 +01004736 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004737 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4738 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4739 }
4740 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4741 asession_temp->sessid[t->proxy->appsession_len] = 0;
4742 asession_temp->serverid = NULL;
4743
4744 /* only do insert, if lookup fails */
4745 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4746 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4747 Alert("Not enought Memory process_srv():asession:calloc().\n");
4748 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4749 return 0;
4750 }
4751 asession_temp->sessid = local_asession.sessid;
4752 asession_temp->serverid = local_asession.serverid;
4753 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004754 }/* end if (chtbl_lookup()) */
4755 else {
willy tarreau12350152005-12-18 01:03:27 +01004756 /* free wasted memory */
4757 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004758 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004759
willy tarreaub952e1d2005-12-18 01:31:20 +01004760 if (asession_temp->serverid == NULL) {
4761 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004762 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4763 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4764 }
4765 asession_temp->serverid[0] = '\0';
4766 }
4767
willy tarreaub952e1d2005-12-18 01:31:20 +01004768 if (asession_temp->serverid[0] == '\0')
4769 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004770
4771 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4772
4773#if defined(DEBUG_HASH)
4774 print_table(&(t->proxy->htbl_proxy));
4775#endif
4776 break;
4777 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004778 else {
4779 // fprintf(stderr,"Ignoring unknown cookie : ");
4780 // write(2, p1, p2-p1);
4781 // fprintf(stderr," = ");
4782 // write(2, p3, p4-p3);
4783 // fprintf(stderr,"\n");
4784 }
4785 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4786 } /* we're now at the end of the cookie value */
4787 } /* end of cookie processing */
4788
willy tarreau97f58572005-12-18 00:53:44 +01004789 /* check for any set-cookie in case we check for cacheability */
4790 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4791 (t->proxy->options & PR_O_CHK_CACHE) &&
4792 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4793 t->flags |= SN_SCK_ANY;
4794 }
4795
willy tarreau5cbea6f2005-12-17 12:48:26 +01004796 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004797 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004798 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004799
willy tarreau5cbea6f2005-12-17 12:48:26 +01004800 rep->h = rep->lr;
4801 } /* while (rep->lr < rep->r) */
4802
4803 /* end of header processing (even if incomplete) */
4804
willy tarreauef900ab2005-12-17 12:52:52 +01004805 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4806 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4807 * full. We cannot loop here since event_srv_read will disable it only if
4808 * rep->l == rlim-data
4809 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004810 FD_SET(t->srv_fd, StaticReadEvent);
4811 if (t->proxy->srvtimeout)
4812 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4813 else
4814 tv_eternity(&t->srexpire);
4815 }
willy tarreau0f7af912005-12-17 12:21:26 +01004816
willy tarreau8337c6b2005-12-17 13:41:01 +01004817 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004818 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004819 tv_eternity(&t->srexpire);
4820 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004821 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004822 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004823 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004824 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004825 if (!(t->flags & SN_ERR_MASK))
4826 t->flags |= SN_ERR_SRVCL;
4827 if (!(t->flags & SN_FINST_MASK))
4828 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004829 return 1;
4830 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004831 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004832 * since we are in header mode, if there's no space left for headers, we
4833 * won't be able to free more later, so the session will never terminate.
4834 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004835 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 +01004836 FD_CLR(t->srv_fd, StaticReadEvent);
4837 tv_eternity(&t->srexpire);
4838 shutdown(t->srv_fd, SHUT_RD);
4839 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004840 //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 +01004841 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004842 }
4843 /* read timeout : return a 504 to the client.
4844 */
4845 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4846 tv_eternity(&t->srexpire);
4847 tv_eternity(&t->swexpire);
4848 fd_delete(t->srv_fd);
4849 t->srv_state = SV_STCLOSE;
4850 t->logs.status = 504;
4851 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004852 if (!(t->flags & SN_ERR_MASK))
4853 t->flags |= SN_ERR_SRVTO;
4854 if (!(t->flags & SN_FINST_MASK))
4855 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004856 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004857
4858 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004859 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004860 /* FIXME!!! here, we don't want to switch to SHUTW if the
4861 * client shuts read too early, because we may still have
4862 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004863 * The side-effect is that if the client completely closes its
4864 * connection during SV_STHEADER, the connection to the server
4865 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004866 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004867 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004868 FD_CLR(t->srv_fd, StaticWriteEvent);
4869 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004870
4871 /* We must ensure that the read part is still alive when switching
4872 * to shutw */
4873 FD_SET(t->srv_fd, StaticReadEvent);
4874 if (t->proxy->srvtimeout)
4875 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4876
willy tarreau0f7af912005-12-17 12:21:26 +01004877 shutdown(t->srv_fd, SHUT_WR);
4878 t->srv_state = SV_STSHUTW;
4879 return 1;
4880 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004881 /* write timeout */
4882 /* FIXME!!! here, we don't want to switch to SHUTW if the
4883 * client shuts read too early, because we may still have
4884 * some work to do on the headers.
4885 */
4886 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4887 FD_CLR(t->srv_fd, StaticWriteEvent);
4888 tv_eternity(&t->swexpire);
4889 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004890 /* We must ensure that the read part is still alive when switching
4891 * to shutw */
4892 FD_SET(t->srv_fd, StaticReadEvent);
4893 if (t->proxy->srvtimeout)
4894 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4895
4896 /* We must ensure that the read part is still alive when switching
4897 * to shutw */
4898 FD_SET(t->srv_fd, StaticReadEvent);
4899 if (t->proxy->srvtimeout)
4900 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4901
willy tarreau036e1ce2005-12-17 13:46:33 +01004902 t->srv_state = SV_STSHUTW;
4903 if (!(t->flags & SN_ERR_MASK))
4904 t->flags |= SN_ERR_SRVTO;
4905 if (!(t->flags & SN_FINST_MASK))
4906 t->flags |= SN_FINST_H;
4907 return 1;
4908 }
willy tarreau0f7af912005-12-17 12:21:26 +01004909
4910 if (req->l == 0) {
4911 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4912 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4913 tv_eternity(&t->swexpire);
4914 }
4915 }
4916 else { /* client buffer not empty */
4917 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4918 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004919 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004920 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004921 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4922 t->srexpire = t->swexpire;
4923 }
willy tarreau0f7af912005-12-17 12:21:26 +01004924 else
4925 tv_eternity(&t->swexpire);
4926 }
4927 }
4928
willy tarreau5cbea6f2005-12-17 12:48:26 +01004929 /* be nice with the client side which would like to send a complete header
4930 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4931 * would read all remaining data at once ! The client should not write past rep->lr
4932 * when the server is in header state.
4933 */
4934 //return header_processed;
4935 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004936 }
4937 else if (s == SV_STDATA) {
4938 /* read or write error */
4939 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004940 tv_eternity(&t->srexpire);
4941 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004942 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004943 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004944 if (!(t->flags & SN_ERR_MASK))
4945 t->flags |= SN_ERR_SRVCL;
4946 if (!(t->flags & SN_FINST_MASK))
4947 t->flags |= SN_FINST_D;
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);
5047 //close(t->srv_fd);
5048 t->srv_state = SV_STCLOSE;
5049 if (!(t->flags & SN_ERR_MASK))
5050 t->flags |= SN_ERR_SRVCL;
5051 if (!(t->flags & SN_FINST_MASK))
5052 t->flags |= SN_FINST_D;
5053 return 1;
5054 }
5055 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005056 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005057 tv_eternity(&t->swexpire);
5058 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005059 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005060 t->srv_state = SV_STCLOSE;
5061 return 1;
5062 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005063 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5064 //FD_CLR(t->srv_fd, StaticWriteEvent);
5065 tv_eternity(&t->swexpire);
5066 fd_delete(t->srv_fd);
5067 //close(t->srv_fd);
5068 t->srv_state = SV_STCLOSE;
5069 if (!(t->flags & SN_ERR_MASK))
5070 t->flags |= SN_ERR_SRVTO;
5071 if (!(t->flags & SN_FINST_MASK))
5072 t->flags |= SN_FINST_D;
5073 return 1;
5074 }
willy tarreau0f7af912005-12-17 12:21:26 +01005075 else if (req->l == 0) {
5076 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5077 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5078 tv_eternity(&t->swexpire);
5079 }
5080 }
5081 else { /* buffer not empty */
5082 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5083 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005084 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005085 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005086 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5087 t->srexpire = t->swexpire;
5088 }
willy tarreau0f7af912005-12-17 12:21:26 +01005089 else
5090 tv_eternity(&t->swexpire);
5091 }
5092 }
5093 return 0;
5094 }
5095 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005096 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005097 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005098 tv_eternity(&t->srexpire);
5099 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005100 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005101 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005102 if (!(t->flags & SN_ERR_MASK))
5103 t->flags |= SN_ERR_SRVCL;
5104 if (!(t->flags & SN_FINST_MASK))
5105 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005106 return 1;
5107 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005108 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5109 //FD_CLR(t->srv_fd, StaticReadEvent);
5110 tv_eternity(&t->srexpire);
5111 fd_delete(t->srv_fd);
5112 //close(t->srv_fd);
5113 t->srv_state = SV_STCLOSE;
5114 return 1;
5115 }
5116 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5117 //FD_CLR(t->srv_fd, StaticReadEvent);
5118 tv_eternity(&t->srexpire);
5119 fd_delete(t->srv_fd);
5120 //close(t->srv_fd);
5121 t->srv_state = SV_STCLOSE;
5122 if (!(t->flags & SN_ERR_MASK))
5123 t->flags |= SN_ERR_SRVTO;
5124 if (!(t->flags & SN_FINST_MASK))
5125 t->flags |= SN_FINST_D;
5126 return 1;
5127 }
willy tarreau0f7af912005-12-17 12:21:26 +01005128 else if (rep->l == BUFSIZE) { /* no room to read more data */
5129 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5130 FD_CLR(t->srv_fd, StaticReadEvent);
5131 tv_eternity(&t->srexpire);
5132 }
5133 }
5134 else {
5135 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5136 FD_SET(t->srv_fd, StaticReadEvent);
5137 if (t->proxy->srvtimeout)
5138 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5139 else
5140 tv_eternity(&t->srexpire);
5141 }
5142 }
5143 return 0;
5144 }
5145 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005146 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005147 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005148 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 +01005149 write(1, trash, len);
5150 }
5151 return 0;
5152 }
5153 return 0;
5154}
5155
5156
willy tarreau5cbea6f2005-12-17 12:48:26 +01005157/* Processes the client and server jobs of a session task, then
5158 * puts it back to the wait queue in a clean state, or
5159 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005160 * the time the task accepts to wait, or TIME_ETERNITY for
5161 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005162 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005163int process_session(struct task *t) {
5164 struct session *s = t->context;
5165 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005166
willy tarreau5cbea6f2005-12-17 12:48:26 +01005167 do {
5168 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005169 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005170 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005171 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005172 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005173 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005174 } while (fsm_resync);
5175
5176 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005177 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005178 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005179
willy tarreau5cbea6f2005-12-17 12:48:26 +01005180 tv_min(&min1, &s->crexpire, &s->cwexpire);
5181 tv_min(&min2, &s->srexpire, &s->swexpire);
5182 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005183 tv_min(&t->expire, &min1, &min2);
5184
5185 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005186 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005187
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005188#ifdef DEBUG_FULL
5189 /* DEBUG code : this should never ever happen, otherwise it indicates
5190 * that a task still has something to do and will provoke a quick loop.
5191 */
5192 if (tv_remain2(&now, &t->expire) <= 0)
5193 exit(100);
5194#endif
5195
willy tarreaub952e1d2005-12-18 01:31:20 +01005196 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005197 }
5198
willy tarreau5cbea6f2005-12-17 12:48:26 +01005199 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005200 actconn--;
5201
willy tarreau982249e2005-12-18 00:57:06 +01005202 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005203 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005204 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 +01005205 write(1, trash, len);
5206 }
5207
willy tarreau750a4722005-12-17 13:21:24 +01005208 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005209 if (s->rep != NULL)
5210 s->logs.bytes = s->rep->total;
5211
willy tarreau9fe663a2005-12-17 13:02:59 +01005212 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005213 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005214 sess_log(s);
5215
willy tarreau0f7af912005-12-17 12:21:26 +01005216 /* the task MUST not be in the run queue anymore */
5217 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005218 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005219 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005220 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005221}
5222
5223
5224
5225/*
5226 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005227 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005228 */
5229int process_chk(struct task *t) {
5230 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005231 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005232 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005233
willy tarreauef900ab2005-12-17 12:52:52 +01005234 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005235
willy tarreau25424f82006-03-19 19:37:48 +01005236 new_chk:
5237 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005238 if (fd < 0) { /* no check currently running */
5239 //fprintf(stderr, "process_chk: 2\n");
5240 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5241 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005242 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005243 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005244
5245 /* we don't send any health-checks when the proxy is stopped or when
5246 * the server should not be checked.
5247 */
5248 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005249 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5250 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005251 task_queue(t); /* restore t to its place in the task list */
5252 return tv_remain2(&now, &t->expire);
5253 }
5254
willy tarreau5cbea6f2005-12-17 12:48:26 +01005255 /* we'll initiate a new check */
5256 s->result = 0; /* no result yet */
5257 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005258 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005259 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5260 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5261 //fprintf(stderr, "process_chk: 3\n");
5262
willy tarreaua41a8b42005-12-17 14:02:24 +01005263 /* we'll connect to the check port on the server */
5264 sa = s->addr;
5265 sa.sin_port = htons(s->check_port);
5266
willy tarreau0174f312005-12-18 01:02:42 +01005267 /* allow specific binding :
5268 * - server-specific at first
5269 * - proxy-specific next
5270 */
5271 if (s->state & SRV_BIND_SRC) {
5272 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5273 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5274 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5275 s->proxy->id, s->id);
5276 s->result = -1;
5277 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005278 }
willy tarreau0174f312005-12-18 01:02:42 +01005279 else if (s->proxy->options & PR_O_BIND_SRC) {
5280 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5281 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5282 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5283 s->proxy->id);
5284 s->result = -1;
5285 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005286 }
willy tarreau0174f312005-12-18 01:02:42 +01005287
5288 if (!s->result) {
5289 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5290 /* OK, connection in progress or established */
5291
5292 //fprintf(stderr, "process_chk: 4\n");
5293
5294 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5295 fdtab[fd].owner = t;
5296 fdtab[fd].read = &event_srv_chk_r;
5297 fdtab[fd].write = &event_srv_chk_w;
5298 fdtab[fd].state = FD_STCONN; /* connection in progress */
5299 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005300#ifdef DEBUG_FULL
5301 assert (!FD_ISSET(fd, StaticReadEvent));
5302#endif
willy tarreau0174f312005-12-18 01:02:42 +01005303 fd_insert(fd);
5304 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5305 tv_delayfrom(&t->expire, &now, s->inter);
5306 task_queue(t); /* restore t to its place in the task list */
5307 return tv_remain(&now, &t->expire);
5308 }
5309 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5310 s->result = -1; /* a real error */
5311 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005312 }
5313 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005314 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005315 }
5316
5317 if (!s->result) { /* nothing done */
5318 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005319 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5320 tv_delayfrom(&t->expire, &t->expire, s->inter);
5321 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005322 }
5323
5324 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005325 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005326 s->health--; /* still good */
5327 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005328 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005329 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005330 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005331 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005332 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5333 s->state & SRV_BACKUP ? "Backup " : "",
5334 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5335 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5336 send_log(s->proxy, LOG_ALERT,
5337 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5338 s->state & SRV_BACKUP ? "Backup " : "",
5339 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5340 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005341
willy tarreau62084d42006-03-24 18:57:41 +01005342 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005343 Alert("Proxy %s has no server available !\n", s->proxy->id);
5344 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5345 }
5346 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005347 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005348 }
5349
5350 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005351 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005352 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5353 tv_delayfrom(&t->expire, &t->expire, s->inter);
5354 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005355 }
5356 else {
5357 //fprintf(stderr, "process_chk: 8\n");
5358 /* there was a test running */
5359 if (s->result > 0) { /* good server detected */
5360 //fprintf(stderr, "process_chk: 9\n");
5361 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005362 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005363 s->state |= SRV_RUNNING;
5364
willy tarreau535ae7a2005-12-17 12:58:00 +01005365 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005366 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005367 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005368 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5369 s->state & SRV_BACKUP ? "Backup " : "",
5370 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5371 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5372 send_log(s->proxy, LOG_NOTICE,
5373 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5374 s->state & SRV_BACKUP ? "Backup " : "",
5375 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5376 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005377 }
willy tarreauef900ab2005-12-17 12:52:52 +01005378
willy tarreaue47c8d72005-12-17 12:55:52 +01005379 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005380 }
willy tarreauef900ab2005-12-17 12:52:52 +01005381 s->curfd = -1; /* no check running anymore */
5382 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005383 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005384 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5385 tv_delayfrom(&t->expire, &t->expire, s->inter);
5386 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005387 }
5388 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5389 //fprintf(stderr, "process_chk: 10\n");
5390 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005391 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005392 s->health--; /* still good */
5393 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005394 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005395
willy tarreau62084d42006-03-24 18:57:41 +01005396 if (s->health == s->rise) {
5397 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005398 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005399 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5400 s->state & SRV_BACKUP ? "Backup " : "",
5401 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5402 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5403 send_log(s->proxy, LOG_ALERT,
5404 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5405 s->state & SRV_BACKUP ? "Backup " : "",
5406 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5407 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5408
5409 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5410 Alert("Proxy %s has no server available !\n", s->proxy->id);
5411 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5412 }
5413 }
willy tarreauef900ab2005-12-17 12:52:52 +01005414
willy tarreau5cbea6f2005-12-17 12:48:26 +01005415 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005416 }
5417 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005418 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005419 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005420 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5421 tv_delayfrom(&t->expire, &t->expire, s->inter);
5422 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005423 }
5424 /* if result is 0 and there's no timeout, we have to wait again */
5425 }
5426 //fprintf(stderr, "process_chk: 11\n");
5427 s->result = 0;
5428 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005429 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005430}
5431
5432
willy tarreau5cbea6f2005-12-17 12:48:26 +01005433
willy tarreau0f7af912005-12-17 12:21:26 +01005434#if STATTIME > 0
5435int stats(void);
5436#endif
5437
5438/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005439 * This does 4 things :
5440 * - wake up all expired tasks
5441 * - call all runnable tasks
5442 * - call maintain_proxies() to enable/disable the listeners
5443 * - return the delay till next event in ms, -1 = wait indefinitely
5444 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5445 *
willy tarreau0f7af912005-12-17 12:21:26 +01005446 */
5447
willy tarreau1c2ad212005-12-18 01:11:29 +01005448int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005449 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005450 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005451 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005452
willy tarreaub952e1d2005-12-18 01:31:20 +01005453 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005454
willy tarreau1c2ad212005-12-18 01:11:29 +01005455 /* look for expired tasks and add them to the run queue.
5456 */
5457 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5458 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5459 tnext = t->next;
5460 if (t->state & TASK_RUNNING)
5461 continue;
5462
willy tarreaub952e1d2005-12-18 01:31:20 +01005463 if (tv_iseternity(&t->expire))
5464 continue;
5465
willy tarreau1c2ad212005-12-18 01:11:29 +01005466 /* wakeup expired entries. It doesn't matter if they are
5467 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005468 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005469 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005470 task_wakeup(&rq, t);
5471 }
5472 else {
5473 /* first non-runnable task. Use its expiration date as an upper bound */
5474 int temp_time = tv_remain(&now, &t->expire);
5475 if (temp_time)
5476 next_time = temp_time;
5477 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005478 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005479 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005480
willy tarreau1c2ad212005-12-18 01:11:29 +01005481 /* process each task in the run queue now. Each task may be deleted
5482 * since we only use tnext.
5483 */
5484 tnext = rq;
5485 while ((t = tnext) != NULL) {
5486 int temp_time;
5487
5488 tnext = t->rqnext;
5489 task_sleep(&rq, t);
5490 temp_time = t->process(t);
5491 next_time = MINTIME(temp_time, next_time);
5492 }
5493
5494 /* maintain all proxies in a consistent state. This should quickly become a task */
5495 time2 = maintain_proxies();
5496 return MINTIME(time2, next_time);
5497}
5498
5499
5500#if defined(ENABLE_EPOLL)
5501
5502/*
5503 * Main epoll() loop.
5504 */
5505
5506/* does 3 actions :
5507 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5508 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5509 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5510 *
5511 * returns 0 if initialization failed, !0 otherwise.
5512 */
5513
5514int epoll_loop(int action) {
5515 int next_time;
5516 int status;
5517 int fd;
5518
5519 int fds, count;
5520 int pr, pw, sr, sw;
5521 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5522 struct epoll_event ev;
5523
5524 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005525 static struct epoll_event *epoll_events = NULL;
5526 static int epoll_fd;
5527
5528 if (action == POLL_LOOP_ACTION_INIT) {
5529 epoll_fd = epoll_create(global.maxsock + 1);
5530 if (epoll_fd < 0)
5531 return 0;
5532 else {
5533 epoll_events = (struct epoll_event*)
5534 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5535 PrevReadEvent = (fd_set *)
5536 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5537 PrevWriteEvent = (fd_set *)
5538 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005539 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005540 return 1;
5541 }
5542 else if (action == POLL_LOOP_ACTION_CLEAN) {
5543 if (PrevWriteEvent) free(PrevWriteEvent);
5544 if (PrevReadEvent) free(PrevReadEvent);
5545 if (epoll_events) free(epoll_events);
5546 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005547 epoll_fd = 0;
5548 return 1;
5549 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005550
willy tarreau1c2ad212005-12-18 01:11:29 +01005551 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005552
willy tarreau1c2ad212005-12-18 01:11:29 +01005553 tv_now(&now);
5554
5555 while (1) {
5556 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005557
5558 /* stop when there's no connection left and we don't allow them anymore */
5559 if (!actconn && listeners == 0)
5560 break;
5561
willy tarreau0f7af912005-12-17 12:21:26 +01005562#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005563 {
5564 int time2;
5565 time2 = stats();
5566 next_time = MINTIME(time2, next_time);
5567 }
willy tarreau0f7af912005-12-17 12:21:26 +01005568#endif
5569
willy tarreau1c2ad212005-12-18 01:11:29 +01005570 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5571
5572 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5573 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5574
5575 if ((ro^rn) | (wo^wn)) {
5576 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5577#define FDSETS_ARE_INT_ALIGNED
5578#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005579
willy tarreauad90a0c2005-12-18 01:09:15 +01005580#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5581#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005582 pr = (ro >> count) & 1;
5583 pw = (wo >> count) & 1;
5584 sr = (rn >> count) & 1;
5585 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005586#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005587 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5588 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5589 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5590 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005591#endif
5592#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005593 pr = FD_ISSET(fd, PrevReadEvent);
5594 pw = FD_ISSET(fd, PrevWriteEvent);
5595 sr = FD_ISSET(fd, StaticReadEvent);
5596 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005597#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005598 if (!((sr^pr) | (sw^pw)))
5599 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005600
willy tarreau1c2ad212005-12-18 01:11:29 +01005601 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5602 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005603
willy tarreaub952e1d2005-12-18 01:31:20 +01005604#ifdef EPOLL_CTL_MOD_WORKAROUND
5605 /* I encountered a rarely reproducible problem with
5606 * EPOLL_CTL_MOD where a modified FD (systematically
5607 * the one in epoll_events[0], fd#7) would sometimes
5608 * be set EPOLL_OUT while asked for a read ! This is
5609 * with the 2.4 epoll patch. The workaround is to
5610 * delete then recreate in case of modification.
5611 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5612 * nor RHEL kernels.
5613 */
5614
5615 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5616 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5617
5618 if ((sr | sw))
5619 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5620#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005621 if ((pr | pw)) {
5622 /* the file-descriptor already exists... */
5623 if ((sr | sw)) {
5624 /* ...and it will still exist */
5625 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5626 // perror("epoll_ctl(MOD)");
5627 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005628 }
5629 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005630 /* ...and it will be removed */
5631 if (fdtab[fd].state != FD_STCLOSE &&
5632 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5633 // perror("epoll_ctl(DEL)");
5634 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005635 }
5636 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005637 } else {
5638 /* the file-descriptor did not exist, let's add it */
5639 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5640 // perror("epoll_ctl(ADD)");
5641 // exit(1);
5642 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005643 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005644#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005645 }
5646 ((int*)PrevReadEvent)[fds] = rn;
5647 ((int*)PrevWriteEvent)[fds] = wn;
5648 }
5649 }
5650
5651 /* now let's wait for events */
5652 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5653 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005654
willy tarreau1c2ad212005-12-18 01:11:29 +01005655 for (count = 0; count < status; count++) {
5656 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005657
5658 if (FD_ISSET(fd, StaticReadEvent)) {
5659 if (fdtab[fd].state == FD_STCLOSE)
5660 continue;
5661 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5662 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005663 }
willy tarreau05be12b2006-03-19 19:35:00 +01005664
5665 if (FD_ISSET(fd, StaticWriteEvent)) {
5666 if (fdtab[fd].state == FD_STCLOSE)
5667 continue;
5668 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5669 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005670 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005671 }
5672 }
5673 return 1;
5674}
5675#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005676
willy tarreauad90a0c2005-12-18 01:09:15 +01005677
willy tarreau5cbea6f2005-12-17 12:48:26 +01005678
willy tarreau1c2ad212005-12-18 01:11:29 +01005679#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005680
willy tarreau1c2ad212005-12-18 01:11:29 +01005681/*
5682 * Main poll() loop.
5683 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005684
willy tarreau1c2ad212005-12-18 01:11:29 +01005685/* does 3 actions :
5686 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5687 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5688 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5689 *
5690 * returns 0 if initialization failed, !0 otherwise.
5691 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005692
willy tarreau1c2ad212005-12-18 01:11:29 +01005693int poll_loop(int action) {
5694 int next_time;
5695 int status;
5696 int fd, nbfd;
5697
5698 int fds, count;
5699 int sr, sw;
5700 unsigned rn, wn; /* read new, write new */
5701
5702 /* private data */
5703 static struct pollfd *poll_events = NULL;
5704
5705 if (action == POLL_LOOP_ACTION_INIT) {
5706 poll_events = (struct pollfd*)
5707 calloc(1, sizeof(struct pollfd) * global.maxsock);
5708 return 1;
5709 }
5710 else if (action == POLL_LOOP_ACTION_CLEAN) {
5711 if (poll_events)
5712 free(poll_events);
5713 return 1;
5714 }
5715
5716 /* OK, it's POLL_LOOP_ACTION_RUN */
5717
5718 tv_now(&now);
5719
5720 while (1) {
5721 next_time = process_runnable_tasks();
5722
5723 /* stop when there's no connection left and we don't allow them anymore */
5724 if (!actconn && listeners == 0)
5725 break;
5726
5727#if STATTIME > 0
5728 {
5729 int time2;
5730 time2 = stats();
5731 next_time = MINTIME(time2, next_time);
5732 }
5733#endif
5734
5735
5736 nbfd = 0;
5737 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5738
5739 rn = ((int*)StaticReadEvent)[fds];
5740 wn = ((int*)StaticWriteEvent)[fds];
5741
5742 if ((rn|wn)) {
5743 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5744#define FDSETS_ARE_INT_ALIGNED
5745#ifdef FDSETS_ARE_INT_ALIGNED
5746
5747#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5748#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5749 sr = (rn >> count) & 1;
5750 sw = (wn >> count) & 1;
5751#else
5752 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5753 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5754#endif
5755#else
5756 sr = FD_ISSET(fd, StaticReadEvent);
5757 sw = FD_ISSET(fd, StaticWriteEvent);
5758#endif
5759 if ((sr|sw)) {
5760 poll_events[nbfd].fd = fd;
5761 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5762 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005763 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005764 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005765 }
5766 }
5767
5768 /* now let's wait for events */
5769 status = poll(poll_events, nbfd, next_time);
5770 tv_now(&now);
5771
5772 for (count = 0; status > 0 && count < nbfd; count++) {
5773 fd = poll_events[count].fd;
5774
5775 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5776 continue;
5777
5778 /* ok, we found one active fd */
5779 status--;
5780
willy tarreau05be12b2006-03-19 19:35:00 +01005781 if (FD_ISSET(fd, StaticReadEvent)) {
5782 if (fdtab[fd].state == FD_STCLOSE)
5783 continue;
5784 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5785 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005786 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005787
willy tarreau05be12b2006-03-19 19:35:00 +01005788 if (FD_ISSET(fd, StaticWriteEvent)) {
5789 if (fdtab[fd].state == FD_STCLOSE)
5790 continue;
5791 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5792 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005793 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005794 }
5795 }
5796 return 1;
5797}
willy tarreauad90a0c2005-12-18 01:09:15 +01005798#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005799
willy tarreauad90a0c2005-12-18 01:09:15 +01005800
willy tarreauad90a0c2005-12-18 01:09:15 +01005801
willy tarreau1c2ad212005-12-18 01:11:29 +01005802/*
5803 * Main select() loop.
5804 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005805
willy tarreau1c2ad212005-12-18 01:11:29 +01005806/* does 3 actions :
5807 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5808 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5809 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5810 *
5811 * returns 0 if initialization failed, !0 otherwise.
5812 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005813
willy tarreauad90a0c2005-12-18 01:09:15 +01005814
willy tarreau1c2ad212005-12-18 01:11:29 +01005815int select_loop(int action) {
5816 int next_time;
5817 int status;
5818 int fd,i;
5819 struct timeval delta;
5820 int readnotnull, writenotnull;
5821 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005822
willy tarreau1c2ad212005-12-18 01:11:29 +01005823 if (action == POLL_LOOP_ACTION_INIT) {
5824 ReadEvent = (fd_set *)
5825 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5826 WriteEvent = (fd_set *)
5827 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5828 return 1;
5829 }
5830 else if (action == POLL_LOOP_ACTION_CLEAN) {
5831 if (WriteEvent) free(WriteEvent);
5832 if (ReadEvent) free(ReadEvent);
5833 return 1;
5834 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005835
willy tarreau1c2ad212005-12-18 01:11:29 +01005836 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005837
willy tarreau1c2ad212005-12-18 01:11:29 +01005838 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005839
willy tarreau1c2ad212005-12-18 01:11:29 +01005840 while (1) {
5841 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005842
willy tarreau1c2ad212005-12-18 01:11:29 +01005843 /* stop when there's no connection left and we don't allow them anymore */
5844 if (!actconn && listeners == 0)
5845 break;
5846
5847#if STATTIME > 0
5848 {
5849 int time2;
5850 time2 = stats();
5851 next_time = MINTIME(time2, next_time);
5852 }
5853#endif
5854
willy tarreau1c2ad212005-12-18 01:11:29 +01005855 if (next_time > 0) { /* FIXME */
5856 /* Convert to timeval */
5857 /* to avoid eventual select loops due to timer precision */
5858 next_time += SCHEDULER_RESOLUTION;
5859 delta.tv_sec = next_time / 1000;
5860 delta.tv_usec = (next_time % 1000) * 1000;
5861 }
5862 else if (next_time == 0) { /* allow select to return immediately when needed */
5863 delta.tv_sec = delta.tv_usec = 0;
5864 }
5865
5866
5867 /* let's restore fdset state */
5868
5869 readnotnull = 0; writenotnull = 0;
5870 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5871 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5872 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5873 }
5874
5875 // /* just a verification code, needs to be removed for performance */
5876 // for (i=0; i<maxfd; i++) {
5877 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5878 // abort();
5879 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5880 // abort();
5881 //
5882 // }
5883
5884 status = select(maxfd,
5885 readnotnull ? ReadEvent : NULL,
5886 writenotnull ? WriteEvent : NULL,
5887 NULL,
5888 (next_time >= 0) ? &delta : NULL);
5889
5890 /* this is an experiment on the separation of the select work */
5891 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5892 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5893
5894 tv_now(&now);
5895
5896 if (status > 0) { /* must proceed with events */
5897
5898 int fds;
5899 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005900
willy tarreau1c2ad212005-12-18 01:11:29 +01005901 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5902 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5903 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5904
5905 /* if we specify read first, the accepts and zero reads will be
5906 * seen first. Moreover, system buffers will be flushed faster.
5907 */
willy tarreau05be12b2006-03-19 19:35:00 +01005908 if (FD_ISSET(fd, ReadEvent)) {
5909 if (fdtab[fd].state == FD_STCLOSE)
5910 continue;
5911 fdtab[fd].read(fd);
5912 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005913
willy tarreau05be12b2006-03-19 19:35:00 +01005914 if (FD_ISSET(fd, WriteEvent)) {
5915 if (fdtab[fd].state == FD_STCLOSE)
5916 continue;
5917 fdtab[fd].write(fd);
5918 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005919 }
5920 }
5921 else {
5922 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005923 }
willy tarreau0f7af912005-12-17 12:21:26 +01005924 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005925 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005926}
5927
5928
5929#if STATTIME > 0
5930/*
5931 * Display proxy statistics regularly. It is designed to be called from the
5932 * select_loop().
5933 */
5934int stats(void) {
5935 static int lines;
5936 static struct timeval nextevt;
5937 static struct timeval lastevt;
5938 static struct timeval starttime = {0,0};
5939 unsigned long totaltime, deltatime;
5940 int ret;
5941
willy tarreau750a4722005-12-17 13:21:24 +01005942 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005943 deltatime = (tv_diff(&lastevt, &now)?:1);
5944 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005945
willy tarreau9fe663a2005-12-17 13:02:59 +01005946 if (global.mode & MODE_STATS) {
5947 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005948 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005949 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5950 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005951 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005952 actconn, totalconn,
5953 stats_tsk_new, stats_tsk_good,
5954 stats_tsk_left, stats_tsk_right,
5955 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5956 }
5957 }
5958
5959 tv_delayfrom(&nextevt, &now, STATTIME);
5960
5961 lastevt=now;
5962 }
5963 ret = tv_remain(&now, &nextevt);
5964 return ret;
5965}
5966#endif
5967
5968
5969/*
5970 * this function enables proxies when there are enough free sessions,
5971 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005972 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005973 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005974 */
5975static int maintain_proxies(void) {
5976 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005977 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005978 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005979
5980 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005981 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005982
5983 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005984 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005985 while (p) {
5986 if (p->nbconn < p->maxconn) {
5987 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005988 for (l = p->listen; l != NULL; l = l->next) {
5989 FD_SET(l->fd, StaticReadEvent);
5990 }
willy tarreau0f7af912005-12-17 12:21:26 +01005991 p->state = PR_STRUN;
5992 }
5993 }
5994 else {
5995 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005996 for (l = p->listen; l != NULL; l = l->next) {
5997 FD_CLR(l->fd, StaticReadEvent);
5998 }
willy tarreau0f7af912005-12-17 12:21:26 +01005999 p->state = PR_STIDLE;
6000 }
6001 }
6002 p = p->next;
6003 }
6004 }
6005 else { /* block all proxies */
6006 while (p) {
6007 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006008 for (l = p->listen; l != NULL; l = l->next) {
6009 FD_CLR(l->fd, StaticReadEvent);
6010 }
willy tarreau0f7af912005-12-17 12:21:26 +01006011 p->state = PR_STIDLE;
6012 }
6013 p = p->next;
6014 }
6015 }
6016
willy tarreau5cbea6f2005-12-17 12:48:26 +01006017 if (stopping) {
6018 p = proxy;
6019 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006020 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006021 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006022 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006023 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006024 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006025 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006026
willy tarreaua41a8b42005-12-17 14:02:24 +01006027 for (l = p->listen; l != NULL; l = l->next) {
6028 fd_delete(l->fd);
6029 listeners--;
6030 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006031 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006032 }
6033 else {
6034 tleft = MINTIME(t, tleft);
6035 }
6036 }
6037 p = p->next;
6038 }
6039 }
6040 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006041}
6042
6043/*
6044 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006045 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6046 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006047 */
6048static void soft_stop(void) {
6049 struct proxy *p;
6050
6051 stopping = 1;
6052 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006053 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006054 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006055 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006056 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006057 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006058 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006059 }
willy tarreau0f7af912005-12-17 12:21:26 +01006060 p = p->next;
6061 }
6062}
6063
willy tarreaudbd3bef2006-01-20 19:35:18 +01006064static void pause_proxy(struct proxy *p) {
6065 struct listener *l;
6066 for (l = p->listen; l != NULL; l = l->next) {
6067 shutdown(l->fd, SHUT_RD);
6068 FD_CLR(l->fd, StaticReadEvent);
6069 p->state = PR_STPAUSED;
6070 }
6071}
6072
6073/*
6074 * This function temporarily disables listening so that another new instance
6075 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006076 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006077 * the proxy, or a SIGTTIN can be sent to listen again.
6078 */
6079static void pause_proxies(void) {
6080 struct proxy *p;
6081
6082 p = proxy;
6083 tv_now(&now); /* else, the old time before select will be used */
6084 while (p) {
6085 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6086 Warning("Pausing proxy %s.\n", p->id);
6087 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6088 pause_proxy(p);
6089 }
6090 p = p->next;
6091 }
6092}
6093
6094
6095/*
6096 * This function reactivates listening. This can be used after a call to
6097 * sig_pause(), for example when a new instance has failed starting up.
6098 * It is designed to be called upon reception of a SIGTTIN.
6099 */
6100static void listen_proxies(void) {
6101 struct proxy *p;
6102 struct listener *l;
6103
6104 p = proxy;
6105 tv_now(&now); /* else, the old time before select will be used */
6106 while (p) {
6107 if (p->state == PR_STPAUSED) {
6108 Warning("Enabling proxy %s.\n", p->id);
6109 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6110
6111 for (l = p->listen; l != NULL; l = l->next) {
6112 if (listen(l->fd, p->maxconn) == 0) {
6113 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6114 FD_SET(l->fd, StaticReadEvent);
6115 p->state = PR_STRUN;
6116 }
6117 else
6118 p->state = PR_STIDLE;
6119 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006120 int port;
6121
6122 if (l->addr.ss_family == AF_INET6)
6123 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6124 else
6125 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6126
willy tarreaudbd3bef2006-01-20 19:35:18 +01006127 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006128 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006129 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006130 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006131 /* Another port might have been enabled. Let's stop everything. */
6132 pause_proxy(p);
6133 break;
6134 }
6135 }
6136 }
6137 p = p->next;
6138 }
6139}
6140
6141
willy tarreau0f7af912005-12-17 12:21:26 +01006142/*
6143 * upon SIGUSR1, let's have a soft stop.
6144 */
6145void sig_soft_stop(int sig) {
6146 soft_stop();
6147 signal(sig, SIG_IGN);
6148}
6149
willy tarreaudbd3bef2006-01-20 19:35:18 +01006150/*
6151 * upon SIGTTOU, we pause everything
6152 */
6153void sig_pause(int sig) {
6154 pause_proxies();
6155 signal(sig, sig_pause);
6156}
willy tarreau0f7af912005-12-17 12:21:26 +01006157
willy tarreau8337c6b2005-12-17 13:41:01 +01006158/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006159 * upon SIGTTIN, let's have a soft stop.
6160 */
6161void sig_listen(int sig) {
6162 listen_proxies();
6163 signal(sig, sig_listen);
6164}
6165
6166/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006167 * this function dumps every server's state when the process receives SIGHUP.
6168 */
6169void sig_dump_state(int sig) {
6170 struct proxy *p = proxy;
6171
6172 Warning("SIGHUP received, dumping servers states.\n");
6173 while (p) {
6174 struct server *s = p->srv;
6175
6176 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6177 while (s) {
6178 if (s->state & SRV_RUNNING) {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006179 Warning("SIGHUP: Server %s/%s is UP.\n", p->id, s->id);
6180 send_log(p, LOG_NOTICE, "SIGUP: Server %s/%s is UP.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006181 }
6182 else {
willy tarreaufd6dfe72006-03-19 19:38:19 +01006183 Warning("SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
6184 send_log(p, LOG_NOTICE, "SIGHUP: Server %s/%s is DOWN.\n", p->id, s->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006185 }
6186 s = s->next;
6187 }
willy tarreaudd07e972005-12-18 00:48:48 +01006188
willy tarreau62084d42006-03-24 18:57:41 +01006189 if (p->srv_act == 0) {
6190 if (p->srv_bck) {
6191 Warning("SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6192 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s is running on backup servers !\n", p->id);
6193 } else {
6194 Warning("SIGHUP: Proxy %s has no server available !\n", p->id);
6195 send_log(p, LOG_NOTICE, "SIGHUP: Proxy %s has no server available !\n", p->id);
6196 }
6197 }
willy tarreaudd07e972005-12-18 00:48:48 +01006198
willy tarreau8337c6b2005-12-17 13:41:01 +01006199 p = p->next;
6200 }
6201 signal(sig, sig_dump_state);
6202}
6203
willy tarreau0f7af912005-12-17 12:21:26 +01006204void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006205 struct task *t, *tnext;
6206 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006207
willy tarreau5cbea6f2005-12-17 12:48:26 +01006208 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6209 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6210 tnext = t->next;
6211 s = t->context;
6212 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6213 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6214 "req=%d, rep=%d, clifd=%d\n",
6215 s, tv_remain(&now, &t->expire),
6216 s->cli_state,
6217 s->srv_state,
6218 FD_ISSET(s->cli_fd, StaticReadEvent),
6219 FD_ISSET(s->cli_fd, StaticWriteEvent),
6220 FD_ISSET(s->srv_fd, StaticReadEvent),
6221 FD_ISSET(s->srv_fd, StaticWriteEvent),
6222 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6223 );
willy tarreau0f7af912005-12-17 12:21:26 +01006224 }
willy tarreau12350152005-12-18 01:03:27 +01006225}
6226
willy tarreau64a3cc32005-12-18 01:13:11 +01006227#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006228static void fast_stop(void)
6229{
6230 struct proxy *p;
6231 p = proxy;
6232 while (p) {
6233 p->grace = 0;
6234 p = p->next;
6235 }
6236 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006237}
6238
willy tarreau12350152005-12-18 01:03:27 +01006239void sig_int(int sig) {
6240 /* This would normally be a hard stop,
6241 but we want to be sure about deallocation,
6242 and so on, so we do a soft stop with
6243 0 GRACE time
6244 */
6245 fast_stop();
6246 /* If we are killed twice, we decide to die*/
6247 signal(sig, SIG_DFL);
6248}
6249
6250void sig_term(int sig) {
6251 /* This would normally be a hard stop,
6252 but we want to be sure about deallocation,
6253 and so on, so we do a soft stop with
6254 0 GRACE time
6255 */
6256 fast_stop();
6257 /* If we are killed twice, we decide to die*/
6258 signal(sig, SIG_DFL);
6259}
willy tarreau64a3cc32005-12-18 01:13:11 +01006260#endif
willy tarreau12350152005-12-18 01:03:27 +01006261
willy tarreauc1f47532005-12-18 01:08:26 +01006262/* returns the pointer to an error in the replacement string, or NULL if OK */
6263char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006264 struct hdr_exp *exp;
6265
willy tarreauc1f47532005-12-18 01:08:26 +01006266 if (replace != NULL) {
6267 char *err;
6268 err = check_replace_string(replace);
6269 if (err)
6270 return err;
6271 }
6272
willy tarreaue39cd132005-12-17 13:00:18 +01006273 while (*head != NULL)
6274 head = &(*head)->next;
6275
6276 exp = calloc(1, sizeof(struct hdr_exp));
6277
6278 exp->preg = preg;
6279 exp->replace = replace;
6280 exp->action = action;
6281 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006282
6283 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006284}
6285
willy tarreau9fe663a2005-12-17 13:02:59 +01006286
willy tarreau0f7af912005-12-17 12:21:26 +01006287/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006288 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006289 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006290int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006291
willy tarreau9fe663a2005-12-17 13:02:59 +01006292 if (!strcmp(args[0], "global")) { /* new section */
6293 /* no option, nothing special to do */
6294 return 0;
6295 }
6296 else if (!strcmp(args[0], "daemon")) {
6297 global.mode |= MODE_DAEMON;
6298 }
6299 else if (!strcmp(args[0], "debug")) {
6300 global.mode |= MODE_DEBUG;
6301 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006302 else if (!strcmp(args[0], "noepoll")) {
6303 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6304 }
6305 else if (!strcmp(args[0], "nopoll")) {
6306 cfg_polling_mechanism &= ~POLL_USE_POLL;
6307 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006308 else if (!strcmp(args[0], "quiet")) {
6309 global.mode |= MODE_QUIET;
6310 }
6311 else if (!strcmp(args[0], "stats")) {
6312 global.mode |= MODE_STATS;
6313 }
6314 else if (!strcmp(args[0], "uid")) {
6315 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006316 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006317 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006318 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006319 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006320 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006321 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006322 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006323 global.uid = atol(args[1]);
6324 }
6325 else if (!strcmp(args[0], "gid")) {
6326 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006327 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006328 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006329 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006330 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006331 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006332 return -1;
6333 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006334 global.gid = atol(args[1]);
6335 }
6336 else if (!strcmp(args[0], "nbproc")) {
6337 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006338 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006339 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006340 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006341 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006342 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006343 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006344 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006345 global.nbproc = atol(args[1]);
6346 }
6347 else if (!strcmp(args[0], "maxconn")) {
6348 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006349 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006350 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006351 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006352 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006353 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006354 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006356 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006357#ifdef SYSTEM_MAXCONN
6358 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6359 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);
6360 global.maxconn = DEFAULT_MAXCONN;
6361 }
6362#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006363 }
willy tarreaub1285d52005-12-18 01:20:14 +01006364 else if (!strcmp(args[0], "ulimit-n")) {
6365 if (global.rlimit_nofile != 0) {
6366 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6367 return 0;
6368 }
6369 if (*(args[1]) == 0) {
6370 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6371 return -1;
6372 }
6373 global.rlimit_nofile = atol(args[1]);
6374 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006375 else if (!strcmp(args[0], "chroot")) {
6376 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006377 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 return 0;
6379 }
6380 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006381 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006382 return -1;
6383 }
6384 global.chroot = strdup(args[1]);
6385 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006386 else if (!strcmp(args[0], "pidfile")) {
6387 if (global.pidfile != NULL) {
6388 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6389 return 0;
6390 }
6391 if (*(args[1]) == 0) {
6392 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6393 return -1;
6394 }
6395 global.pidfile = strdup(args[1]);
6396 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006397 else if (!strcmp(args[0], "log")) { /* syslog server address */
6398 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006399 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006400
6401 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006402 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006403 return -1;
6404 }
6405
6406 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6407 if (!strcmp(log_facilities[facility], args[2]))
6408 break;
6409
6410 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006411 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006412 exit(1);
6413 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006414
6415 level = 7; /* max syslog level = debug */
6416 if (*(args[3])) {
6417 while (level >= 0 && strcmp(log_levels[level], args[3]))
6418 level--;
6419 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006420 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006421 exit(1);
6422 }
6423 }
6424
willy tarreau9fe663a2005-12-17 13:02:59 +01006425 sa = str2sa(args[1]);
6426 if (!sa->sin_port)
6427 sa->sin_port = htons(SYSLOG_PORT);
6428
6429 if (global.logfac1 == -1) {
6430 global.logsrv1 = *sa;
6431 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006432 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006433 }
6434 else if (global.logfac2 == -1) {
6435 global.logsrv2 = *sa;
6436 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006437 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006438 }
6439 else {
6440 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6441 return -1;
6442 }
6443
6444 }
6445 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006446 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006447 return -1;
6448 }
6449 return 0;
6450}
6451
6452
willy tarreaua41a8b42005-12-17 14:02:24 +01006453void init_default_instance() {
6454 memset(&defproxy, 0, sizeof(defproxy));
6455 defproxy.mode = PR_MODE_TCP;
6456 defproxy.state = PR_STNEW;
6457 defproxy.maxconn = cfg_maxpconn;
6458 defproxy.conn_retries = CONN_RETRIES;
6459 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6460}
6461
willy tarreau9fe663a2005-12-17 13:02:59 +01006462/*
6463 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6464 */
6465int cfg_parse_listen(char *file, int linenum, char **args) {
6466 static struct proxy *curproxy = NULL;
6467 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006468 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006469 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006470
6471 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006472 if (!*args[1]) {
6473 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6474 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006475 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006476 return -1;
6477 }
6478
6479 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006480 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006481 return -1;
6482 }
6483 curproxy->next = proxy;
6484 proxy = curproxy;
6485 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006486
6487 /* parse the listener address if any */
6488 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006489 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006490 if (!curproxy->listen)
6491 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006492 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006493 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006494
willy tarreau9fe663a2005-12-17 13:02:59 +01006495 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006496 curproxy->state = defproxy.state;
6497 curproxy->maxconn = defproxy.maxconn;
6498 curproxy->conn_retries = defproxy.conn_retries;
6499 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006500
6501 if (defproxy.check_req)
6502 curproxy->check_req = strdup(defproxy.check_req);
6503 curproxy->check_len = defproxy.check_len;
6504
6505 if (defproxy.cookie_name)
6506 curproxy->cookie_name = strdup(defproxy.cookie_name);
6507 curproxy->cookie_len = defproxy.cookie_len;
6508
6509 if (defproxy.capture_name)
6510 curproxy->capture_name = strdup(defproxy.capture_name);
6511 curproxy->capture_namelen = defproxy.capture_namelen;
6512 curproxy->capture_len = defproxy.capture_len;
6513
6514 if (defproxy.errmsg.msg400)
6515 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6516 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6517
6518 if (defproxy.errmsg.msg403)
6519 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6520 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6521
6522 if (defproxy.errmsg.msg408)
6523 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6524 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6525
6526 if (defproxy.errmsg.msg500)
6527 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6528 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6529
6530 if (defproxy.errmsg.msg502)
6531 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6532 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6533
6534 if (defproxy.errmsg.msg503)
6535 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6536 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6537
6538 if (defproxy.errmsg.msg504)
6539 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6540 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6541
willy tarreaua41a8b42005-12-17 14:02:24 +01006542 curproxy->clitimeout = defproxy.clitimeout;
6543 curproxy->contimeout = defproxy.contimeout;
6544 curproxy->srvtimeout = defproxy.srvtimeout;
6545 curproxy->mode = defproxy.mode;
6546 curproxy->logfac1 = defproxy.logfac1;
6547 curproxy->logsrv1 = defproxy.logsrv1;
6548 curproxy->loglev1 = defproxy.loglev1;
6549 curproxy->logfac2 = defproxy.logfac2;
6550 curproxy->logsrv2 = defproxy.logsrv2;
6551 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006552 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006553 curproxy->grace = defproxy.grace;
6554 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006555 curproxy->mon_net = defproxy.mon_net;
6556 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006557 return 0;
6558 }
6559 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006560 /* some variables may have already been initialized earlier */
6561 if (defproxy.check_req) free(defproxy.check_req);
6562 if (defproxy.cookie_name) free(defproxy.cookie_name);
6563 if (defproxy.capture_name) free(defproxy.capture_name);
6564 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6565 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6566 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6567 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6568 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6569 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6570 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6571
6572 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006573 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006574 return 0;
6575 }
6576 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006577 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006578 return -1;
6579 }
6580
willy tarreaua41a8b42005-12-17 14:02:24 +01006581 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6582 if (curproxy == &defproxy) {
6583 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6584 return -1;
6585 }
6586
6587 if (strchr(args[1], ':') == NULL) {
6588 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6589 file, linenum, args[0]);
6590 return -1;
6591 }
6592 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006593 if (!curproxy->listen)
6594 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006595 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006596 return 0;
6597 }
willy tarreaub1285d52005-12-18 01:20:14 +01006598 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6599 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6600 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6601 file, linenum, args[0]);
6602 return -1;
6603 }
6604 /* flush useless bits */
6605 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6606 return 0;
6607 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006608 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006609 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6610 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6611 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6612 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006613 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006614 return -1;
6615 }
6616 }
6617 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006618 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006619 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006620 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6621 curproxy->state = PR_STNEW;
6622 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006623 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6624 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006625// if (curproxy == &defproxy) {
6626// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6627// return -1;
6628// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006629
willy tarreau9fe663a2005-12-17 13:02:59 +01006630 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006631// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6632// file, linenum);
6633// return 0;
6634 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006635 }
6636
6637 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006638 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6639 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006640 return -1;
6641 }
6642 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006643 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006644
6645 cur_arg = 2;
6646 while (*(args[cur_arg])) {
6647 if (!strcmp(args[cur_arg], "rewrite")) {
6648 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006649 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006650 else if (!strcmp(args[cur_arg], "indirect")) {
6651 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006652 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006653 else if (!strcmp(args[cur_arg], "insert")) {
6654 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006655 }
willy tarreau240afa62005-12-17 13:14:35 +01006656 else if (!strcmp(args[cur_arg], "nocache")) {
6657 curproxy->options |= PR_O_COOK_NOC;
6658 }
willy tarreaucd878942005-12-17 13:27:43 +01006659 else if (!strcmp(args[cur_arg], "postonly")) {
6660 curproxy->options |= PR_O_COOK_POST;
6661 }
willy tarreau0174f312005-12-18 01:02:42 +01006662 else if (!strcmp(args[cur_arg], "prefix")) {
6663 curproxy->options |= PR_O_COOK_PFX;
6664 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006665 else {
willy tarreau0174f312005-12-18 01:02:42 +01006666 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006667 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006668 return -1;
6669 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006670 cur_arg++;
6671 }
willy tarreau0174f312005-12-18 01:02:42 +01006672 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6673 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6674 file, linenum);
6675 return -1;
6676 }
6677
6678 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6679 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006680 file, linenum);
6681 return -1;
6682 }
willy tarreau12350152005-12-18 01:03:27 +01006683 }/* end else if (!strcmp(args[0], "cookie")) */
6684 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6685// if (curproxy == &defproxy) {
6686// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6687// return -1;
6688// }
6689
6690 if (curproxy->appsession_name != NULL) {
6691// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6692// file, linenum);
6693// return 0;
6694 free(curproxy->appsession_name);
6695 }
6696
6697 if (*(args[5]) == 0) {
6698 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6699 file, linenum, args[0]);
6700 return -1;
6701 }
6702 have_appsession = 1;
6703 curproxy->appsession_name = strdup(args[1]);
6704 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6705 curproxy->appsession_len = atoi(args[3]);
6706 curproxy->appsession_timeout = atoi(args[5]);
6707 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6708 if (rc) {
6709 Alert("Error Init Appsession Hashtable.\n");
6710 return -1;
6711 }
6712 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006713 else if (!strcmp(args[0], "capture")) {
6714 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6715 // if (curproxy == &defproxy) {
6716 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6717 // return -1;
6718 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006719
willy tarreau4302f492005-12-18 01:00:37 +01006720 if (curproxy->capture_name != NULL) {
6721 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6722 // file, linenum, args[0]);
6723 // return 0;
6724 free(curproxy->capture_name);
6725 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006726
willy tarreau4302f492005-12-18 01:00:37 +01006727 if (*(args[4]) == 0) {
6728 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6729 file, linenum, args[0]);
6730 return -1;
6731 }
6732 curproxy->capture_name = strdup(args[2]);
6733 curproxy->capture_namelen = strlen(curproxy->capture_name);
6734 curproxy->capture_len = atol(args[4]);
6735 if (curproxy->capture_len >= CAPTURE_LEN) {
6736 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6737 file, linenum, CAPTURE_LEN - 1);
6738 curproxy->capture_len = CAPTURE_LEN - 1;
6739 }
6740 curproxy->to_log |= LW_COOKIE;
6741 }
6742 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6743 struct cap_hdr *hdr;
6744
6745 if (curproxy == &defproxy) {
6746 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6747 return -1;
6748 }
6749
6750 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6751 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6752 file, linenum, args[0], args[1]);
6753 return -1;
6754 }
6755
6756 hdr = calloc(sizeof(struct cap_hdr), 1);
6757 hdr->next = curproxy->req_cap;
6758 hdr->name = strdup(args[3]);
6759 hdr->namelen = strlen(args[3]);
6760 hdr->len = atol(args[5]);
6761 hdr->index = curproxy->nb_req_cap++;
6762 curproxy->req_cap = hdr;
6763 curproxy->to_log |= LW_REQHDR;
6764 }
6765 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6766 struct cap_hdr *hdr;
6767
6768 if (curproxy == &defproxy) {
6769 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6770 return -1;
6771 }
6772
6773 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6774 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6775 file, linenum, args[0], args[1]);
6776 return -1;
6777 }
6778 hdr = calloc(sizeof(struct cap_hdr), 1);
6779 hdr->next = curproxy->rsp_cap;
6780 hdr->name = strdup(args[3]);
6781 hdr->namelen = strlen(args[3]);
6782 hdr->len = atol(args[5]);
6783 hdr->index = curproxy->nb_rsp_cap++;
6784 curproxy->rsp_cap = hdr;
6785 curproxy->to_log |= LW_RSPHDR;
6786 }
6787 else {
6788 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006789 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006790 return -1;
6791 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006792 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006793 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006794 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006795 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006796 return 0;
6797 }
6798 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006799 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6800 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006801 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006802 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006803 curproxy->contimeout = atol(args[1]);
6804 }
6805 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006806 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006807 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6808 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006809 return 0;
6810 }
6811 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006812 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6813 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006814 return -1;
6815 }
6816 curproxy->clitimeout = atol(args[1]);
6817 }
6818 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006819 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006820 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006821 return 0;
6822 }
6823 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006824 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6825 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006826 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006827 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006828 curproxy->srvtimeout = atol(args[1]);
6829 }
6830 else if (!strcmp(args[0], "retries")) { /* connection retries */
6831 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006832 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6833 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006834 return -1;
6835 }
6836 curproxy->conn_retries = atol(args[1]);
6837 }
6838 else if (!strcmp(args[0], "option")) {
6839 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006840 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006841 return -1;
6842 }
6843 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006844 /* enable reconnections to dispatch */
6845 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006846#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006847 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006848 /* enable transparent proxy connections */
6849 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006850#endif
6851 else if (!strcmp(args[1], "keepalive"))
6852 /* enable keep-alive */
6853 curproxy->options |= PR_O_KEEPALIVE;
6854 else if (!strcmp(args[1], "forwardfor"))
6855 /* insert x-forwarded-for field */
6856 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006857 else if (!strcmp(args[1], "logasap"))
6858 /* log as soon as possible, without waiting for the session to complete */
6859 curproxy->options |= PR_O_LOGASAP;
6860 else if (!strcmp(args[1], "httpclose"))
6861 /* force connection: close in both directions in HTTP mode */
6862 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006863 else if (!strcmp(args[1], "forceclose"))
6864 /* force connection: close in both directions in HTTP mode and enforce end of session */
6865 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006866 else if (!strcmp(args[1], "checkcache"))
6867 /* require examination of cacheability of the 'set-cookie' field */
6868 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006869 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006870 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006871 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006872 else if (!strcmp(args[1], "tcplog"))
6873 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006874 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006875 else if (!strcmp(args[1], "dontlognull")) {
6876 /* don't log empty requests */
6877 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006878 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006879 else if (!strcmp(args[1], "tcpka")) {
6880 /* enable TCP keep-alives on client and server sessions */
6881 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6882 }
6883 else if (!strcmp(args[1], "clitcpka")) {
6884 /* enable TCP keep-alives on client sessions */
6885 curproxy->options |= PR_O_TCP_CLI_KA;
6886 }
6887 else if (!strcmp(args[1], "srvtcpka")) {
6888 /* enable TCP keep-alives on server sessions */
6889 curproxy->options |= PR_O_TCP_SRV_KA;
6890 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006891 else if (!strcmp(args[1], "allbackups")) {
6892 /* Use all backup servers simultaneously */
6893 curproxy->options |= PR_O_USE_ALL_BK;
6894 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006895 else if (!strcmp(args[1], "httpchk")) {
6896 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006897 if (curproxy->check_req != NULL) {
6898 free(curproxy->check_req);
6899 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006900 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006901 if (!*args[2]) { /* no argument */
6902 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6903 curproxy->check_len = strlen(DEF_CHECK_REQ);
6904 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006905 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6906 curproxy->check_req = (char *)malloc(reqlen);
6907 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6908 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006909 } else { /* more arguments : METHOD URI [HTTP_VER] */
6910 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6911 if (*args[4])
6912 reqlen += strlen(args[4]);
6913 else
6914 reqlen += strlen("HTTP/1.0");
6915
6916 curproxy->check_req = (char *)malloc(reqlen);
6917 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6918 "%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 +01006919 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006920 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006921 else if (!strcmp(args[1], "persist")) {
6922 /* persist on using the server specified by the cookie, even when it's down */
6923 curproxy->options |= PR_O_PERSIST;
6924 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006925 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006926 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006927 return -1;
6928 }
6929 return 0;
6930 }
6931 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6932 /* enable reconnections to dispatch */
6933 curproxy->options |= PR_O_REDISP;
6934 }
willy tarreaua1598082005-12-17 13:08:06 +01006935#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006936 else if (!strcmp(args[0], "transparent")) {
6937 /* enable transparent proxy connections */
6938 curproxy->options |= PR_O_TRANSP;
6939 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006940#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006941 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6942 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006943 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006944 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006945 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006946 curproxy->maxconn = atol(args[1]);
6947 }
6948 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6949 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006950 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006951 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006952 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006953 curproxy->grace = atol(args[1]);
6954 }
6955 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006956 if (curproxy == &defproxy) {
6957 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6958 return -1;
6959 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006960 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006961 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006962 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006963 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006964 curproxy->dispatch_addr = *str2sa(args[1]);
6965 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006966 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006967 if (*(args[1])) {
6968 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006969 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006970 }
willy tarreau1a3442d2006-03-24 21:03:20 +01006971 else if (!strcmp(args[1], "source")) {
6972 curproxy->options |= PR_O_BALANCE_SH;
6973 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006974 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01006975 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006976 return -1;
6977 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006978 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006979 else /* if no option is set, use round-robin by default */
6980 curproxy->options |= PR_O_BALANCE_RR;
6981 }
6982 else if (!strcmp(args[0], "server")) { /* server address */
6983 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006984 char *rport;
6985 char *raddr;
6986 short realport;
6987 int do_check;
6988
6989 if (curproxy == &defproxy) {
6990 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6991 return -1;
6992 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006993
willy tarreaua41a8b42005-12-17 14:02:24 +01006994 if (!*args[2]) {
6995 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006996 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006997 return -1;
6998 }
6999 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7000 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7001 return -1;
7002 }
willy tarreau0174f312005-12-18 01:02:42 +01007003
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007004 /* the servers are linked backwards first */
7005 newsrv->next = curproxy->srv;
7006 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007007 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007008
7009 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007010 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007011 newsrv->id = strdup(args[1]);
7012
7013 /* several ways to check the port component :
7014 * - IP => port=+0, relative
7015 * - IP: => port=+0, relative
7016 * - IP:N => port=N, absolute
7017 * - IP:+N => port=+N, relative
7018 * - IP:-N => port=-N, relative
7019 */
7020 raddr = strdup(args[2]);
7021 rport = strchr(raddr, ':');
7022 if (rport) {
7023 *rport++ = 0;
7024 realport = atol(rport);
7025 if (!isdigit((int)*rport))
7026 newsrv->state |= SRV_MAPPORTS;
7027 } else {
7028 realport = 0;
7029 newsrv->state |= SRV_MAPPORTS;
7030 }
7031
7032 newsrv->addr = *str2sa(raddr);
7033 newsrv->addr.sin_port = htons(realport);
7034 free(raddr);
7035
willy tarreau9fe663a2005-12-17 13:02:59 +01007036 newsrv->curfd = -1; /* no health-check in progress */
7037 newsrv->inter = DEF_CHKINTR;
7038 newsrv->rise = DEF_RISETIME;
7039 newsrv->fall = DEF_FALLTIME;
7040 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7041 cur_arg = 3;
7042 while (*args[cur_arg]) {
7043 if (!strcmp(args[cur_arg], "cookie")) {
7044 newsrv->cookie = strdup(args[cur_arg + 1]);
7045 newsrv->cklen = strlen(args[cur_arg + 1]);
7046 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007047 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007048 else if (!strcmp(args[cur_arg], "rise")) {
7049 newsrv->rise = atol(args[cur_arg + 1]);
7050 newsrv->health = newsrv->rise;
7051 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007052 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007053 else if (!strcmp(args[cur_arg], "fall")) {
7054 newsrv->fall = atol(args[cur_arg + 1]);
7055 cur_arg += 2;
7056 }
7057 else if (!strcmp(args[cur_arg], "inter")) {
7058 newsrv->inter = atol(args[cur_arg + 1]);
7059 cur_arg += 2;
7060 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007061 else if (!strcmp(args[cur_arg], "port")) {
7062 newsrv->check_port = atol(args[cur_arg + 1]);
7063 cur_arg += 2;
7064 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007065 else if (!strcmp(args[cur_arg], "backup")) {
7066 newsrv->state |= SRV_BACKUP;
7067 cur_arg ++;
7068 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007069 else if (!strcmp(args[cur_arg], "weight")) {
7070 int w;
7071 w = atol(args[cur_arg + 1]);
7072 if (w < 1 || w > 256) {
7073 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7074 file, linenum, newsrv->id, w);
7075 return -1;
7076 }
7077 newsrv->uweight = w - 1;
7078 cur_arg += 2;
7079 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007080 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007081 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007082 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007083 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007084 }
willy tarreau0174f312005-12-18 01:02:42 +01007085 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7086 if (!*args[cur_arg + 1]) {
7087 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7088 file, linenum, "source");
7089 return -1;
7090 }
7091 newsrv->state |= SRV_BIND_SRC;
7092 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7093 cur_arg += 2;
7094 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007095 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007096 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01007097 file, linenum, newsrv->id);
7098 return -1;
7099 }
7100 }
7101
7102 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007103 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7104 newsrv->check_port = realport; /* by default */
7105 if (!newsrv->check_port) {
7106 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 +01007107 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007108 return -1;
7109 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007110 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007111 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007112
willy tarreau62084d42006-03-24 18:57:41 +01007113 if (newsrv->state & SRV_BACKUP)
7114 curproxy->srv_bck++;
7115 else
7116 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007117 }
7118 else if (!strcmp(args[0], "log")) { /* syslog server address */
7119 struct sockaddr_in *sa;
7120 int facility;
7121
7122 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7123 curproxy->logfac1 = global.logfac1;
7124 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007125 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007126 curproxy->logfac2 = global.logfac2;
7127 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007128 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007129 }
7130 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007131 int level;
7132
willy tarreau0f7af912005-12-17 12:21:26 +01007133 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7134 if (!strcmp(log_facilities[facility], args[2]))
7135 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007136
willy tarreau0f7af912005-12-17 12:21:26 +01007137 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007138 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007139 exit(1);
7140 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007141
willy tarreau8337c6b2005-12-17 13:41:01 +01007142 level = 7; /* max syslog level = debug */
7143 if (*(args[3])) {
7144 while (level >= 0 && strcmp(log_levels[level], args[3]))
7145 level--;
7146 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007147 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007148 exit(1);
7149 }
7150 }
7151
willy tarreau0f7af912005-12-17 12:21:26 +01007152 sa = str2sa(args[1]);
7153 if (!sa->sin_port)
7154 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007155
willy tarreau0f7af912005-12-17 12:21:26 +01007156 if (curproxy->logfac1 == -1) {
7157 curproxy->logsrv1 = *sa;
7158 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007159 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007160 }
7161 else if (curproxy->logfac2 == -1) {
7162 curproxy->logsrv2 = *sa;
7163 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007164 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007165 }
7166 else {
7167 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007168 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007169 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007170 }
7171 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007172 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007173 file, linenum);
7174 return -1;
7175 }
7176 }
willy tarreaua1598082005-12-17 13:08:06 +01007177 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007178 if (!*args[1]) {
7179 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007180 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007181 return -1;
7182 }
7183
7184 curproxy->source_addr = *str2sa(args[1]);
7185 curproxy->options |= PR_O_BIND_SRC;
7186 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007187 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7188 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007189 if (curproxy == &defproxy) {
7190 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7191 return -1;
7192 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007193
7194 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007195 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7196 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007197 return -1;
7198 }
7199
7200 preg = calloc(1, sizeof(regex_t));
7201 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007202 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007203 return -1;
7204 }
7205
willy tarreauc1f47532005-12-18 01:08:26 +01007206 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7207 if (err) {
7208 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7209 file, linenum, *err);
7210 return -1;
7211 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007212 }
7213 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7214 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007215 if (curproxy == &defproxy) {
7216 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7217 return -1;
7218 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007219
7220 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007221 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007222 return -1;
7223 }
7224
7225 preg = calloc(1, sizeof(regex_t));
7226 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007227 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007228 return -1;
7229 }
7230
7231 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7232 }
7233 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7234 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007235 if (curproxy == &defproxy) {
7236 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7237 return -1;
7238 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007239
7240 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007241 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007242 return -1;
7243 }
7244
7245 preg = calloc(1, sizeof(regex_t));
7246 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007247 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007248 return -1;
7249 }
7250
7251 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7252 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007253 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7254 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007255 if (curproxy == &defproxy) {
7256 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7257 return -1;
7258 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007259
7260 if (*(args[1]) == 0) {
7261 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7262 return -1;
7263 }
7264
7265 preg = calloc(1, sizeof(regex_t));
7266 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7267 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7268 return -1;
7269 }
7270
7271 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7272 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007273 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7274 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007275 if (curproxy == &defproxy) {
7276 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7277 return -1;
7278 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007279
7280 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007281 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007282 return -1;
7283 }
7284
7285 preg = calloc(1, sizeof(regex_t));
7286 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007287 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007288 return -1;
7289 }
7290
7291 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7292 }
7293 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7294 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007295 if (curproxy == &defproxy) {
7296 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7297 return -1;
7298 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007299
7300 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007301 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7302 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007303 return -1;
7304 }
7305
7306 preg = calloc(1, sizeof(regex_t));
7307 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007308 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007309 return -1;
7310 }
7311
willy tarreauc1f47532005-12-18 01:08:26 +01007312 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7313 if (err) {
7314 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7315 file, linenum, *err);
7316 return -1;
7317 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007318 }
7319 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7320 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007321 if (curproxy == &defproxy) {
7322 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7323 return -1;
7324 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007325
7326 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007327 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007328 return -1;
7329 }
7330
7331 preg = calloc(1, sizeof(regex_t));
7332 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007333 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007334 return -1;
7335 }
7336
7337 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7338 }
7339 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7340 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007341 if (curproxy == &defproxy) {
7342 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7343 return -1;
7344 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007345
7346 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007347 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007348 return -1;
7349 }
7350
7351 preg = calloc(1, sizeof(regex_t));
7352 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007353 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007354 return -1;
7355 }
7356
7357 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7358 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007359 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7360 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007361 if (curproxy == &defproxy) {
7362 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7363 return -1;
7364 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007365
7366 if (*(args[1]) == 0) {
7367 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7368 return -1;
7369 }
7370
7371 preg = calloc(1, sizeof(regex_t));
7372 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7373 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7374 return -1;
7375 }
7376
7377 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7378 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007379 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7380 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007381 if (curproxy == &defproxy) {
7382 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7383 return -1;
7384 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007385
7386 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007387 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007388 return -1;
7389 }
7390
7391 preg = calloc(1, sizeof(regex_t));
7392 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007393 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007394 return -1;
7395 }
7396
7397 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7398 }
7399 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007400 if (curproxy == &defproxy) {
7401 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7402 return -1;
7403 }
7404
willy tarreau9fe663a2005-12-17 13:02:59 +01007405 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007406 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007407 return 0;
7408 }
7409
7410 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007411 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007412 return -1;
7413 }
7414
willy tarreau4302f492005-12-18 01:00:37 +01007415 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7416 }
7417 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7418 regex_t *preg;
7419
7420 if (*(args[1]) == 0 || *(args[2]) == 0) {
7421 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7422 file, linenum, args[0]);
7423 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007424 }
willy tarreau4302f492005-12-18 01:00:37 +01007425
7426 preg = calloc(1, sizeof(regex_t));
7427 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7428 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7429 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007430 }
willy tarreau4302f492005-12-18 01:00:37 +01007431
willy tarreauc1f47532005-12-18 01:08:26 +01007432 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7433 if (err) {
7434 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7435 file, linenum, *err);
7436 return -1;
7437 }
willy tarreau4302f492005-12-18 01:00:37 +01007438 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007439 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7440 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007441 if (curproxy == &defproxy) {
7442 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7443 return -1;
7444 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007445
7446 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007447 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007448 return -1;
7449 }
willy tarreaue39cd132005-12-17 13:00:18 +01007450
willy tarreau9fe663a2005-12-17 13:02:59 +01007451 preg = calloc(1, sizeof(regex_t));
7452 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007453 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007454 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007455 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007456
willy tarreauc1f47532005-12-18 01:08:26 +01007457 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7458 if (err) {
7459 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7460 file, linenum, *err);
7461 return -1;
7462 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007463 }
willy tarreau982249e2005-12-18 00:57:06 +01007464 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7465 regex_t *preg;
7466 if (curproxy == &defproxy) {
7467 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7468 return -1;
7469 }
7470
7471 if (*(args[1]) == 0) {
7472 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7473 return -1;
7474 }
7475
7476 preg = calloc(1, sizeof(regex_t));
7477 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7478 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7479 return -1;
7480 }
7481
willy tarreauc1f47532005-12-18 01:08:26 +01007482 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7483 if (err) {
7484 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7485 file, linenum, *err);
7486 return -1;
7487 }
willy tarreau982249e2005-12-18 00:57:06 +01007488 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007489 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007490 regex_t *preg;
7491 if (curproxy == &defproxy) {
7492 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7493 return -1;
7494 }
willy tarreaue39cd132005-12-17 13:00:18 +01007495
willy tarreaua41a8b42005-12-17 14:02:24 +01007496 if (*(args[1]) == 0 || *(args[2]) == 0) {
7497 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7498 file, linenum, args[0]);
7499 return -1;
7500 }
willy tarreaue39cd132005-12-17 13:00:18 +01007501
willy tarreaua41a8b42005-12-17 14:02:24 +01007502 preg = calloc(1, sizeof(regex_t));
7503 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7504 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7505 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007506 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007507
willy tarreauc1f47532005-12-18 01:08:26 +01007508 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7509 if (err) {
7510 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7511 file, linenum, *err);
7512 return -1;
7513 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007514 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007515 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7516 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007517 if (curproxy == &defproxy) {
7518 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7519 return -1;
7520 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007521
7522 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007523 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007524 return -1;
7525 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007526
willy tarreau9fe663a2005-12-17 13:02:59 +01007527 preg = calloc(1, sizeof(regex_t));
7528 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007529 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007530 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007531 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007532
willy tarreauc1f47532005-12-18 01:08:26 +01007533 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7534 if (err) {
7535 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7536 file, linenum, *err);
7537 return -1;
7538 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007539 }
willy tarreau982249e2005-12-18 00:57:06 +01007540 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7541 regex_t *preg;
7542 if (curproxy == &defproxy) {
7543 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7544 return -1;
7545 }
7546
7547 if (*(args[1]) == 0) {
7548 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7549 return -1;
7550 }
7551
7552 preg = calloc(1, sizeof(regex_t));
7553 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7554 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7555 return -1;
7556 }
7557
willy tarreauc1f47532005-12-18 01:08:26 +01007558 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7559 if (err) {
7560 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7561 file, linenum, *err);
7562 return -1;
7563 }
willy tarreau982249e2005-12-18 00:57:06 +01007564 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007565 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007566 if (curproxy == &defproxy) {
7567 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7568 return -1;
7569 }
7570
willy tarreau9fe663a2005-12-17 13:02:59 +01007571 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007572 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007573 return 0;
7574 }
7575
7576 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007577 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007578 return -1;
7579 }
7580
7581 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7582 }
willy tarreauc1f47532005-12-18 01:08:26 +01007583 else if (!strcmp(args[0], "errorloc") ||
7584 !strcmp(args[0], "errorloc302") ||
7585 !strcmp(args[0], "errorloc303")) { /* error location */
7586 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007587 char *err;
7588
willy tarreaueedaa9f2005-12-17 14:08:03 +01007589 // if (curproxy == &defproxy) {
7590 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7591 // return -1;
7592 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007593
willy tarreau8337c6b2005-12-17 13:41:01 +01007594 if (*(args[2]) == 0) {
7595 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7596 return -1;
7597 }
7598
7599 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007600 if (!strcmp(args[0], "errorloc303")) {
7601 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7602 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7603 } else {
7604 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7605 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7606 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007607
7608 if (errnum == 400) {
7609 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007610 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007611 free(curproxy->errmsg.msg400);
7612 }
7613 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007614 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007615 }
7616 else if (errnum == 403) {
7617 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007618 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007619 free(curproxy->errmsg.msg403);
7620 }
7621 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007622 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007623 }
7624 else if (errnum == 408) {
7625 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007626 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007627 free(curproxy->errmsg.msg408);
7628 }
7629 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007630 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007631 }
7632 else if (errnum == 500) {
7633 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007634 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007635 free(curproxy->errmsg.msg500);
7636 }
7637 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007638 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007639 }
7640 else if (errnum == 502) {
7641 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007642 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007643 free(curproxy->errmsg.msg502);
7644 }
7645 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007646 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007647 }
7648 else if (errnum == 503) {
7649 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007650 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007651 free(curproxy->errmsg.msg503);
7652 }
7653 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007654 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007655 }
7656 else if (errnum == 504) {
7657 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007658 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007659 free(curproxy->errmsg.msg504);
7660 }
7661 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007662 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007663 }
7664 else {
7665 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7666 free(err);
7667 }
7668 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007669 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007670 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007671 return -1;
7672 }
7673 return 0;
7674}
willy tarreaue39cd132005-12-17 13:00:18 +01007675
willy tarreau5cbea6f2005-12-17 12:48:26 +01007676
willy tarreau9fe663a2005-12-17 13:02:59 +01007677/*
7678 * This function reads and parses the configuration file given in the argument.
7679 * returns 0 if OK, -1 if error.
7680 */
7681int readcfgfile(char *file) {
7682 char thisline[256];
7683 char *line;
7684 FILE *f;
7685 int linenum = 0;
7686 char *end;
7687 char *args[MAX_LINE_ARGS];
7688 int arg;
7689 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007690 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007691 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007692
willy tarreau9fe663a2005-12-17 13:02:59 +01007693 struct proxy *curproxy = NULL;
7694 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007695
willy tarreau9fe663a2005-12-17 13:02:59 +01007696 if ((f=fopen(file,"r")) == NULL)
7697 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007698
willy tarreaueedaa9f2005-12-17 14:08:03 +01007699 init_default_instance();
7700
willy tarreau9fe663a2005-12-17 13:02:59 +01007701 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7702 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007703
willy tarreau9fe663a2005-12-17 13:02:59 +01007704 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007705
willy tarreau9fe663a2005-12-17 13:02:59 +01007706 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007707 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007708 line++;
7709
7710 arg = 0;
7711 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007712
willy tarreau9fe663a2005-12-17 13:02:59 +01007713 while (*line && arg < MAX_LINE_ARGS) {
7714 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7715 * C equivalent value. Other combinations left unchanged (eg: \1).
7716 */
7717 if (*line == '\\') {
7718 int skip = 0;
7719 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7720 *line = line[1];
7721 skip = 1;
7722 }
7723 else if (line[1] == 'r') {
7724 *line = '\r';
7725 skip = 1;
7726 }
7727 else if (line[1] == 'n') {
7728 *line = '\n';
7729 skip = 1;
7730 }
7731 else if (line[1] == 't') {
7732 *line = '\t';
7733 skip = 1;
7734 }
willy tarreauc1f47532005-12-18 01:08:26 +01007735 else if (line[1] == 'x') {
7736 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7737 unsigned char hex1, hex2;
7738 hex1 = toupper(line[2]) - '0';
7739 hex2 = toupper(line[3]) - '0';
7740 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7741 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7742 *line = (hex1<<4) + hex2;
7743 skip = 3;
7744 }
7745 else {
7746 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7747 return -1;
7748 }
7749 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007750 if (skip) {
7751 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7752 end -= skip;
7753 }
7754 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007755 }
willy tarreaua1598082005-12-17 13:08:06 +01007756 else if (*line == '#' || *line == '\n' || *line == '\r') {
7757 /* end of string, end of loop */
7758 *line = 0;
7759 break;
7760 }
willy tarreauc29948c2005-12-17 13:10:27 +01007761 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007762 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007763 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007764 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007765 line++;
7766 args[++arg] = line;
7767 }
7768 else {
7769 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007770 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007771 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007772
willy tarreau9fe663a2005-12-17 13:02:59 +01007773 /* empty line */
7774 if (!**args)
7775 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007776
willy tarreau9fe663a2005-12-17 13:02:59 +01007777 /* zero out remaining args */
7778 while (++arg < MAX_LINE_ARGS) {
7779 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007780 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007781
willy tarreaua41a8b42005-12-17 14:02:24 +01007782 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007783 confsect = CFG_LISTEN;
7784 else if (!strcmp(args[0], "global")) /* global config */
7785 confsect = CFG_GLOBAL;
7786 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007787
willy tarreau9fe663a2005-12-17 13:02:59 +01007788 switch (confsect) {
7789 case CFG_LISTEN:
7790 if (cfg_parse_listen(file, linenum, args) < 0)
7791 return -1;
7792 break;
7793 case CFG_GLOBAL:
7794 if (cfg_parse_global(file, linenum, args) < 0)
7795 return -1;
7796 break;
7797 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007798 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007799 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007800 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007801
7802
willy tarreau0f7af912005-12-17 12:21:26 +01007803 }
7804 fclose(f);
7805
7806 /*
7807 * Now, check for the integrity of all that we have collected.
7808 */
7809
Willy TARREAU3759f982006-03-01 22:44:17 +01007810 /* will be needed further to delay some tasks */
7811 tv_now(&now);
7812
willy tarreau0f7af912005-12-17 12:21:26 +01007813 if ((curproxy = proxy) == NULL) {
7814 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7815 file);
7816 return -1;
7817 }
7818
7819 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007820 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007821 curproxy = curproxy->next;
7822 continue;
7823 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007824
7825 if (curproxy->listen == NULL) {
7826 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);
7827 cfgerr++;
7828 }
7829 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007830 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007831 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007832 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7833 file, curproxy->id);
7834 cfgerr++;
7835 }
7836 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7837 if (curproxy->options & PR_O_TRANSP) {
7838 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7839 file, curproxy->id);
7840 cfgerr++;
7841 }
7842 else if (curproxy->srv == NULL) {
7843 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7844 file, curproxy->id);
7845 cfgerr++;
7846 }
willy tarreaua1598082005-12-17 13:08:06 +01007847 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007848 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7849 file, curproxy->id);
7850 }
7851 }
7852 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007853 if (curproxy->cookie_name != NULL) {
7854 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7855 file, curproxy->id);
7856 }
7857 if ((newsrv = curproxy->srv) != NULL) {
7858 Warning("parsing %s : servers will be ignored for listener %s.\n",
7859 file, curproxy->id);
7860 }
willy tarreaue39cd132005-12-17 13:00:18 +01007861 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007862 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7863 file, curproxy->id);
7864 }
willy tarreaue39cd132005-12-17 13:00:18 +01007865 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007866 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7867 file, curproxy->id);
7868 }
7869 }
7870 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7871 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7872 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7873 file, curproxy->id);
7874 cfgerr++;
7875 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007876 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007877
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007878 /* first, we will invert the servers list order */
7879 newsrv = NULL;
7880 while (curproxy->srv) {
7881 struct server *next;
7882
7883 next = curproxy->srv->next;
7884 curproxy->srv->next = newsrv;
7885 newsrv = curproxy->srv;
7886 if (!next)
7887 break;
7888 curproxy->srv = next;
7889 }
7890
7891 /* now, newsrv == curproxy->srv */
7892 if (newsrv) {
7893 struct server *srv;
7894 int pgcd;
7895 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02007896
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007897 /* We will factor the weights to reduce the table,
7898 * using Euclide's largest common divisor algorithm
7899 */
7900 pgcd = newsrv->uweight + 1;
7901 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
7902 int t, w;
7903
7904 w = srv->uweight + 1;
7905 while (w) {
7906 t = pgcd % w;
7907 pgcd = w;
7908 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02007909 }
willy tarreau0f7af912005-12-17 12:21:26 +01007910 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007911
7912 act = bck = 0;
7913 for (srv = newsrv; srv; srv = srv->next) {
7914 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
7915 if (srv->state & SRV_BACKUP)
7916 bck += srv->eweight + 1;
7917 else
7918 act += srv->eweight + 1;
7919 }
7920
7921 /* this is the largest map we will ever need for this servers list */
7922 if (act < bck)
7923 act = bck;
7924
7925 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
7926 /* recounts servers and their weights */
7927 recount_servers(curproxy);
7928 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01007929 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007930
7931 if (curproxy->options & PR_O_LOGASAP)
7932 curproxy->to_log &= ~LW_BYTES;
7933
willy tarreau8337c6b2005-12-17 13:41:01 +01007934 if (curproxy->errmsg.msg400 == NULL) {
7935 curproxy->errmsg.msg400 = (char *)HTTP_400;
7936 curproxy->errmsg.len400 = strlen(HTTP_400);
7937 }
7938 if (curproxy->errmsg.msg403 == NULL) {
7939 curproxy->errmsg.msg403 = (char *)HTTP_403;
7940 curproxy->errmsg.len403 = strlen(HTTP_403);
7941 }
7942 if (curproxy->errmsg.msg408 == NULL) {
7943 curproxy->errmsg.msg408 = (char *)HTTP_408;
7944 curproxy->errmsg.len408 = strlen(HTTP_408);
7945 }
7946 if (curproxy->errmsg.msg500 == NULL) {
7947 curproxy->errmsg.msg500 = (char *)HTTP_500;
7948 curproxy->errmsg.len500 = strlen(HTTP_500);
7949 }
7950 if (curproxy->errmsg.msg502 == NULL) {
7951 curproxy->errmsg.msg502 = (char *)HTTP_502;
7952 curproxy->errmsg.len502 = strlen(HTTP_502);
7953 }
7954 if (curproxy->errmsg.msg503 == NULL) {
7955 curproxy->errmsg.msg503 = (char *)HTTP_503;
7956 curproxy->errmsg.len503 = strlen(HTTP_503);
7957 }
7958 if (curproxy->errmsg.msg504 == NULL) {
7959 curproxy->errmsg.msg504 = (char *)HTTP_504;
7960 curproxy->errmsg.len504 = strlen(HTTP_504);
7961 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007962
7963 /* now we'll start this proxy's health checks if any */
7964 /* 1- count the checkers to run simultaneously */
7965 nbchk = 0;
7966 mininter = 0;
7967 newsrv = curproxy->srv;
7968 while (newsrv != NULL) {
7969 if (newsrv->state & SRV_CHECKED) {
7970 if (!mininter || mininter > newsrv->inter)
7971 mininter = newsrv->inter;
7972 nbchk++;
7973 }
7974 newsrv = newsrv->next;
7975 }
7976
7977 /* 2- start them as far as possible from each others while respecting
7978 * their own intervals. For this, we will start them after their own
7979 * interval added to the min interval divided by the number of servers,
7980 * weighted by the server's position in the list.
7981 */
7982 if (nbchk > 0) {
7983 struct task *t;
7984 int srvpos;
7985
7986 newsrv = curproxy->srv;
7987 srvpos = 0;
7988 while (newsrv != NULL) {
7989 /* should this server be checked ? */
7990 if (newsrv->state & SRV_CHECKED) {
7991 if ((t = pool_alloc(task)) == NULL) {
7992 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7993 return -1;
7994 }
7995
7996 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7997 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7998 t->state = TASK_IDLE;
7999 t->process = process_chk;
8000 t->context = newsrv;
8001
8002 /* check this every ms */
8003 tv_delayfrom(&t->expire, &now,
8004 newsrv->inter + mininter * srvpos / nbchk);
8005 task_queue(t);
8006 //task_wakeup(&rq, t);
8007 srvpos++;
8008 }
8009 newsrv = newsrv->next;
8010 }
8011 }
8012
willy tarreau0f7af912005-12-17 12:21:26 +01008013 curproxy = curproxy->next;
8014 }
8015 if (cfgerr > 0) {
8016 Alert("Errors found in configuration file, aborting.\n");
8017 return -1;
8018 }
8019 else
8020 return 0;
8021}
8022
8023
8024/*
8025 * This function initializes all the necessary variables. It only returns
8026 * if everything is OK. If something fails, it exits.
8027 */
8028void init(int argc, char **argv) {
8029 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008030 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008031 char *old_argv = *argv;
8032 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008033 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008034
8035 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008036 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008037 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008038 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008039 exit(1);
8040 }
8041
willy tarreau746e26b2006-03-25 11:14:35 +01008042#ifdef HAPROXY_MEMMAX
8043 global.rlimit_memmax = HAPROXY_MEMMAX;
8044#endif
8045
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008046 /* initialize the libc's localtime structures once for all so that we
8047 * won't be missing memory if we want to send alerts under OOM conditions.
8048 */
8049 tv_now(&now);
8050 localtime(&now.tv_sec);
8051
willy tarreau4302f492005-12-18 01:00:37 +01008052 /* initialize the log header encoding map : '{|}"#' should be encoded with
8053 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8054 * URL encoding only requires '"', '#' to be encoded as well as non-
8055 * printable characters above.
8056 */
8057 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8058 memset(url_encode_map, 0, sizeof(url_encode_map));
8059 for (i = 0; i < 32; i++) {
8060 FD_SET(i, hdr_encode_map);
8061 FD_SET(i, url_encode_map);
8062 }
8063 for (i = 127; i < 256; i++) {
8064 FD_SET(i, hdr_encode_map);
8065 FD_SET(i, url_encode_map);
8066 }
8067
8068 tmp = "\"#{|}";
8069 while (*tmp) {
8070 FD_SET(*tmp, hdr_encode_map);
8071 tmp++;
8072 }
8073
8074 tmp = "\"#";
8075 while (*tmp) {
8076 FD_SET(*tmp, url_encode_map);
8077 tmp++;
8078 }
8079
willy tarreau64a3cc32005-12-18 01:13:11 +01008080 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8081#if defined(ENABLE_POLL)
8082 cfg_polling_mechanism |= POLL_USE_POLL;
8083#endif
8084#if defined(ENABLE_EPOLL)
8085 cfg_polling_mechanism |= POLL_USE_EPOLL;
8086#endif
8087
willy tarreau0f7af912005-12-17 12:21:26 +01008088 pid = getpid();
8089 progname = *argv;
8090 while ((tmp = strchr(progname, '/')) != NULL)
8091 progname = tmp + 1;
8092
8093 argc--; argv++;
8094 while (argc > 0) {
8095 char *flag;
8096
8097 if (**argv == '-') {
8098 flag = *argv+1;
8099
8100 /* 1 arg */
8101 if (*flag == 'v') {
8102 display_version();
8103 exit(0);
8104 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008105#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008106 else if (*flag == 'd' && flag[1] == 'e')
8107 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008108#endif
8109#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008110 else if (*flag == 'd' && flag[1] == 'p')
8111 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008112#endif
willy tarreau982249e2005-12-18 00:57:06 +01008113 else if (*flag == 'V')
8114 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008115 else if (*flag == 'd' && flag[1] == 'b')
8116 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008117 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008118 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008119 else if (*flag == 'c')
8120 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008121 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008122 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008123 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008124 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008125 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8126 /* list of pids to finish ('f') or terminate ('t') */
8127
8128 if (flag[1] == 'f')
8129 oldpids_sig = SIGUSR1; /* finish then exit */
8130 else
8131 oldpids_sig = SIGTERM; /* terminate immediately */
8132 argv++; argc--;
8133
8134 if (argc > 0) {
8135 oldpids = calloc(argc, sizeof(int));
8136 while (argc > 0) {
8137 oldpids[nb_oldpids] = atol(*argv);
8138 if (oldpids[nb_oldpids] <= 0)
8139 usage(old_argv);
8140 argc--; argv++;
8141 nb_oldpids++;
8142 }
8143 }
8144 }
willy tarreau2c513732006-04-15 19:25:16 +02008145#if STATTIME > 0
8146 else if (*flag == 's')
8147 arg_mode |= MODE_STATS;
8148 else if (*flag == 'l')
8149 arg_mode |= MODE_LOG;
8150#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008151 else { /* >=2 args */
8152 argv++; argc--;
8153 if (argc == 0)
8154 usage(old_argv);
8155
8156 switch (*flag) {
8157 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008158 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008159 case 'N' : cfg_maxpconn = atol(*argv); break;
8160 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008161 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008162 default: usage(old_argv);
8163 }
8164 }
8165 }
8166 else
8167 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008168 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008169 }
8170
willy tarreaud0fb4652005-12-18 01:32:04 +01008171 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008172 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8173 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008174
willy tarreau0f7af912005-12-17 12:21:26 +01008175 if (!cfg_cfgfile)
8176 usage(old_argv);
8177
8178 gethostname(hostname, MAX_HOSTNAME_LEN);
8179
willy tarreau12350152005-12-18 01:03:27 +01008180 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008181 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008182 if (readcfgfile(cfg_cfgfile) < 0) {
8183 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8184 exit(1);
8185 }
willy tarreau12350152005-12-18 01:03:27 +01008186 if (have_appsession)
8187 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008188
willy tarreau982249e2005-12-18 00:57:06 +01008189 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008190 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8191 exit(0);
8192 }
8193
willy tarreau9fe663a2005-12-17 13:02:59 +01008194 if (cfg_maxconn > 0)
8195 global.maxconn = cfg_maxconn;
8196
willy tarreaufe2c5c12005-12-17 14:14:34 +01008197 if (cfg_pidfile) {
8198 if (global.pidfile)
8199 free(global.pidfile);
8200 global.pidfile = strdup(cfg_pidfile);
8201 }
8202
willy tarreau9fe663a2005-12-17 13:02:59 +01008203 if (global.maxconn == 0)
8204 global.maxconn = DEFAULT_MAXCONN;
8205
Willy TARREAU203b0b62006-03-12 18:00:28 +01008206 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008207
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008208 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008209 /* command line debug mode inhibits configuration mode */
8210 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8211 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008212 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8213 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008214
8215 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8216 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8217 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8218 }
8219
8220 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008221 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8222 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008223 global.nbproc = 1;
8224 }
8225
8226 if (global.nbproc < 1)
8227 global.nbproc = 1;
8228
willy tarreau0f7af912005-12-17 12:21:26 +01008229 StaticReadEvent = (fd_set *)calloc(1,
8230 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008231 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008232 StaticWriteEvent = (fd_set *)calloc(1,
8233 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008234 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008235
8236 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008237 sizeof(struct fdtab) * (global.maxsock));
8238 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008239 fdtab[i].state = FD_STCLOSE;
8240 }
8241}
8242
8243/*
willy tarreau41310e72006-03-25 18:17:56 +01008244 * this function starts all the proxies. Its return value is composed from
8245 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8246 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008247 */
willy tarreau41310e72006-03-25 18:17:56 +01008248int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008249 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008250 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008251 int err = ERR_NONE;
8252 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008253
8254 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008255 if (curproxy->state != PR_STNEW)
8256 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008257
willy tarreau41310e72006-03-25 18:17:56 +01008258 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008259 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008260 if (listener->fd != -1)
8261 continue; /* already initialized */
8262
8263 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8264 if (verbose)
8265 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8266 curproxy->id);
8267 err |= ERR_RETRYABLE;
8268 pxerr |= 1;
8269 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008270 }
willy tarreau0f7af912005-12-17 12:21:26 +01008271
willy tarreaua41a8b42005-12-17 14:02:24 +01008272 if (fd >= global.maxsock) {
8273 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8274 curproxy->id);
8275 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008276 err |= ERR_FATAL;
8277 pxerr |= 1;
8278 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008279 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008280
willy tarreaua41a8b42005-12-17 14:02:24 +01008281 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8282 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8283 (char *) &one, sizeof(one)) == -1)) {
8284 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8285 curproxy->id);
8286 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008287 err |= ERR_FATAL;
8288 pxerr |= 1;
8289 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008290 }
willy tarreau0f7af912005-12-17 12:21:26 +01008291
willy tarreaua41a8b42005-12-17 14:02:24 +01008292 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8293 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8294 curproxy->id);
8295 }
willy tarreau0f7af912005-12-17 12:21:26 +01008296
willy tarreaua41a8b42005-12-17 14:02:24 +01008297 if (bind(fd,
8298 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008299 listener->addr.ss_family == AF_INET6 ?
8300 sizeof(struct sockaddr_in6) :
8301 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008302 if (verbose)
8303 Alert("cannot bind socket for proxy %s. Aborting.\n",
8304 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008305 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008306 err |= ERR_RETRYABLE;
8307 pxerr |= 1;
8308 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008309 }
willy tarreau0f7af912005-12-17 12:21:26 +01008310
willy tarreaua41a8b42005-12-17 14:02:24 +01008311 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008312 if (verbose)
8313 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8314 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008315 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008316 err |= ERR_RETRYABLE;
8317 pxerr |= 1;
8318 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008319 }
willy tarreau0f7af912005-12-17 12:21:26 +01008320
willy tarreau41310e72006-03-25 18:17:56 +01008321 /* the socket is ready */
8322 listener->fd = fd;
8323
willy tarreaua41a8b42005-12-17 14:02:24 +01008324 /* the function for the accept() event */
8325 fdtab[fd].read = &event_accept;
8326 fdtab[fd].write = NULL; /* never called */
8327 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008328 fdtab[fd].state = FD_STLISTEN;
8329 FD_SET(fd, StaticReadEvent);
8330 fd_insert(fd);
8331 listeners++;
8332 }
willy tarreau41310e72006-03-25 18:17:56 +01008333
8334 if (!pxerr) {
8335 curproxy->state = PR_STRUN;
8336 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8337 }
willy tarreau0f7af912005-12-17 12:21:26 +01008338 }
willy tarreau41310e72006-03-25 18:17:56 +01008339
8340 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008341}
8342
willy tarreaub952e1d2005-12-18 01:31:20 +01008343int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008344
8345 appsess *temp1,*temp2;
8346 temp1 = (appsess *)key1;
8347 temp2 = (appsess *)key2;
8348
8349 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8350 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8351
8352 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8353}/* end match_str */
8354
willy tarreaub952e1d2005-12-18 01:31:20 +01008355void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008356 appsess *temp1;
8357
8358 //printf("destroy called\n");
8359 temp1 = (appsess *)data;
8360
8361 if (temp1->sessid)
8362 pool_free_to(apools.sessid, temp1->sessid);
8363
8364 if (temp1->serverid)
8365 pool_free_to(apools.serverid, temp1->serverid);
8366
8367 pool_free(appsess, temp1);
8368} /* end destroy */
8369
8370void appsession_cleanup( void )
8371{
8372 struct proxy *p = proxy;
8373
8374 while(p) {
8375 chtbl_destroy(&(p->htbl_proxy));
8376 p = p->next;
8377 }
8378}/* end appsession_cleanup() */
8379
8380void pool_destroy(void **pool)
8381{
8382 void *temp, *next;
8383 next = pool;
8384 while (next) {
8385 temp = next;
8386 next = *(void **)temp;
8387 free(temp);
8388 }
8389}/* end pool_destroy() */
8390
willy tarreaub952e1d2005-12-18 01:31:20 +01008391void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008392 struct proxy *p = proxy;
8393 struct cap_hdr *h,*h_next;
8394 struct server *s,*s_next;
8395 struct listener *l,*l_next;
8396
8397 while (p) {
8398 if (p->id)
8399 free(p->id);
8400
8401 if (p->check_req)
8402 free(p->check_req);
8403
8404 if (p->cookie_name)
8405 free(p->cookie_name);
8406
8407 if (p->capture_name)
8408 free(p->capture_name);
8409
8410 /* only strup if the user have set in config.
8411 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008412 if (p->errmsg.msg400) free(p->errmsg.msg400);
8413 if (p->errmsg.msg403) free(p->errmsg.msg403);
8414 if (p->errmsg.msg408) free(p->errmsg.msg408);
8415 if (p->errmsg.msg500) free(p->errmsg.msg500);
8416 if (p->errmsg.msg502) free(p->errmsg.msg502);
8417 if (p->errmsg.msg503) free(p->errmsg.msg503);
8418 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008419 */
8420 if (p->appsession_name)
8421 free(p->appsession_name);
8422
8423 h = p->req_cap;
8424 while (h) {
8425 h_next = h->next;
8426 if (h->name)
8427 free(h->name);
8428 pool_destroy(h->pool);
8429 free(h);
8430 h = h_next;
8431 }/* end while(h) */
8432
8433 h = p->rsp_cap;
8434 while (h) {
8435 h_next = h->next;
8436 if (h->name)
8437 free(h->name);
8438
8439 pool_destroy(h->pool);
8440 free(h);
8441 h = h_next;
8442 }/* end while(h) */
8443
8444 s = p->srv;
8445 while (s) {
8446 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008447 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008448 free(s->id);
8449
willy tarreaub952e1d2005-12-18 01:31:20 +01008450 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008451 free(s->cookie);
8452
8453 free(s);
8454 s = s_next;
8455 }/* end while(s) */
8456
8457 l = p->listen;
8458 while (l) {
8459 l_next = l->next;
8460 free(l);
8461 l = l_next;
8462 }/* end while(l) */
8463
8464 pool_destroy((void **) p->req_cap_pool);
8465 pool_destroy((void **) p->rsp_cap_pool);
8466 p = p->next;
8467 }/* end while(p) */
8468
8469 if (global.chroot) free(global.chroot);
8470 if (global.pidfile) free(global.pidfile);
8471
willy tarreau12350152005-12-18 01:03:27 +01008472 if (StaticReadEvent) free(StaticReadEvent);
8473 if (StaticWriteEvent) free(StaticWriteEvent);
8474 if (fdtab) free(fdtab);
8475
8476 pool_destroy(pool_session);
8477 pool_destroy(pool_buffer);
8478 pool_destroy(pool_fdtab);
8479 pool_destroy(pool_requri);
8480 pool_destroy(pool_task);
8481 pool_destroy(pool_capture);
8482 pool_destroy(pool_appsess);
8483
8484 if (have_appsession) {
8485 pool_destroy(apools.serverid);
8486 pool_destroy(apools.sessid);
8487 }
8488} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008489
willy tarreau41310e72006-03-25 18:17:56 +01008490/* sends the signal <sig> to all pids found in <oldpids> */
8491static void tell_old_pids(int sig) {
8492 int p;
8493 for (p = 0; p < nb_oldpids; p++)
8494 kill(oldpids[p], sig);
8495}
8496
willy tarreau0f7af912005-12-17 12:21:26 +01008497int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008498 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008499 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008500 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008501 init(argc, argv);
8502
willy tarreau0f7af912005-12-17 12:21:26 +01008503 signal(SIGQUIT, dump);
8504 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008505 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008506#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008507 signal(SIGINT, sig_int);
8508 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008509#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008510
8511 /* on very high loads, a sigpipe sometimes happen just between the
8512 * getsockopt() which tells "it's OK to write", and the following write :-(
8513 */
willy tarreau3242e862005-12-17 12:27:53 +01008514#ifndef MSG_NOSIGNAL
8515 signal(SIGPIPE, SIG_IGN);
8516#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008517
willy tarreau41310e72006-03-25 18:17:56 +01008518 /* We will loop at most 100 times with 10 ms delay each time.
8519 * That's at most 1 second. We only send a signal to old pids
8520 * if we cannot grab at least one port.
8521 */
8522 retry = MAX_START_RETRIES;
8523 err = ERR_NONE;
8524 while (retry >= 0) {
8525 struct timeval w;
8526 err = start_proxies(retry == 0 || nb_oldpids == 0);
8527 if (err != ERR_RETRYABLE)
8528 break;
8529 if (nb_oldpids == 0)
8530 break;
8531
8532 tell_old_pids(SIGTTOU);
8533 /* give some time to old processes to stop listening */
8534 w.tv_sec = 0;
8535 w.tv_usec = 10*1000;
8536 select(0, NULL, NULL, NULL, &w);
8537 retry--;
8538 }
8539
8540 /* Note: start_proxies() sends an alert when it fails. */
8541 if (err != ERR_NONE) {
8542 if (retry != MAX_START_RETRIES && nb_oldpids)
8543 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008544 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008545 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008546
8547 if (listeners == 0) {
8548 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008549 /* Note: we don't have to send anything to the old pids because we
8550 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008551 exit(1);
8552 }
8553
willy tarreaudbd3bef2006-01-20 19:35:18 +01008554 /* prepare pause/play signals */
8555 signal(SIGTTOU, sig_pause);
8556 signal(SIGTTIN, sig_listen);
8557
Willy TARREAUe3283d12006-03-01 22:15:29 +01008558 if (global.mode & MODE_DAEMON) {
8559 global.mode &= ~MODE_VERBOSE;
8560 global.mode |= MODE_QUIET;
8561 }
8562
willy tarreaud0fb4652005-12-18 01:32:04 +01008563 /* MODE_QUIET can inhibit alerts and warnings below this line */
8564
8565 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008566 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008567 /* detach from the tty */
8568 fclose(stdin); fclose(stdout); fclose(stderr);
8569 close(0); close(1); close(2);
8570 }
willy tarreau0f7af912005-12-17 12:21:26 +01008571
willy tarreaufe2c5c12005-12-17 14:14:34 +01008572 /* open log & pid files before the chroot */
8573 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8574 int pidfd;
8575 unlink(global.pidfile);
8576 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8577 if (pidfd < 0) {
8578 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008579 if (nb_oldpids)
8580 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008581 exit(1);
8582 }
8583 pidfile = fdopen(pidfd, "w");
8584 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008585
8586 /* chroot if needed */
8587 if (global.chroot != NULL) {
8588 if (chroot(global.chroot) == -1) {
8589 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008590 if (nb_oldpids)
8591 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008592 }
8593 chdir("/");
8594 }
8595
willy tarreaub1285d52005-12-18 01:20:14 +01008596 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008597 if (!global.rlimit_nofile)
8598 global.rlimit_nofile = global.maxsock;
8599
willy tarreaub1285d52005-12-18 01:20:14 +01008600 if (global.rlimit_nofile) {
8601 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8602 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8603 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8604 }
willy tarreau746e26b2006-03-25 11:14:35 +01008605 }
8606
8607 if (global.rlimit_memmax) {
8608 limit.rlim_cur = limit.rlim_max =
8609 global.rlimit_memmax * 1048576 / global.nbproc;
8610#ifdef RLIMIT_AS
8611 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8612 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8613 argv[0], global.rlimit_memmax);
8614 }
8615#else
8616 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8617 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8618 argv[0], global.rlimit_memmax);
8619 }
8620#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008621 }
8622
willy tarreau41310e72006-03-25 18:17:56 +01008623 if (nb_oldpids)
8624 tell_old_pids(oldpids_sig);
8625
8626 /* Note that any error at this stage will be fatal because we will not
8627 * be able to restart the old pids.
8628 */
8629
willy tarreau9fe663a2005-12-17 13:02:59 +01008630 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008631 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008632 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8633 exit(1);
8634 }
8635
willy tarreau036e1ce2005-12-17 13:46:33 +01008636 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008637 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8638 exit(1);
8639 }
8640
willy tarreaub1285d52005-12-18 01:20:14 +01008641 /* check ulimits */
8642 limit.rlim_cur = limit.rlim_max = 0;
8643 getrlimit(RLIMIT_NOFILE, &limit);
8644 if (limit.rlim_cur < global.maxsock) {
8645 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",
8646 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8647 }
8648
willy tarreau9fe663a2005-12-17 13:02:59 +01008649 if (global.mode & MODE_DAEMON) {
8650 int ret = 0;
8651 int proc;
8652
8653 /* the father launches the required number of processes */
8654 for (proc = 0; proc < global.nbproc; proc++) {
8655 ret = fork();
8656 if (ret < 0) {
8657 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008658 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008659 exit(1); /* there has been an error */
8660 }
8661 else if (ret == 0) /* child breaks here */
8662 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008663 if (pidfile != NULL) {
8664 fprintf(pidfile, "%d\n", ret);
8665 fflush(pidfile);
8666 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008667 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008668 /* close the pidfile both in children and father */
8669 if (pidfile != NULL)
8670 fclose(pidfile);
8671 free(global.pidfile);
8672
willy tarreau9fe663a2005-12-17 13:02:59 +01008673 if (proc == global.nbproc)
8674 exit(0); /* parent must leave */
8675
willy tarreau750a4722005-12-17 13:21:24 +01008676 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8677 * that we can detach from the TTY. We MUST NOT do it in other cases since
8678 * it would have already be done, and 0-2 would have been affected to listening
8679 * sockets
8680 */
8681 if (!(global.mode & MODE_QUIET)) {
8682 /* detach from the tty */
8683 fclose(stdin); fclose(stdout); fclose(stderr);
8684 close(0); close(1); close(2); /* close all fd's */
8685 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8686 }
willy tarreaua1598082005-12-17 13:08:06 +01008687 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008688 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008689 }
8690
willy tarreau1c2ad212005-12-18 01:11:29 +01008691#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008692 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008693 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8694 epoll_loop(POLL_LOOP_ACTION_RUN);
8695 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008696 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008697 }
8698 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008699 Warning("epoll() is not available. Using poll()/select() instead.\n");
8700 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008701 }
8702 }
8703#endif
8704
8705#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008706 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008707 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8708 poll_loop(POLL_LOOP_ACTION_RUN);
8709 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008710 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008711 }
8712 else {
8713 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008714 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008715 }
8716 }
8717#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008718 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008719 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8720 select_loop(POLL_LOOP_ACTION_RUN);
8721 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008722 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008723 }
8724 }
8725
willy tarreau0f7af912005-12-17 12:21:26 +01008726
willy tarreau12350152005-12-18 01:03:27 +01008727 /* Free all Hash Keys and all Hash elements */
8728 appsession_cleanup();
8729 /* Do some cleanup */
8730 deinit();
8731
willy tarreau0f7af912005-12-17 12:21:26 +01008732 exit(0);
8733}
willy tarreau12350152005-12-18 01:03:27 +01008734
8735#if defined(DEBUG_HASH)
8736static void print_table(const CHTbl *htbl) {
8737
8738 ListElmt *element;
8739 int i;
8740 appsess *asession;
8741
8742 /*****************************************************************************
8743 * *
8744 * Display the chained hash table. *
8745 * *
8746 *****************************************************************************/
8747
8748 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8749
8750 for (i = 0; i < TBLSIZ; i++) {
8751 fprintf(stdout, "Bucket[%03d]\n", i);
8752
8753 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8754 //fprintf(stdout, "%c", *(char *)list_data(element));
8755 asession = (appsess *)list_data(element);
8756 fprintf(stdout, "ELEM :%s:", asession->sessid);
8757 fprintf(stdout, " Server :%s: \n", asession->serverid);
8758 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8759 }
8760
8761 fprintf(stdout, "\n");
8762 }
8763 return;
8764} /* end print_table */
8765#endif
8766
8767static int appsession_init(void)
8768{
8769 static int initialized = 0;
8770 int idlen;
8771 struct server *s;
8772 struct proxy *p = proxy;
8773
8774 if (!initialized) {
8775 if (!appsession_task_init()) {
8776 apools.sessid = NULL;
8777 apools.serverid = NULL;
8778 apools.ser_waste = 0;
8779 apools.ser_use = 0;
8780 apools.ser_msize = sizeof(void *);
8781 apools.ses_waste = 0;
8782 apools.ses_use = 0;
8783 apools.ses_msize = sizeof(void *);
8784 while (p) {
8785 s = p->srv;
8786 if (apools.ses_msize < p->appsession_len)
8787 apools.ses_msize = p->appsession_len;
8788 while (s) {
8789 idlen = strlen(s->id);
8790 if (apools.ser_msize < idlen)
8791 apools.ser_msize = idlen;
8792 s = s->next;
8793 }
8794 p = p->next;
8795 }
8796 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8797 apools.ses_msize ++;
8798 }
8799 else {
8800 fprintf(stderr, "appsession_task_init failed\n");
8801 return -1;
8802 }
8803 initialized ++;
8804 }
8805 return 0;
8806}
8807
8808static int appsession_task_init(void)
8809{
8810 static int initialized = 0;
8811 struct task *t;
8812 if (!initialized) {
8813 if ((t = pool_alloc(task)) == NULL)
8814 return -1;
8815 t->next = t->prev = t->rqnext = NULL;
8816 t->wq = LIST_HEAD(wait_queue);
8817 t->state = TASK_IDLE;
8818 t->context = NULL;
8819 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8820 task_queue(t);
8821 t->process = appsession_refresh;
8822 initialized ++;
8823 }
8824 return 0;
8825}
8826
8827static int appsession_refresh(struct task *t) {
8828 struct proxy *p = proxy;
8829 CHTbl *htbl;
8830 ListElmt *element, *last;
8831 int i;
8832 appsess *asession;
8833 void *data;
8834
8835 while (p) {
8836 if (p->appsession_name != NULL) {
8837 htbl = &p->htbl_proxy;
8838 /* if we ever give up the use of TBLSIZ, we need to change this */
8839 for (i = 0; i < TBLSIZ; i++) {
8840 last = NULL;
8841 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8842 asession = (appsess *)list_data(element);
8843 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8844 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8845 int len;
8846 /*
8847 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8848 */
8849 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8850 asession->sessid, asession->serverid?asession->serverid:"(null)");
8851 write(1, trash, len);
8852 }
8853 /* delete the expired element from within the hash table */
8854 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8855 && (htbl->table[i].destroy != NULL)) {
8856 htbl->table[i].destroy(data);
8857 }
8858 if (last == NULL) {/* patient lost his head, get a new one */
8859 element = list_head(&htbl->table[i]);
8860 if (element == NULL) break; /* no heads left, go to next patient */
8861 }
8862 else
8863 element = last;
8864 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8865 else
8866 last = element;
8867 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8868 }
8869 }
8870 p = p->next;
8871 }
8872 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8873 return TBLCHKINT;
8874} /* end appsession_refresh */
8875